MyBatis 配置深入
核心配置
动态SQL
动态 SQL 是 MyBatis 的一个重要特性,用于根据条件动态生成不同的 SQL 语句。它允许开发者使用类似编程语言的逻辑结构来构建 SQL,解决了复杂查询条件下 SQL 的拼接问题,提高了开发效率和代码的可读性。
动态SQL的用途
- 灵活性:处理动态变化的查询条件,例如用户界面的表单筛选条件。
- 避免冗余:可以通过动态语法合并多个类似的 SQL 查询逻辑,减少代码冗余。
- 提高效率:仅在需要时生成相应的 SQL,避免加载不必要的数据。
动态SQL的注意事项
null 值的处理
MyBatis 不会自动过滤 null 值,需在 SQL 标签中显式判断。
复杂逻辑的可读性
动态 SQL 逻辑过多会导致 XML 文件过于复杂,建议合理拆分。
性能问题
动态生成的 SQL 应尽量减少复杂性,避免影响数据库查询性能。
调试
可以开启 MyBatis 的日志功能,查看生成的 SQL,确保正确性。
参数拼接
我们需要根据实体的不同取值,使用不同的 SQL 语句来进行查询,比如在 ID 如果不为空的时候可以根据 ID 查询,如果 username 不空时还要加入用户名作为条件,这种情况在我们的多条件组合查询中经常会碰到。
<!-- 查询所有用户信息 -->
<select id="selectList" resultType="icu.wzk.model.UserInfo">
SELECT
*
FROM
user_info
<where>
<if test="username != null and username != ''">
and username=#{username}
</if>
<if test="password != null and password != ''">
and password=#{password}
</if>
<if test="age != null and age != ''">
and age=#{age}
</if>
</where>
</select>
测试代码
public class WzkIcu05 {
public static void main(String[] args) throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserInfoMapper userInfoMapper = sqlSession.getMapper(UserInfoMapper.class);
UserInfo userInfo = UserInfo
.builder()
.username("wzk")
.build();
List<UserInfo> dataList = userInfoMapper.selectList(userInfo);
dataList.forEach(System.out::println);
sqlSession.close();
}
}
执行结果日志
24/11/11 15:59:59 DEBUG UserInfoMapper.selectList: ==> Preparing: SELECT * FROM user_info WHERE username=?
24/11/11 15:59:59 DEBUG UserInfoMapper.selectList: ==> Parameters: wzk(String)
24/11/11 15:59:59 DEBUG UserInfoMapper.selectList: <== Total: 1
UserInfo(id=1, username=wzk, password=icu, age=18)
循环拼接
我们在 UserMapper 中添加一个新的方法:
List<UserInfo> selectListByIdList(@Param("idList") List<Integer> idList);
对应的 XML 编写
<select id="selectListByIdList" parameterType="icu.wzk.model.UserInfo" resultType="icu.wzk.model.UserInfo">
SELECT
*
FROM
user_info
<where>
id IN
<foreach collection="idList" open="(" close=")" separator="," index="index" item="item">
#{item}
</foreach>
</where>
</select>
测试代码
public class WzkIcu06 {
public static void main(String[] args) throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserInfoMapper userInfoMapper = sqlSession.getMapper(UserInfoMapper.class);
List<Integer> idList = Arrays.asList(1, 2, 3);
List<UserInfo> dataList = userInfoMapper.selectListByIdList(idList);
dataList.forEach(System.out::println);
sqlSession.close();
}
}
执行结果日志
24/11/11 16:15:16 DEBUG UserInfoMapper.selectListByIdList: ==> Preparing: SELECT * FROM user_info WHERE id IN ( ? , ? , ? )
24/11/11 16:15:16 DEBUG UserInfoMapper.selectListByIdList: ==> Parameters: 1(Integer), 2(Integer), 3(Integer)
24/11/11 16:15:16 DEBUG UserInfoMapper.selectListByIdList: <== Total: 3
UserInfo(id=1, username=wzk, password=icu, age=18)
foreach 标签属性说明
- collection: 要遍历的集合元素,主要不要写 #{}
- open: 语句的开始部分
- close: 语句的结束部分
- item: 集合遍历的每个元素,生成的遍历名
- separator: 分割符号
片段抽取
SQL 中重复的 SQL 提取出来,使用 include 引用即可,最终达到 SQL 重复使用的目的。
我们在 UserInfoMapper 的接口中添加一个方法:
UserInfo selectOneBySegment(UserInfo userInfo);
编写对应的 XML
<sql id="SELECT_USER_INFO">
SELECT * FROM user_info
</sql>
<select id="selectOneBySegment" parameterType="icu.wzk.model.UserInfo" resultType="icu.wzk.model.UserInfo">
<include refid="SELECT_USER_INFO"></include>
<where>
id=#{id}
</where>
</select>
测试代码
public class WzkIcu07 {
public static void main(String[] args) throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserInfoMapper userInfoMapper = sqlSession.getMapper(UserInfoMapper.class);
UserInfo userInfo = UserInfo
.builder()
.id(1L)
.build();
userInfo = userInfoMapper.selectOneBySegment(userInfo);
System.out.println(userInfo);
sqlSession.close();
}
}
执行结果日志
24/11/11 17:04:08 DEBUG UserInfoMapper.selectOneBySegment: ==> Preparing: SELECT * FROM user_info WHERE id=?
24/11/11 17:04:08 DEBUG UserInfoMapper.selectOneBySegment: ==> Parameters: 1(Long)
24/11/11 17:04:08 DEBUG UserInfoMapper.selectOneBySegment: <== Total: 1
UserInfo(id=1, username=wzk, password=icu, age=18)