1.1 动态sql语句概述
Mybatis 的映射文件中,业务逻辑复杂时, SQL是动态变化的,此时在前面的学习中 SQL 就不能满足要求了。
参考的官方文档:
1.2 动态 SQL 之<if>
根据实体类的不同取值,使用不同的 SQL语句来进行查询
比如在 id 如果不为空时可以根据id查询,如果username 不为空时还要加入用户名作为条件。
这种情况在多条件组合查询中经常会碰到
<select id="findColl" parameterType="user" resultType="user">select * from T_user<where> <!--表示where--><if test="id!=0">id=#{id}</if><if test="username!=null and username!=''">and username=#{username}</if></where>
编写dao接口:
//多条件查询
public List<User> findColl(User user);
当查询条件id和username都存在时,控制台打印的sql语句如下:
@Testpublic void findCollT(){SqlSession sqlSession = MybatisUtils.getSqlSession(true);UserDao mapper = sqlSession.getMapper(UserDao.class);User user=new User();user.setId(1);user.setUsername("张三");List<User> coll = mapper.findColl(user);System.out.println(coll.toString());MybatisUtils.closeSqlSession(sqlSession);}
当查询条件只有id存在时,控制台打印的sql语句如下:
//获得MyBatis框架生成的UserDao接口的实现类
@Testpublic void findCollT(){SqlSession sqlSession = MybatisUtils.getSqlSession(true);UserDao mapper = sqlSession.getMapper(UserDao.class);User user=new User();user.setId(1);List<User> coll = mapper.findColl(user);System.out.println(coll.toString());
MybatisUtils.closeSqlSession(sqlSession);}
总结语法:
<where>:条件标签。如果有动态条件,则使用该标签代替 where 关键字。
<if>:条件判断标签。
<if test=“条件判断”>查询条件拼接
</if>
1.3 动态sql之set (update insert)
<!-- 动态语句 set 更新语句 update 表名 set name=#{name} --><update id="updateMap" parameterType="map">update T_user <set><if test="username!=null">username=#{username},</if><if test="sex!=null">sex=#{sex}</if></set><where><if test="id!=null">id=#{id}</if></where></update><!-- 动态语句 set 插入语句 insert into 表名 set name=#{name},age=#{age} --><insert id="saveMap" parameterType="map">insert into T_user<set><if test="id!=null">id=#{id},</if><if test="username!=null">username=#{username},</if><if test="sex!=null">sex=#{sex},</if><if test="address!=null">address=#{address},</if><if test="birthday!=null">birthday=#{birthday}</if></set></insert>
编写dao接口添加方法:
public int updateMap(Map<String ,Object> map);
public int saveMap(Map<String ,Object> map);
测试类编写:
修改的测试方法
@Testpublic void updatemap(){SqlSession sqlSession = MybatisUtils.getSqlSession(true);UserDao mapper = sqlSession.getMapper(UserDao.class);
Map<String,Object> map=new HashMap<>();map.put("id",1);map.put("username","老六");map.put("sex","女");int i = mapper.updateMap(map);System.out.println(i);}
添加的测试方法@Testpublic void savemapT(){SqlSession sqlSession = MybatisUtils.getSqlSession(true);UserDao mapper = sqlSession.getMapper(UserDao.class);
Map<String,Object> map=new HashMap<>();map.put("username","老六");map.put("sex","女");map.put("address","郑州");map.put("birthday",Date.valueOf("2010-03-09"));int i = mapper.saveMap(map);System.out.println(i);}
总结语法:
<set>:条件标签。set 元素可以用于动态包含需要更新的列
<if>:条件判断标签。
<if test="条件判断">查询条件拼接
</if>
1.4 动态sql之choose (when, otherwise)
相当于Java中的switch语句
当when有条件满足的时候,就跳出choose
<choose><when test="条件1">...</when><when test="条件2">...</when><when test="条件3">...</when><otherwise>其他条件</otherwise>
</choose>
代码演示步骤:
1、编写Dao接口代码
2、编写mapper文件
3、测试运行
代码实现:
编写Dao接口代码
public List<User> showUserfindAll(@Param("username") String username,@Param("sex") String sex,@Param("address") String address,@Param("birthday") Date birthday;
编写mapper文件
<!-- 动态语句choose when when otherwise -->
<!-- if elseif elseif else<choose><when test=""></when><when test=""></when><when test=""></when><otherwise>...</otherwise></choose>-->
<select id="showUserfindAll" resultType="cn.zxy.pojo.User">select * from user where <choose><when test="username!=null and username!=''">username like concat("%",#{username},"%")</when><when test="sex!=null and sex!=''">sex =#{sex}</when><when test="address!=null and address!=''">address like concat("%",#{address},"%")</when><otherwise>year(birthday)=year(#{birthday})</otherwise>
</choose>
另一种写法
<select id="showUserfindAll" resultType="cn.zxy.pojo.User">select * from user <where><choose><when test="username!=null"><choose><when test="username.indexOf('%')!=-1"> username like #{username}</when><when test="username.indexOf('_')!=-1">username like #{username}</when><otherwise>username = #{username}</otherwise></choose></when><when test="sex!=null and sex!=''">sex =#{sex}</when><when test="address!=null and address!=''">address like concat("%",#{address},"%")</when><otherwise>birthday=#{birthday}</otherwise></choose></where></select>
实体和数据库名字不匹配
<!-- 查询中如果表字段名和实体类名不一致,不想定义ResultMap,可以使用查询的列名 -->
<sql id="s1p">id,user_name username,birthday birth,address addr,sex sex</sql>
<select id="showUserfindAll" resultType="cn.zxy.pojo.User">select <include refid="s1p"/> from user where 1=1<choose><when test="username!=null"><choose><when test="username.indexOf('%')!=-1">user_name like #{username}</when><when test="username.indexOf('_')!=-1">user_name like #{username}</when><otherwise>user_name = #{username}</otherwise></choose></when><when test="sex!=null and sex!=''">and sex =#{sex}</when><when test="address!=null and address!=''">and address like concat("%",#{addr},"%")</when><otherwise>and year(birthday)=year(#{birth})</otherwise></choose>
</select>
测试运行
@Testpublic void test() throws IOException {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);SqlSession session = factory.openSession();UserDao userDao = session.getMapper(UserDao.class);List<User> users = userDao.showUserfindAll("小_", "男", "河", null);System.out.println(users.toString());
}
1.5 动态 SQL 之<foreach>
循环执行sql的拼接操作,例如:SELECT * FROM user WHERE id IN (1,2,5)。
foreach 迭代一个集合,通常用于in条件
属性:
-
item 查询条件
-
collection:必须指定
-
list
-
array
-
map—key
-
-
open : 括号 (
-
separator :分割符 ,
-
close :括号 )
例子如下
<!--循环迭代-->
<select id="findByIds" parameterType="list" resultType="user"><!--collection: 表示集合存储类型 分别为 list array数组open : id in ( 是指代 where id in(close: 闭合括号item : 查询条件separator: 分割符-->select * from T_user<where><foreach collection="list" open="id in (" close=")" item="id" separator=",">#{id}</foreach></where>
</select>
编写dao接口:
//根据多个id查询
public List<User> findByIds(List<Integer> ids);
测试代码片段如下:
@Testpublic void findByidst() {//获取sqlssession给定的对象SqlSession sqlSession = MybatisUtils.getSqlSession(true);UserDao mapper = sqlSession.getMapper(UserDao.class);//创建list集合 并赋值List<Integer> list=new ArrayList<>();list.add(1);list.add(3);list.add(5);//把集合里面的值赋给mapperList<User> byIds = mapper.findByIds(list);for (User byId : byIds) {System.out.println(byId);}MybatisUtils.closeSqlSession(sqlSession);}
批量插入:
Mapper接口编写
public void insert(List<User> list);
映射文件编写:
<insert id="insert" parameterType="user">insert into user values<foreach collection="list" separator="," item="user">(#{user.id},#{user.username},#{user.sex},#{user.address},#{user.birthday})</foreach></insert>
测试类编写:
@Testpublic void inTest(){SqlSession sqlSession = MyBatisUtils.getSqlSession(true);DUserMapper mapper = sqlSession.getMapper(DUserMapper.class);long start=System.currentTimeMillis();log.info("开始的时间{}",start);List<User> userList=new ArrayList<>();User user;for (int i = 0; i < 5; i++) {user=new User();user.setUsername("唐"+i);user.setSex("男");user.setAddress("河南北京");user.setBirthday(new Date());userList.add(user);}mapper.insert(userList);long end = System.currentTimeMillis();log.info("结束的时间{}",(end-start));}
总结语法:
<foreach>:循环遍历标签。适用于多个参数或者的关系。<foreach collection="" open="" close="" item="" separator="">获取参数</foreach>
属性
collection:参数容器类型, (list-集合, array-数组)
open:开始的 SQL 语句 id in (
close:结束的 SQL 语句
item:参数变量名
separator:分隔符
1.6 SQL片段抽取
Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的
<!--抽取sql片段简化编写-->
<sql id="selectUser" select * from student</sql>
<!--根据id查询-->
<select id="findById" parameterType="int" resultType="user"><include refid="selectUser"></include> where id=#{id}
</select>
<!--根据ids遍历-->
<select id="findByIds" parameterType="list" resultType="student"><include refid="selectUser"></include><where><foreach collection="array" open="id in(" close=")" item="id" separator=",">#{id}</foreach></where>
</select>
总结语法:
我们可以将一些重复性的 SQL 语句进行抽取,以达到复用的效果。
- <sql>:抽取 SQL 语句标签。
- <include>:引入 SQL 片段标签。 <sql id=“片段唯一标识”>抽取的 SQL 语句</sql>
<include refid=“片段唯一标识”/>
1.7 知识小结
MyBatis映射文件配置:
<select>:查询
<insert>:插入
<update>:修改
<delete>:删除
<where>:where条件
<if>:if判断
<foreach>:循环
<sql>:sql片段抽取