MyBatis(4)动态SQL
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
![](https://img2018.cnblogs.com/blog/1488757/201810/1488757-20181003232314519-67576586.png)
mybatis-config.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="db.properties" ></properties> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <mappers> <mapper resource="DynamicSQL.xml"/> </mappers> </configuration>
Employee.java(getter&setter&toString)
public class Employee { private int id; private String name; private String gender; private String email; private Department dept; }
现在基本的布局已经完成!!
1)if
A.在DynamicMapper.java接口中
//携带了哪个字段的查询条件就携带这个字段的值 public List<Employee> getEmpByIf(Employee emp);
<!-- if --> <!-- 查询员工,要求,携带了那个字段查询条件就带上那个字段的字段值 --> <!-- public List<Employee> getEmpByIf(Employee emp); --> <select id="getEmpByIf" resultType="com.MrChengs.bean.Employee"> select * from test where <!-- test:判断表达式(OGNL) --> <!-- OGNL:apache官方文档有明确的解释说明 --> <!-- 从参数中取值进行判断不是数据库中取值 --> <!-- 特殊字符应该写转义字符 --> <if test="id!=null"> id=#{id} </if> <if test="name!=null and name!=''"> and name like #{name} </if> <if test="email!=null and email.trim()!=''"> and email like #{email} </if> </select>
public SqlSessionFactory getSqlSessionFactory() throws IOException{ String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); return new SqlSessionFactoryBuilder().build(inputStream); } @Test public void test() throws IOException { SqlSessionFactory sessionFactory = getSqlSessionFactory(); SqlSession session = sessionFactory.openSession(); try{ DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class); //传入的红色name值进行数据库的查询 Employee emp = new Employee(5, "%Mr%", "boy", "%1287%"); List<Employee> emps = mapper.getEmpByIf(emp); System.out.println(emps); }finally{ session.close(); } }
查询之后的显示代码
DEBUG 10-02 12:13:49,806 ==> Preparing: select * from test where id=? and name like ? and email like ? (BaseJdbcLogger.java:159) DEBUG 10-02 12:13:49,843 ==> Parameters: 5(Integer), %Mr%(String), %1287%(String) (BaseJdbcLogger.java:159) DEBUG 10-02 12:13:49,873 <== Total: 1 (BaseJdbcLogger.java:159) [Employee [id=5, name=MrChengs, gender=boy, email=1287xxxxxx@xx.com, dept=null]]
<select id="getEmpByIf" resultType="com.MrChengs.bean.Employee"> select * from test where <!-- test:判断表达式(OGNL) --> <!-- OGNL:apache官方文档有明确的解释说明 --> <!-- 从参数中取值进行判断不是数据库中取值 --> <!-- 特殊字符应该写转义字符 --> <!--此时我们假设忘记把id传进来 --> <if test="name!=null and name!=''"> and name like #{name} </if> <if test="email!=null and email.trim()!=''"> and email like #{email} </if> </select>
look:
show message:DEBUG 10-02 12:18:30,831 ==> Preparing: select * from test where and name like ? and email like ?
(BaseJdbcLogger.java:159)
<select id="getEmpByIf" resultType="com.MrChengs.bean.Employee"> select * from test <!-- 加入固定的条件,怎么拼装都行 --> where 1=1 <!-- test:判断表达式(OGNL) --> <!-- OGNL:apache官方文档有明确的解释说明 --> <!-- 从参数中取值进行判断不是数据库中取值 --> <!-- 特殊字符应该写转义字符 --> <if test="name!=null and name!=''"> and name like #{name} </if> <if test="email!=null and email.trim()!=''"> and email like #{email} </if> </select>
<select id="getEmpByIf" resultType="com.MrChengs.bean.Employee"> select * from test <where> <!-- test:判断表达式(OGNL) --> <!-- OGNL:apache官方文档有明确的解释说明 --> <!-- 从参数中取值进行判断不是数据库中取值 --> <!-- 特殊字符应该写转义字符 --> <if test="name!=null and name!=''"> and name like #{name} </if> <if test="email!=null and email.trim()!=''"> and email like #{email} </if> </where> </select>
注意使用and
2.使用trim标签进行,字符串截取
//测试Trim public List<Employee> getEmpByIfTrim(Employee emp);
在DynamicSQL.xml
<!-- 测试Trim() --> <!-- public List<Employee> getEmpByIfTrim(Employee emp); --> <select id="getEmpByIfTrim" resultType="com.MrChengs.bean.Employee"> select * from test where <if test="id!=null"> id=#{id} and </if> <if test="name!=null and name!=''"> name like #{name} and </if> <if test="email!=null and email.trim()!=''"> email like #{email} </if> </select>
@Test public void testgetEmpByIfTrim() throws IOException { SqlSessionFactory sessionFactory = getSqlSessionFactory(); SqlSession session = sessionFactory.openSession(); try{ DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class); Employee emp = new Employee("%Mr%", null, null); List<Employee> emps = mapper.getEmpByIfTrim(emp); System.out.println(emps); }finally{ session.close(); } }
拼串结果
DEBUG 10-02 13:31:59,995 ==> Preparing: select * from test where id=? and name like ? and
开始使用trim标签:(一些用法都在注释中,请注意看注释)
<!-- 测试Trim() --> <!-- public List<Employee> getEmpByIfTrim(Employee emp); --> <select id="getEmpByIfTrim" resultType="com.MrChengs.bean.Employee"> select * from test
<!-- prefix:前缀, trim标签体中是整个字符串拼串后的结果 给拼串后的整体字符串加一个前缀--> <!-- prefixOverrides:前缀覆盖, 去点整个前缀前面多余的字符串 --> <!-- suffix:后缀, 给拼串后的整个字符串加一个后缀 --> <!-- suffixOverrides:后缀覆盖,去掉整个字符串后面多余的字符串 -->
<trim prefix="where" suffixOverrides="and"> <if test="name!=null and name!=''"> name like #{name} and </if> <if test="email!=null and email.trim()!=''"> email like #{email} and </if> <if test="gender!=null"> gender=#{gender} </if> </trim> </select>
测试:
public void testgetEmpByIfTrim() throws IOException { SqlSessionFactory sessionFactory = getSqlSessionFactory(); SqlSession session = sessionFactory.openSession(); try{ DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class); Employee emp = new Employee("%Mr%", null, null); List<Employee> emps = mapper.getEmpByIfTrim(emp); System.out.println(emps); }finally{ session.close(); } }
结果拼串:
DEBUG 10-02 13:43:25,216 ==> Preparing: select * from test where name like ? (BaseJdbcLogger.java:159) DEBUG 10-02 13:43:25,266 ==> Parameters: %Mr%(String) (BaseJdbcLogger.java:159)
注意:在测试id的时候,不写则默认为零,博主自己测试的时候遇到的,所以把id的查询条件拿掉了!
//测试choose public List<Employee> getEmpBychoose(Employee emp);
DynamicSQL.xml:
<!-- choose --> <!-- 如果带了id使用id进行查询,带了name就是用name进行查询,只能使用一个进行查询 --> <!-- public List<Employee> getEmpBychoose(Employee emp); --> <select id="getEmpBychoose" resultType="com.MrChengs.bean.Employee"> select * from test <where> <choose> <when test="name!=null"> name like #{name} </when> <when test="email!=null"> email = #{email} </when> <when test="id!=null"> id=#{id} </when> <otherwise> d_id=1 </otherwise> </choose> </where> </select>
测试代码:
//测试choose @Test public void testgetEmpBychoose() throws IOException { SqlSessionFactory sessionFactory = getSqlSessionFactory(); SqlSession session = sessionFactory.openSession(); try{ DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class); Employee emp = new Employee("%Mr%", null, null); emp.setId(5); List<Employee> emps = mapper.getEmpBychoose(emp); System.out.println(emps); }finally{ session.close(); } }
结果:
DEBUG 10-02 14:07:35,311 ==> Preparing: select * from test WHERE name like ? (BaseJdbcLogger.java:159)
DEBUG 10-02 14:07:35,363 ==> Parameters: %Mr%(String) (BaseJdbcLogger.java:159)
此时我们不仅传入了name同时还传入了id,但是拼串之后是使用name进行查询的
3.更新
//更新方法 public void updataEmp(Employee emp);
在DynamicSQl.xml文件:
<!-- update更新 --> <!-- 更新 --> <!-- public void updataEmp(Employee emp); --> <update id="updataEmp"> update test <set> <if test="name!=null">name=#{name},</if> <if test="email!=null"> email=#{email},</if> <if test="gender!=null">gender=#{gender},</if> </set> where id=#{id} </update>
使用<set>标签,可以自动为我们解决存在的 ”,“ 问题
//更新upddate @Test public void testgetEmpupdate() throws IOException { SqlSessionFactory sessionFactory = getSqlSessionFactory(); SqlSession session = sessionFactory.openSession(); try{ DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class); Employee emp = new Employee("MrChengsR", "gril", null); emp.setId(7); mapper.updataEmp(emp); System.out.println(emp); session.commit(); }finally{ session.close(); } }
此时修改数据成功
<update id="updataEmp"> update test <trim prefix="set" suffixOverrides=","> <if test="name!=null">name=#{name},</if> <if test="email!=null"> email=#{email},</if> <if test="gender!=null">gender=#{gender},</if> </trim> where id=#{id} </update>
4.foreach
//foreach public List<Employee> getEmpsByCollection(List<Integer> list);
DynamicSQL.xml
<!-- foreach: --> <!-- public List<Employee> getEmpsByCollection(Employee emp); --> <select id="getEmpsByCollection" resultType="com.MrChengs.bean.Employee" > select * from test where id in( <!-- collection:指定遍历的集合 --> <!-- list类型的参数会做特殊的处理封装在map中,map的key叫list --> <!-- item:将当前遍历出的元素赋值给指定的变量 --> <!-- #{变量名} 就能取出当前遍历的元素 --> <!-- separator:每个元素之间的分隔符 此时是in(a,b,c,d)这里面的 , --> <!-- open:遍历出所有结果拼接一个开始的字符 --> <!-- close:便利的所有结果拼出结尾 --> <!-- index:遍历list是索引,遍历map就是map的key --> <foreach collection="list" item="item_id" separator=","> #{item_id} </foreach> ) </select>
@Test public void testgetEmpForeach() throws IOException { SqlSessionFactory sessionFactory = getSqlSessionFactory(); SqlSession session = sessionFactory.openSession(); try{ DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class); List<Employee> emps = mapper.getEmpsByCollection(Arrays.asList(5,7,8)); for(Employee emp : emps){ System.out.println(emp); } }finally{ session.close(); } }
得到结果:
DEBUG 10-02 19:16:01,838 ==> Preparing: select * from test where id in( ? , ? , ? ) (BaseJdbcLogger.java:159) DEBUG 10-02 19:16:01,887 ==> Parameters: 5(Integer), 7(Integer), 8(Integer) (BaseJdbcLogger.java:159) DEBUG 10-02 19:16:01,909 <== Total: 3 (BaseJdbcLogger.java:159) Employee [id=5, name=MrChengs, gender=boy, email=xxxxxxxx@qq.com, dept=null] Employee [id=7, name=MrChengs, gender=gril, email=zhangsan@qq.com, dept=null] Employee [id=8, name=MrChen, gender=gril, email=xxxxxx@xx.xxx, dept=null]
B.批量保存
//批量存取 public void addEmps(@Param("emps")List<Employee> employee);
xml文件:
<!-- //批量存取--> <!-- public void addEmps(@Param("emps")Employee employee); --> <insert id="addEmps"> insert into test(name,gender,email,d_id) values <foreach collection="emps" separator="," item="emp"> <!-- 传参数之前是我们new的一个对象,传参数之后是插入数据库的数据 --> (#{emp.name},#{emp.gender},#{emp.email},#{emp.dept.id}) </foreach> </insert>
实现类:
//批量存取 @Test public void testgetEmpaddEmps() throws IOException { SqlSessionFactory sessionFactory = getSqlSessionFactory(); SqlSession session = sessionFactory.openSession(); try{ DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class); List<Employee> employee = new ArrayList<Employee>(); employee.add(new Employee("Ma", "gril", "Ma@Ma", new Department(1))); employee.add(new Employee("Mb", "boy", "Mb@Mb", new Department(2))); mapper.addEmps(employee); session.commit(); }finally{ session.close(); } }
<!-- 方法二 --> <!-- 需要加上 --> <!-- jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true --> <insert id="addEmps"> <foreach collection="emps" separator=";" item="emp"> insert into test(name,gender,email,d_id) values (#{emp.name},#{emp.gender},#{emp.email},#{emp.dept.id}) </foreach> </insert>
其余不变可以进行测试
<databaseIdProvider type="DB_VENDOR"> <property name="MySQL" value="mysql"/> <property name="Oracle" value="oracle"/> </databaseIdProvider>
接口类中
//测试两个属性 public List<Employee> getEmpselect();
DynamicMapper.xml
<!-- 两个重要的参数 --> <!-- _parameter:代表整个参数,单个参数就是这个参数,多个参数就是封装成的map --> <!-- _databaseId:配置了databaseIdProvider标签,就是代表当前数据库的别名 --> <!-- public Employee getEmpselect(int id); --> <!-- 修改if中的test条件即可实现不同数据库之间的查询 --> <select id="getEmpselect" resultType="com.MrChengs.bean.Employee" databaseId="mysql"> <if test="_databaseId=='mysql'"> select * from test </if> <if test="_databaseId=='oracle'"> select * from test </if> </select>
测试类:
//两个重要的参数 @Test public void testgetEmpselect() throws IOException { SqlSessionFactory sessionFactory = getSqlSessionFactory(); SqlSession session = sessionFactory.openSession(); try{ DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class); List<Employee> emps= mapper.getEmpselect(); for(Employee emp : emps){ System.out.println(); } }finally{ session.close(); } }
//测试两个属性 public List<Employee> getEmpselect(int id);
在xnl文件中:
<!-- public Employee getEmpselect(int id); --> <select id="getEmpselect" resultType="com.MrChengs.bean.Employee" databaseId="mysql"> <if test="_databaseId=='mysql'"> select * from test <if test="_parameter!=null"> where id=#{id} </if> </if> <if test="_databaseId=='oracle'"> select * from test </if> </select>
@Test public void testgetEmpselect() throws IOException { SqlSessionFactory sessionFactory = getSqlSessionFactory(); SqlSession session = sessionFactory.openSession(); try{ DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class); List<Employee> emps= mapper.getEmpselect(5); System.out.println(emps); }finally{ session.close(); } }
//测试两个属性 //public List<Employee> getEmpselect(); //public List<Employee> getEmpselect(int id); public List<Employee> getEmpselect(Employee em);
xml文件:
测试类:
@Test public void testgetEmpselect() throws IOException { SqlSessionFactory sessionFactory = getSqlSessionFactory(); SqlSession session = sessionFactory.openSession(); try{ DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class); //List<Employee> emps= mapper.getEmpselect(); //List<Employee> emps= mapper.getEmpselect(5); Employee emp = new Employee(); emp.setName("M"); List<Employee> emps= mapper.getEmpselect(emp); System.out.println(emps); }finally{ session.close(); } }
E.SQL标签