第497集MyBatis | 字数总计: 4.1k | 阅读时长: 21分钟 | 阅读量:
MyBatis 1. 概述 1.1 MyBatis的重要性 MyBatis 是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射,避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。
本文内容 :
MyBatis基础 :核心概念和配置
SQL映射 :Mapper接口和XML映射
动态SQL :动态SQL语句构建
结果映射 :结果集映射配置
缓存机制 :一级缓存和二级缓存
插件开发 :MyBatis插件机制
MyBatis Plus :增强工具包
1.2 本文内容结构 本文将从以下几个方面深入探讨MyBatis:
MyBatis基础 :核心概念和快速开始
SQL映射 :Mapper接口和XML映射
动态SQL :动态SQL语句
结果映射 :结果集映射
缓存机制 :缓存配置和使用
插件开发 :自定义插件
MyBatis Plus :增强功能
2. MyBatis基础 2.1 MyBatis特性 2.1.1 核心特性 MyBatis核心特性 :
SQL映射 :将SQL语句映射到Java方法
参数映射 :自动将Java对象映射到SQL参数
结果映射 :自动将SQL结果映射到Java对象
动态SQL :根据条件动态构建SQL
缓存机制 :一级缓存和二级缓存
MyBatis优势 :
灵活性强 :可以编写原生SQL
性能优异 :SQL可控,性能优化方便
易于学习 :学习曲线平缓
功能丰富 :支持复杂查询和映射
2.2 快速开始 2.2.1 项目配置 Maven依赖 :
1 2 3 4 5 6 7 8 9 10 11 12 <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.10</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.33</version > </dependency >
MyBatis配置文件(mybatis-config.xml) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.cj.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/test" /> <property name ="username" value ="root" /> <property name ="password" value ="password" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="mapper/UserMapper.xml" /> </mappers > </configuration >
Java代码使用 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;public class MyBatisExample { public static void main (String[] args) throws Exception { String resource = "mybatis-config.xml" ; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder () .build(inputStream); try (SqlSession session = sqlSessionFactory.openSession()) { UserMapper mapper = session.getMapper(UserMapper.class); User user = mapper.findById(1L ); System.out.println(user); } } }
2.3 Spring集成 2.3.1 Spring Boot集成 Spring Boot配置 :
1 2 3 4 5 <dependency > <groupId > org.mybatis.spring.boot</groupId > <artifactId > mybatis-spring-boot-starter</artifactId > <version > 2.2.2</version > </dependency >
application.yml配置 :
1 2 3 4 5 6 7 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.entity configuration: map-underscore-to-camel-case: true cache-enabled: true lazy-loading-enabled: false
主应用类 :
1 2 3 4 5 6 7 @SpringBootApplication @MapperScan("com.example.mapper") public class Application { public static void main (String[] args) { SpringApplication.run(Application.class, args); } }
3. SQL映射 3.1 Mapper接口 3.1.1 接口定义 Mapper接口示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Mapper public interface UserMapper { User findById (Long id) ; List<User> findAll () ; List<User> findByName (String name) ; int insert (User user) ; int update (User user) ; int deleteById (Long id) ; }
3.2 XML映射 3.2.1 XML映射文件 UserMapper.xml :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <?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.example.mapper.UserMapper" > <resultMap id ="userResultMap" type ="User" > <id property ="id" column ="id" /> <result property ="name" column ="name" /> <result property ="email" column ="email" /> <result property ="createTime" column ="create_time" /> </resultMap > <select id ="findById" parameterType ="Long" resultMap ="userResultMap" > SELECT * FROM users WHERE id = #{id} </select > <select id ="findAll" resultMap ="userResultMap" > SELECT * FROM users </select > <select id ="findByName" parameterType ="String" resultMap ="userResultMap" > SELECT * FROM users WHERE name LIKE CONCAT('%', #{name}, '%') </select > <insert id ="insert" parameterType ="User" useGeneratedKeys ="true" keyProperty ="id" > INSERT INTO users(name, email, create_time) VALUES(#{name}, #{email}, #{createTime}) </insert > <update id ="update" parameterType ="User" > UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id} </update > <delete id ="deleteById" parameterType ="Long" > DELETE FROM users WHERE id = #{id} </delete > </mapper >
3.3 注解方式 3.3.1 注解映射 注解方式示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Mapper public interface UserMapper { @Select("SELECT * FROM users WHERE id = #{id}") User findById (Long id) ; @Select("SELECT * FROM users") List<User> findAll () ; @Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})") @Options(useGeneratedKeys = true, keyProperty = "id") int insert (User user) ; @Update("UPDATE users SET name = #{name} WHERE id = #{id}") int update (User user) ; @Delete("DELETE FROM users WHERE id = #{id}") int deleteById (Long id) ; @SelectProvider(type = UserSqlProvider.class, method = "findByCondition") List<User> findByCondition (@Param("name") String name, @Param("email") String email) ; }
SQL提供者 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class UserSqlProvider { public String findByCondition (@Param("name") String name, @Param("email") String email) { return new SQL () {{ SELECT("*" ); FROM("users" ); if (name != null ) { WHERE("name LIKE CONCAT('%', #{name}, '%')" ); } if (email != null ) { WHERE("email = #{email}" ); } }}.toString(); } }
4. 动态SQL 4.1 if标签 4.1.1 条件判断 if标签示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <select id ="findByCondition" resultMap ="userResultMap" > SELECT * FROM users <where > <if test ="name != null and name != ''" > AND name LIKE CONCAT('%', #{name}, '%') </if > <if test ="email != null and email != ''" > AND email = #{email} </if > <if test ="status != null" > AND status = #{status} </if > </where > </select >
4.2 choose标签 4.2.1 多条件选择 choose标签示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <select id ="findByCondition" resultMap ="userResultMap" > SELECT * FROM users <where > <choose > <when test ="name != null" > AND name = #{name} </when > <when test ="email != null" > AND email = #{email} </when > <otherwise > AND status = 1 </otherwise > </choose > </where > </select >
4.3 foreach标签 4.3.1 循环处理 foreach标签示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <select id ="findByIds" resultMap ="userResultMap" > SELECT * FROM users WHERE id IN <foreach collection ="ids" item ="id" open ="(" separator ="," close =")" > #{id} </foreach > </select > <insert id ="batchInsert" > INSERT INTO users(name, email) VALUES <foreach collection ="users" item ="user" separator ="," > (#{user.name}, #{user.email}) </foreach > </insert >
4.4 set标签 4.4.1 动态更新 set标签示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <update id ="updateSelective" parameterType ="User" > UPDATE users <set > <if test ="name != null" > name = #{name}, </if > <if test ="email != null" > email = #{email}, </if > <if test ="status != null" > status = #{status}, </if > </set > WHERE id = #{id} </update >
4.5 trim标签 4.5.1 字符串处理 trim标签示例 :
1 2 3 4 5 6 7 8 9 10 11 12 <update id ="updateSelective" parameterType ="User" > UPDATE users <trim prefix ="SET" suffixOverrides ="," > <if test ="name != null" > name = #{name}, </if > <if test ="email != null" > email = #{email}, </if > </trim > WHERE id = #{id} </update >
5. 结果映射 5.1 简单映射 5.1.1 自动映射 自动映射 :
1 2 3 4 <select id ="findById" resultType ="User" > SELECT id, name, email FROM users WHERE id = #{id} </select >
5.2 复杂映射 5.2.1 resultMap resultMap示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <resultMap id ="orderResultMap" type ="Order" > <id property ="id" column ="order_id" /> <result property ="orderNo" column ="order_no" /> <result property ="createTime" column ="create_time" /> <association property ="user" javaType ="User" > <id property ="id" column ="user_id" /> <result property ="name" column ="user_name" /> <result property ="email" column ="user_email" /> </association > </resultMap > <select id ="findOrderWithUser" resultMap ="orderResultMap" > SELECT o.id as order_id, o.order_no, o.create_time, u.id as user_id, u.name as user_name, u.email as user_email FROM orders o LEFT JOIN users u ON o.user_id = u.id WHERE o.id = #{id} </select >
5.3 一对多映射 5.3.1 collection标签 一对多映射 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <resultMap id ="userWithOrdersResultMap" type ="User" > <id property ="id" column ="user_id" /> <result property ="name" column ="user_name" /> <collection property ="orders" ofType ="Order" > <id property ="id" column ="order_id" /> <result property ="orderNo" column ="order_no" /> <result property ="createTime" column ="order_create_time" /> </collection > </resultMap > <select id ="findUserWithOrders" resultMap ="userWithOrdersResultMap" > SELECT u.id as user_id, u.name as user_name, o.id as order_id, o.order_no, o.create_time as order_create_time FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.id = #{id} </select >
5.4 多对多映射 5.4.1 多对多关系 多对多映射 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <resultMap id ="userWithRolesResultMap" type ="User" > <id property ="id" column ="user_id" /> <result property ="name" column ="user_name" /> <collection property ="roles" ofType ="Role" > <id property ="id" column ="role_id" /> <result property ="name" column ="role_name" /> </collection > </resultMap > <select id ="findUserWithRoles" resultMap ="userWithRolesResultMap" > SELECT u.id as user_id, u.name as user_name, r.id as role_id, r.name as role_name FROM users u LEFT JOIN user_role ur ON u.id = ur.user_id LEFT JOIN roles r ON ur.role_id = r.id WHERE u.id = #{id} </select >
6. 缓存机制 6.1 一级缓存 6.1.1 SqlSession级别缓存 一级缓存 :
默认开启
SqlSession级别
同一个SqlSession中,相同查询只执行一次
一级缓存示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 SqlSession session = sqlSessionFactory.openSession();UserMapper mapper = session.getMapper(UserMapper.class);User user1 = mapper.findById(1L );User user2 = mapper.findById(1L );session.clearCache(); User user3 = mapper.findById(1L );session.close();
一级缓存失效情况 :
执行了增删改操作
调用了clearCache()方法
提交或回滚事务
关闭SqlSession
6.2 二级缓存 6.2.1 Mapper级别缓存 二级缓存配置 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <settings > <setting name ="cacheEnabled" value ="true" /> </settings > <mapper namespace ="com.example.mapper.UserMapper" > <cache eviction ="LRU" flushInterval ="60000" size ="512" readOnly ="true" /> <select id ="findById" resultType ="User" useCache ="true" > SELECT * FROM users WHERE id = #{id} </select > </mapper >
二级缓存特点 :
Mapper级别缓存
跨SqlSession共享
需要手动开启
缓存策略 :
LRU:最近最少使用
FIFO:先进先出
SOFT:软引用
WEAK:弱引用
6.3 自定义缓存 6.3.1 实现Cache接口 自定义缓存 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class RedisCache implements Cache { private String id; private RedisTemplate<String, Object> redisTemplate; public RedisCache (String id) { this .id = id; } @Override public String getId () { return id; } @Override public void putObject (Object key, Object value) { redisTemplate.opsForValue().set(key.toString(), value); } @Override public Object getObject (Object key) { return redisTemplate.opsForValue().get(key.toString()); } @Override public Object removeObject (Object key) { redisTemplate.delete(key.toString()); return null ; } @Override public void clear () { } @Override public int getSize () { return 0 ; } }
使用自定义缓存 :
1 <cache type ="com.example.cache.RedisCache" />
7. 插件开发 7.1 插件原理 7.1.1 拦截器机制 MyBatis插件 :基于拦截器机制,可以拦截以下方法:
Executor:执行器
ParameterHandler:参数处理器
ResultSetHandler:结果集处理器
StatementHandler:SQL语句处理器
7.2 自定义插件 7.2.1 实现Interceptor接口 自定义插件示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Intercepts({ @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}) }) public class MyPlugin implements Interceptor { @Override public Object intercept (Invocation invocation) throws Throwable { System.out.println("Before execution" ); Object result = invocation.proceed(); System.out.println("After execution" ); return result; } @Override public Object plugin (Object target) { return Plugin.wrap(target, this ); } @Override public void setProperties (Properties properties) { } }
注册插件 :
1 2 3 4 5 6 <plugins > <plugin interceptor ="com.example.plugin.MyPlugin" > <property name ="property1" value ="value1" /> </plugin > </plugins >
7.3 分页插件 7.3.1 PageHelper PageHelper使用 :
1 2 3 4 5 <dependency > <groupId > com.github.pagehelper</groupId > <artifactId > pagehelper-spring-boot-starter</artifactId > <version > 1.4.6</version > </dependency >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Service public class UserService { @Autowired private UserMapper userMapper; public PageInfo<User> findUsers (int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); List<User> users = userMapper.findAll(); return new PageInfo <>(users); } }
8. MyBatis Plus 8.1 MyBatis Plus简介 8.1.1 核心特性 MyBatis Plus :MyBatis的增强工具包,简化CRUD操作。
核心特性 :
无侵入:只做增强不做改变
损耗小:启动即会自动注入基本CRUD
强大的CRUD操作:内置通用Mapper
支持Lambda形式调用
支持主键自动生成
8.2 快速开始 8.2.1 配置和使用 Maven依赖 :
1 2 3 4 5 <dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus-boot-starter</artifactId > <version > 3.5.3</version > </dependency >
实体类 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @TableName("users") public class User { @TableId(type = IdType.AUTO) private Long id; @TableField("name") private String name; @TableField("email") private String email; }
Mapper接口 :
1 2 3 4 @Mapper public interface UserMapper extends BaseMapper <User> { }
使用示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Service public class UserService { @Autowired private UserMapper userMapper; public void test () { User user = userMapper.selectById(1L ); List<User> users = userMapper.selectList(null ); User newUser = new User (); newUser.setName("test" ); userMapper.insert(newUser); user.setName("updated" ); userMapper.updateById(user); userMapper.deleteById(1L ); QueryWrapper<User> wrapper = new QueryWrapper <>(); wrapper.eq("name" , "test" ); List<User> result = userMapper.selectList(wrapper); } }
8.3 条件构造器 8.3.1 QueryWrapper 条件构造器示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 QueryWrapper<User> wrapper = new QueryWrapper <>(); wrapper.eq("name" , "test" ) .like("email" , "@" ) .between("age" , 18 , 30 ) .orderByDesc("create_time" ); List<User> users = userMapper.selectList(wrapper); LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper <>(); lambdaWrapper.eq(User::getName, "test" ) .like(User::getEmail, "@" ); List<User> users2 = userMapper.selectList(lambdaWrapper);
9. 实战案例 9.1 复杂查询 9.1.1 多表关联查询 多表关联查询 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <resultMap id ="orderDetailResultMap" type ="OrderDetail" > <id property ="id" column ="order_id" /> <result property ="orderNo" column ="order_no" /> <association property ="user" javaType ="User" > <id property ="id" column ="user_id" /> <result property ="name" column ="user_name" /> </association > <collection property ="items" ofType ="OrderItem" > <id property ="id" column ="item_id" /> <result property ="productName" column ="product_name" /> <result property ="quantity" column ="quantity" /> </collection > </resultMap > <select id ="findOrderDetail" resultMap ="orderDetailResultMap" > SELECT o.id as order_id, o.order_no, u.id as user_id, u.name as user_name, oi.id as item_id, oi.product_name, oi.quantity FROM orders o LEFT JOIN users u ON o.user_id = u.id LEFT JOIN order_items oi ON o.id = oi.order_id WHERE o.id = #{id} </select >
9.2 批量操作 9.2.1 批量插入和更新 批量操作 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <insert id ="batchInsert" > INSERT INTO users(name, email) VALUES <foreach collection ="users" item ="user" separator ="," > (#{user.name}, #{user.email}) </foreach > </insert > <update id ="batchUpdate" > <foreach collection ="users" item ="user" separator =";" > UPDATE users SET name = #{user.name}, email = #{user.email} WHERE id = #{user.id} </foreach > </update >
10. 总结 10.1 核心要点
SQL映射 :灵活编写SQL,精确控制
动态SQL :根据条件动态构建SQL
结果映射 :灵活映射查询结果
缓存机制 :提高查询性能
插件机制 :扩展MyBatis功能
10.2 关键理解
灵活性强 :可以编写原生SQL
性能优异 :SQL可控,易于优化
易于扩展 :插件机制支持扩展
10.3 最佳实践
合理使用动态SQL :避免SQL注入
优化结果映射 :减少N+1查询
合理使用缓存 :提高查询性能
使用MyBatis Plus :简化CRUD操作
相关文章 :