在使用 JDBC 的过程中, 根据条件进行 SQL 的拼接是很麻烦且很容易出错的。 MyBatis 动态 SQL 的出现, 解决了这个麻烦。Mybatis提供了动态SQL,可以根据用户提供的参数,动态决定查询语句依赖的查询条件或SQL语句的内容。
目前, MyBatis 动态 SQL 支持以下几种标签
元素 | 作用 | 备注 |
---|---|---|
if | 判断语句 | 单条件分支 |
choose(when、otherwise) | 相当于 Java 中的 if else | 多条件分支 |
trim(where、set) | 辅助元素 | 用于处理 SQL 拼接问题 |
foreach | 循环语句 | 批量插入, 更新, 查询时经常用到 |
bind | 创建一个变量, 并绑定到上下文中 | 用于兼容不同的数据库, 防止 SQL 注入等 |
在介绍各标签使用前,我们先创建一个Spring整合Mybatis工程 【Spring】Spring整合Mybatis案例
工程目录结构如下:
数据库中创建一张user
表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8;
if
标签需要配合 test
属性联合使用,通常在查询、删除、更新的时候用到
根据输入的用户信息进行条件检索
name
名时, 使用name
进行模糊检索;age
时, 使用age
条件进行匹配name
和age
都存在时, 用这两个条件进行查询匹配查询@Repository("userMapper")
@Mapper
public interface UserMapper {
List<User> selectByUserSelective(User user);
}
在UserMapper.xml
中添加动态SQL
<mapper namespace="com.lucas.mybatis.mapper.UserMapper">
<select id="selectByUserSelective" resultType="com.lucas.mybatis.model.User"
parameterType="com.lucas.mybatis.model.User">
select * from user where 1=1
<if test="name != null and name !=''">
and name like concat('%', #{name}, '%')
if>
<if test="age != null and age > 0">
and age>#{age}
if>
select>
mapper>
测试1:
public class App {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
User user = new User();
user.setName("张");
List<User> users = userMapper.selectByUserSelective(user);
for (User user1 : users) {
System.out.println(user1);
}
}
}
测试2:
public class App {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
User user = new User();
user.setAge(18);
List<User> users = userMapper.selectByUserSelective(user);
for (User user1 : users) {
System.out.println(user1);
}
}
}
测试3:
public class App {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
User user = new User();
user.setName("张");
user.setAge(18);
List<User> users = userMapper.selectByUserSelective(user);
for (User user1 : users) {
System.out.println(user1);
}
}
}
choose
标签类似于switch
语句,配合when
、otherwise
标签,一个 choose
标签至少有一个 when
, 最多一个otherwise
在UserMapper.xml
中添加动态SQL
<mapper namespace="com.lucas.mybatis.mapper.UserMapper">
<select id="selectByUserSelective" resultType="com.lucas.mybatis.model.User"
parameterType="com.lucas.mybatis.model.User">
select * from user where 1=1
<choose>
<when test="name != null and name !=''">
and name like concat('%', #{name}, '%')
when>
<when test="age != null and age > 0">
and age>#{age}
when>
<otherwise>
and id =#{id}
otherwise>
choose>
select>
mapper>
测试1:
public class App {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
User user = new User();
user.setName("张");
user.setAge(18);
user.setId(2);
List<User> users = userMapper.selectByUserSelective(user);
for (User user1 : users) {
System.out.println(user1);
}
}
}
这里的name
和age
条件都匹配,但是只拼接了第一个条件
测试2:
public class App {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
User user = new User();
user.setId(2);
List<User> users = userMapper.selectByUserSelective(user);
for (User user1 : users) {
System.out.println(user1);
}
}
}
这里的name
和age
条件都不匹配,拼接otherwise
里面的条件
前面的if条件中如果我们 把where 后的 1=1
去掉,
<select id="selectByUserSelective" resultType="com.lucas.mybatis.model.User"
parameterType="com.lucas.mybatis.model.User">
select * from user where 1=1
<if test="name != null and name !=''">
and name like concat('%', #{name}, '%')
if>
<if test="age != null and age > 0">
and age>#{age}
if>
select>
我们只需在外层加个where
即可解决这种问题
<select id="selectByUserSelective" resultType="com.lucas.mybatis.model.User"
parameterType="com.lucas.mybatis.model.User">
select * from user
<where>
<if test="name != null and name !=''">
and name like concat('%', #{
name}, '%')
</if>
<if test="age != null and age > 0">
and age>#{
age}
</if>
</where>
</select>
在 update更新中一般可以使用set
标签
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.lucas.mybatis.mapper.UserMapper">
<update id="selectByUserSelective"
parameterType="com.lucas.mybatis.model.User">
update user
<set>
<if test="name != null and name !=''">name = #{
name},</if>
<if test="age != null and age > 0">age= #{
age}</if>
</set>
<where>id = #{
id}</where>
</update>
</mapper>
public class App {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
User user = new User();
user.setName("张三3");
user.setAge(19);
user.setId(2);
int result = userMapper.selectByUserSelective(user);
System.out.println(result);
}
}
trim
标签主要功能是在包含的内容前面加上某些前缀和后缀。
前面的set
和 where
其实都是 trim
标签的一种类型, 该两种功能都可以使用 trim 标签进行实现。
trim 标签常用元素如下:
前面的where
可以用 trim
表示如下:
<trim prefix="where" prefixOverrides="AND |OR"></trim>
前面的where
动态SQL可以替换如下
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.lucas.mybatis.mapper.UserMapper">
<select id="selectByUserSelective" resultType="com.lucas.mybatis.model.User"
parameterType="com.lucas.mybatis.model.User">
select * from user
<trim prefix="where" prefixOverrides="AND |OR">
<if test="name != null and name !=''">
and name like concat('%', #{
name}, '%')
</if>
<if test="age != null and age > 0">
and age>#{
age}
</if>
</trim>
</select>
</mapper>
set 标签可以 trim
表示如下:
<trim prefix="SET" suffixOverrides=","></trim>
前面的set 动态SQL可以替换如下
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.lucas.mybatis.mapper.UserMapper">
<update id="selectByUserSelective"
parameterType="com.lucas.mybatis.model.User">
update user
<trim prefix="SET" suffixOverrides=",">
<if test="name != null and name !=''">name = #{
name},</if>
<if test="age != null and age > 0">age= #{
age}</if>
</trim>
<where>id = #{
id}</where>
</update>
</mapper>
foreach 标签常用语in条件中
foreach 标签可以对数组, Map 或实现 Iterable 接口。
foreach 中常用属性如下:
@Repository("userMapper")
@Mapper
public interface UserMapper {
List<User> selectByUserSelective(List<Integer> list);
}
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.lucas.mybatis.mapper.UserMapper">
<select id="selectByUserSelective" resultType="com.lucas.mybatis.model.User"
parameterType="java.util.List">
select * from user where id in
<foreach collection="list" item="id" open="(" close=")" separator="," index="i"> #{
id}
</foreach>
</select>
</mapper>
public class App {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
List<Integer> list = new ArrayList<>();
list.add(2);
list.add(48);
list.add(49);
List<User> users = userMapper.selectByUserSelective(list);
for (User user1 : users) {
System.out.println(user1);
}
}
}
list
, 数组collection的值填arraypublic interface UserMapper {
List<User> selectByUserSelective
(@Param("mylist") List<Integer> list1);
}
<foreach collection="mylist" item="id"
open="(" close=")" separator="," index="i"> #{
id}
</foreach>
bind标签用于拼接字段形成新的变量,常用于like查询等
<select id="selectByUserSelective"
resultType="com.lucas.mybatis.model.User"
parameterType="com.lucas.mybatis.model.User">
select * from user
<bind name="nameLike" value="'%' + name + '%'"/>
<where>
<if test="name != null and name !=''">
and name like #{
nameLike}
</if>
<if test="age != null and age > 0">
and age>#{
age}
</if>
</where>
</select>