Mybatis中的动态sql
1.Mybatis动态sql介绍
在传统的JDBC连接数据库总,我们需要编写大量的java代码来对sql语句进行拼接,对sql语句的拼接使得代码的可复用性很差,我们将大量的时间花在了编写java拼接sql语句上,开发速度慢。Mybatis使用了动态sql语句的方法,使得拼接sql代码的时间大大减少,引用Mybatis官方的就是:动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦 。
2.Mybatis动态sql的使用
2.1 Mybatis简介
使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
2.2 万能的Map
在介绍动态sql之前,我们需要了解的是,在进行数据库中进行数据操作时,引入Map可以达到很多的操作。下面我们简单介绍一下的Map的强大。
代码:
UserMapper接口
package com.xiaoli.dao;
import com.xiaoli.pojo.User;
import java.util.List;
import java.util.Map;
public interface UserMapper {
//查询用户:万能的Map
//我们需要查询id为1的用户,不使用基本数据类型进行查询,使用Map
List<User> getUserList(Map map);
}
UserMapper.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaoli.dao.UserMapper">
<!--
parameterType:表示传入的元素类型
select * from user where id = #{user_id}
1.表示传入的元素user_id
2.理解为map映射的key为:"user_id",然后取key为user_id的值value
-->
<select id="getUserList" parameterType="map" resultType="user">
select * from user where id = #{user_id}
</select>
</mapper>
测试代码:
package com.xiaoli.dao;
import com.xiaoli.pojo.User;
import com.xiaoli.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TestUserMapper {
@Test
public void testGetUserList(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String,Object> map = new HashMap<String,Object>();
//传入key为user_id,value值为1的数据
map.put("user_id",1);
List<User> userList = mapper.getUserList(map);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
}
测试结果:
2.3 if元素
-
if元素语法(举例)
<select id="getUserIf" parameterType="map" resultType="User"> select * from user where 1 = 1 <if test="user_id != null"> and id = #{user_id} </if> </select>
-
代码测试
-
UserMapper接口
package com.xiaoli.dao; import com.xiaoli.pojo.User; import java.util.List; import java.util.Map; public interface UserMapper { //动态sql:if元素 List<User> getUserIf(Map map); }
-
UserMapper.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xiaoli.dao.UserMapper"> <!--动态sql:if元素--> <select id="getUserIf" parameterType="map" resultType="User"> select * from user where 1 = 1 <if test="user_id != null"> and id = #{user_id} </if> </select> </mapper>
-
测试代码
package com.xiaoli.dao; import com.xiaoli.pojo.User; import com.xiaoli.util.MybatisUtil; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.HashMap; import java.util.List; import java.util.Map; public class TestUserMapper { //动态sql:if元素 @Test public void testGetUserIf(){ SqlSession sqlSession = MybatisUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map<String,Object> map = new HashMap<String,Object>(); //传入key为user_id,value值为1的数据 map.put("user_id",1); List<User> userList = mapper.getUserIf(map); for (User user : userList) { System.out.println(user); } sqlSession.close(); } }
-
测试结果:
-
2.4 where元素
细心的你可能发现了,上面使用的if元素存在一个局限性,在外面查询时,需要在条件查询前加上where 1=1 条件,这样我们才能在后面的使用if元素,所以Mybatis官方为我们引入了where元素。
代码测试:
-
UserMapper接口
package com.xiaoli.dao; import com.xiaoli.pojo.User; import java.util.List; import java.util.Map; public interface UserMapper { //动态sql:where元素 List<User> getUserWhere(Map map); }
-
UserMapper.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xiaoli.dao.UserMapper"> <!--动态sql:where元素--> <select id="getUserWhere" parameterType="map" resultType="User"> select * from user <where> <if test="user_id != null"> id = #{user_id} </if> </where> </select> </mapper>
-
测试代码
package com.xiaoli.dao; import com.xiaoli.pojo.User; import com.xiaoli.util.MybatisUtil; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.HashMap; import java.util.List; import java.util.Map; public class TestUserMapper { //动态sql:where元素 @Test public void testGetUserWhere(){ SqlSession sqlSession = MybatisUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map<String,Object> map = new HashMap<String,Object>(); //传入key为user_id,value值为1的数据 map.put("user_id",1); List<User> userList = mapper.getUserIf(map); for (User user : userList) { System.out.println(user); } sqlSession.close(); } }
-
测试结果
2.5 chose(where,otherwise)元素
chose(where,otherwise)解决了一个问题,当我们不想使用所有的元素时,我们需要一种能够选择的方式来执行sq语句,我们选择使用chose和其附带的元素,当我们需要在sql语句中做选择,我们可以使用他。引用官方的介绍就是:
“有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。”
-
代码测试:
UserMapper接口
package com.xiaoli.dao; import com.xiaoli.pojo.User; import java.util.List; import java.util.Map; public interface UserMapper { //动态sql:chose(when,otherwise)元素 List<User> getUserChoseWhenOtherwise(Map map); }
UserMapper.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xiaoli.dao.UserMapper"> <!--动态sql:chose(when,otherwise)元素--> <select id="getUserChoseWhenOtherwise" parameterType="map" resultType="User"> select * from user <where> <choose> <when test="stu_id != null"> id = #{stu_id} </when> <when test="stu_name != null"> and name = #{stu_name} </when> <otherwise> and id = 1 </otherwise> </choose> </where> </select> </mapper>
-
测试代码:
package com.xiaoli.dao; import com.xiaoli.pojo.User; import com.xiaoli.util.MybatisUtil; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.HashMap; import java.util.List; import java.util.Map; public class TestUserMapper { //动态sql:chose(when,otherwise)元素 @Test public void testGetUserChoseWhenOtherwise(){ SqlSession sqlSession = MybatisUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map map = new HashMap<String,Object>();//我们这里尝试不向map中传入数据,查看查询到的数据 List<User> userChoseWhenOtherwise = mapper.getUserChoseWhenOtherwise(map); for (User user : userChoseWhenOtherwise) { System.out.println(user); } sqlSession.close(); } }
测试结果:
-
接下来我们尝试向Map中传入我们预先指定的参数,查看代码测试结果:
测试代码:
package com.xiaoli.dao; import com.xiaoli.pojo.User; import com.xiaoli.util.MybatisUtil; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.HashMap; import java.util.List; import java.util.Map; public class TestUserMapper { //动态sql:chose(when,otherwise)元素 @Test public void testGetUserChoseWhenOtherwise(){ SqlSession sqlSession = MybatisUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map map = new HashMap<String,Object>(); //我们向map中传入我们预先指定的元素,查看数据的查询结果 map.put("stu_id",2); List<User> userChoseWhenOtherwise = mapper.getUserChoseWhenOtherwise(map); for (User user : userChoseWhenOtherwise) { System.out.println(user); } sqlSession.close(); } }
测试结果:
2.6 where,set元素
在CRUD的修改中,我们需要用到where与set元素的组合。
-
代码测试:
UserMapper接口
package com.xiaoli.dao; import com.xiaoli.pojo.User; import java.util.List; import java.util.Map; public interface UserMapper { //动态sql:where,set元素 int updateUserWhereSet(Map map); }
UserMapper.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xiaoli.dao.UserMapper"> <!--动态sql:where,set元素--> <update id="updateUserWhereSet" parameterType="map"> update user <set> <if test="stu_name != null"> name = #{stu_name},</if> <if test="stu_password != null"> password = #{stu_password}</if> </set> <where> id = #{stu_id} </where> </update> </mapper>
-
测试代码:
package com.xiaoli.dao; import com.xiaoli.pojo.User; import com.xiaoli.util.MybatisUtil; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.HashMap; import java.util.List; import java.util.Map; public class TestUserMapper { //动态sql:where,set元素 @Test public void testUpdateUserWhereSet(){ SqlSession sqlSession = MybatisUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map map = new HashMap<String,Object>(); map.put("stu_id",1);//设置id map.put("stu_name","小扎");//设置需要修改的属性 int i = mapper.updateUserWhereSet(map); System.out.println(i); sqlSession.commit();//设置事务提交 sqlSession.close(); } }
测试结果:
-
2.7 foreach遍历元素
我们为什么引入foreach元素,动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。
你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
-
代码测试:
UserMapper接口
package com.xiaoli.dao; import com.xiaoli.pojo.User; import java.util.List; import java.util.Map; public interface UserMapper { //动态sql:foreach遍历元素 List<User> getUserForEach(Map map); }
UserMapper.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xiaoli.dao.UserMapper"> <!--动态sql:foreach遍历元素--> <!-- foreach标签:遍历集合或者容器 index:起点 collection:遍历的集合 open与close:对foreach标签中的元素包围 separator:分界符 --> <select id="getUserForEach" parameterType="map" resultType="User"> select * from user <where> <foreach collection="userList" index="0" item="this" open="(" close=")" separator="or"> id = #{this} </foreach> </where> </select> </mapper>
-
测试代码
package com.xiaoli.dao; import com.xiaoli.pojo.User; import com.xiaoli.util.MybatisUtil; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class TestUserMapper {s //动态sql:foreach遍历元素 @Test public void testGetUserForEach(){ SqlSession sqlSession = MybatisUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map map = new HashMap<String,Object>(); List<Integer> list = new ArrayList<>(); list.add(1);//我们先集合中放入三个元素 list.add(2); list.add(4); map.put("userList",list); List<User> userForEach = mapper.getUserForEach(map); for (User forEach : userForEach) { System.out.println(forEach); } sqlSession.close(); } }
测试结果:
-
3.sql片段
有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽
取出来,然后使用时直接调用。
-
抽取sql片段
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xiaoli.dao.UserMapper"> <sql id="sql_example"> <where> id = #{id} </where> </sql> <!--抽取sql片段--> <select id="getUserSql" parameterType="_int" resultType="User"> select * from user <include refid="sql_example"></include> </select> </mapper>
-
测试代码:
//动态sql:sql片段 @Test public void testGetUserSql(){ SqlSession sqlSession = MybatisUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userSql = mapper.getUserSql(1); for (User user : userSql) { System.out.println(user); } sqlSession.close(); }
测试结果: