1.介绍
动态SQL:动态SQL是指根据不同的查询条件,生成不同的SQL语句
我们之前写的 SQL 语句都比较简单,如果有比较复杂的业务,我们需要写复杂的 SQL 语句,往往需要拼接,而拼接 SQL ,稍微不注意,由于引号,空格等缺失可能都会导致错误。那么怎么去解决这个问题呢?这就要使用 mybatis 动态SQL,通过 if, choose, when, otherwise,trim, where, set, foreach等标签,可组合成非常灵活的SQL语句,从而在提高 SQL 语句的准确性的同时,也大大提高了开发人员的效率。
2.搭建坏境
数据库信息:
#创建表 CREATE TABLE `user` ( `id` INT(5) NOT NULL AUTO_INCREMENT COMMENT '编号', `username` VARCHAR(50) DEFAULT NULL COMMENT '姓名', `address` VARCHAR(50) DEFAULT NULL COMMENT '住址', PRIMARY KEY (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8; # 添加数据 INSERT INTO `user` VALUES (1,'齐元松','河南'), (2,'苏炳添','中国'), (3,'齐菁菁','河南'), (4,'牛辉','中国'), (5,'刘祥','中国'), (6,'齐元松','河南'), (7,'齐元松','中国'), (100,'詹三','中国');
编写实体类:
@Data public class User { private int id; private String username; private String address; }
编写Mapper接口及xml文件
public interface UserMapper { }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mapper.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.lili.dao.UserMapper"> </mapper>
3.编写代码
1. if,where的使用
需求:根据所传参数进行动态查询:
编写接口类:
List<User> findUserByIf(Map<String, Object> map);
编写xml文件:
<select id="findUserByIf" parameterType="map" resultType="com.lili.entity.User"> select * from user <where> <if test="id != null"> id = #{id} </if> <if test="username != null"> and username = #{username} </if> <if test="address !=null"> and address = #{address} </if> </where> </select>
这里注意,where标签的作用:如果没有满足条件的,自动去除where,有的话,会加上where 并且去掉第一个and
编写测试:
@Test public void test2() { try (SqlSession sqlSession = MybatisUtil.getSqlSession()) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map<String,Object> map = new HashMap<>(); map.put("id",1); map.put("username","齐元松"); map.put("address","中国"); List<User> users = mapper.findUserByIf(map); users.forEach(System.out::println); } catch (Exception e) { e.printStackTrace(); } }
2. set
当我们想更新一条数据时,我们只需要传入须要更新的字段值即可
接口方法:
int update(User user);
编写Mapper:
<update id="update" parameterType="com.lili.entity.User"> update user <set> <if test="username !=null"> username = #{username}, </if> <if test="address !=null"> address = #{address} </if> where id = #{id} </set> </update>
编写测试:
@Test public void test4() { try (SqlSession sqlSession = MybatisUtil.getSqlSession()) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = new User(); user.setId(100); user.setAddress("中国"); user.setUsername("詹三"); int i = mapper.update(user); System.out.println(i); sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } }
3. choose语句
有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose标签可以解决此类问题,类似于 Java 的 switch 语句
接口方法:
List<User> findUserByChoose(Map<String, Object> map);
编写Mapper:
<select id="findUserByChoose" parameterType="map" resultType="com.lili.entity.User"> select * from user <where> <choose> <when test="id !=null">id = #{id}</when> <when test="username !=null">username = #{username}</when> <when test="address !=null">address = #{address}</when> <otherwise>id = 1</otherwise> </choose> </where> </select>
编写测试:
@Test public void test3() { try (SqlSession sqlSession = MybatisUtil.getSqlSession()) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map<String, Object> map = new HashMap<>(); map.put("username", "齐元松"); List<User> users = mapper.findUserByChoose(map); users.forEach(System.out::println); } catch (Exception e) { e.printStackTrace(); } }
4. SQL片段
有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。
提取sql片段:
<sql id="username_address"> <if test="username !=null"> username = #{username}, </if> <if test="address !=null"> address = #{address} </if> </sql>
引用sql片段:
<update id="update" parameterType="com.lili.entity.User"> update user <set> <include refid="username_address"/> where id = #{id} </set> </update>
5. foreach语句
需求:查询id为1或2或3或4的信息
接口方法:
List<User> findByForeach(@Param("idList") List<Integer> idList);
编写Mapper:
<select id="findByForeach" resultType="com.lili.entity.User" parameterType="list"> select * from user where id in <foreach collection="idList" item="id" open="(" separator="," close=")"> #{id} </foreach> </select>
编写测试:
@Test public void test5() { try (SqlSession sqlSession = MybatisUtil.getSqlSession()) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<Integer> integers = Arrays.asList(1, 2, 3, 4); List<User> users = mapper.findByForeach(integers); users.forEach(System.out::println); } catch (Exception e) { e.printStackTrace(); } }
小结:其实动态 sql 语句的编写往往就是一个拼接的问题,为了保证拼接准确,我们最好首先要写原生的 sql 语句出来,然后在通过 mybatis 动态sql 对照着改,防止出错。多在实践中使用才是熟练掌握它的技巧