一. 动态Sql 查询
在数据库的持久化操作的过程中,最复杂最常用的就是查询 select 语句, 主要是后面跟着各种各样的 条件判断语句。而MyBatis很好的提供了这一点。 体现了Mybatis的灵活性,高度可配置性和可维护性。
具有的sql动态元素有:
1.if 判断 单分支的语句
2.choose (when otherwise) 多条件分支
3.trim 去除前缀和后缀的第一个符号
4.where 辅助元素, 代替 sql中的 1=1
5.set 更新元素
6.foreach 循环判断
7.bind 绑定元素
下面 老蝴蝶 会讲解这些元素的使用。
二. if元素
二.一 以前不带参数的查询
老蝴蝶 以前常写的 查询全部:
接口:
User getById(int id); List<User> findAllF1();
sql 语句配置:
<!-- 定义map形式 --> <resultMap type="user" id="userResultMap"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="sex" column="sex"/> <result property="age" column="age"/> <result property="description" column="description"/> </resultMap> <select id="getById" parameterType="int" resultType="user"> <!-- 设置别名 --> select * from user where id=#{id} </select> <select id="findAllF1" resultMap="userResultMap"> select * from user t </select>
测试方法:
@Test public void findAllF1Test(){ SqlSession sqlSession=SqlSessionFactoryUtils.getSession(); UserMapper userMapper=sqlSession.getMapper(UserMapper.class); List<User> allList=userMapper.findAllF1(); allList.forEach(n ->System.out.println(n)); }
二.二 带参数的简单查询
上面的都是没有传入条件的,下面传入条件。 按照 名称进行查询,其中,名称可填可不填。 即,如果名称有值,则按照名称进行查询,如果没有传入名称值,则查询全部。
接口:
List<User> findAllF2(User user);
sql 元素: 用mybatis提供的 if 元素 进行单分支判断。
<select id="findAllF2" parameterType="user" resultMap="userResultMap"> select * from user t where <if test="name!=null and name!=''"> t.name like concat('%',#{name},'%') </if> </select>
测试方法:
@Test public void findAllF2Test(){ SqlSession sqlSession=SqlSessionFactoryUtils.getSession(); UserMapper userMapper=sqlSession.getMapper(UserMapper.class); User user=new User(); user.setName("蝴蝶飞"); List<User> allList=userMapper.findAllF2(user); allList.forEach(n ->System.out.println(n)); }
可以填写查询的值为 蝴蝶飞, 可以查询出结果。
但如果此时 没有传入 name值呢?
即将 user.setName(“蝴蝶飞”); 注释掉:
是错误的。
二.三 添加1=1 避免sql语句组装不正确
所以,常见的写法就是在where 后面添加一个 1=1, 避免在没有传入参数时,sql 语句组装不正确。
<select id="findAllF2" parameterType="user" resultMap="userResultMap"> select * from user t where 1=1 <if test="name!=null and name!=''"> and t.name like concat('%',#{name},'%') </if> </select>
当然,也可以传入多个参数, 如按照name 和age 进行查询。 接口是不变的。
sql 语句也按照 上面 if 的写法。 后面加上1=1 就避免了sql语句出现错误
<select id="findAllF2" parameterType="user" resultMap="userResultMap"> select * from user t where 1=1 <if test="name!=null and name!=''"> and t.name like concat('%',#{name},'%') </if> <if test="age!=null"> and t.age>#{age} </if> </select>
测试方法:
@Test public void findAllF2Test(){ SqlSession sqlSession=SqlSessionFactoryUtils.getSession(); UserMapper userMapper=sqlSession.getMapper(UserMapper.class); User user=new User(); //两个条件时 user.setName("蝴蝶飞"); user.setAge(24); List<User> allList=userMapper.findAllF2(user); allList.forEach(n ->System.out.println(n)); }
传入一个name 参数,传入一个age 参数, 不传参数, 都是正确的, 只是拼接的sql 语句不一样而已。
三. where 语句
在if 中 写的 1=1 虽然避免了错误,但总是不合理的, 应该直接对参数进行相应的解析。如果没有传入值,应该是 select * from user, 而不是 后面再跟上 where 1=1 , 故可以用where 语句进行。 where 语句中条件正确成立后,才会加上 where 语句。
故 接口为:
List<User> findAllF3(User user);
sql语句:
<select id="findAllF3" parameterType="user" resultMap="userResultMap"> select * from user t <where> <if test="name!=null and name!=''"> and t.name like concat('%',#{name},'%') </if> <if test="age!=null"> and t.age>#{age} </if> </where> </select>
测试方法:
@Test public void findAllF3Test(){ SqlSession sqlSession=SqlSessionFactoryUtils.getSession(); UserMapper userMapper=sqlSession.getMapper(UserMapper.class); User user=new User(); //user.setName("蝴蝶飞"); //填写时, 不填写时不又其作为查询条件。 //两个条件时 user.setName("蝴蝶飞"); user.setAge(24); List<User> allList=userMapper.findAllF3(user); allList.forEach(n ->System.out.println(n)); }
传入两个参数是:
传入一个 name 参数为:
传入一个 age 参数为:
不传入参数为:
这样,就可以达到 去除 1=1 的效果了。