一、MyBatis核心架构解析
1. 什么是MyBatis?
MyBatis是一款半自动ORM框架,它通过XML或注解将SQL与Java对象映射,提供比Hibernate更灵活的SQL控制能力,同时消除了传统JDBC的样板代码。
2. 核心组件关系图
3. 核心组件职责
组件 | 职责 | 生命周期 |
---|---|---|
SqlSessionFactory | 创建SqlSession | 应用级单例 |
SqlSession | 执行SQL操作 | 请求/方法级 |
Mapper接口 | 定义数据库操作 | 应用级 |
SQL映射文件 | 配置SQL语句 | 应用级 |
二、环境搭建与配置
1. Maven依赖
<dependencies><!-- MyBatis核心 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.13</version></dependency><!-- 数据库驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><!-- 连接池 --><dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><version>5.0.1</version></dependency>
</dependencies>
2. 核心配置文件(mybatis-config.xml)
<?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><settings><!-- 开启驼峰命名转换 --><setting name="mapUnderscoreToCamelCase" value="true"/><!-- 开启二级缓存 --><setting name="cacheEnabled" value="true"/></settings><typeAliases><package name="com.example.model"/></typeAliases><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/mydb?useSSL=false"/><property name="username" value="root"/><property name="password" value="password"/><!-- HikariCP连接池配置 --><property name="maximumPoolSize" value="20"/><property name="connectionTimeout" value="30000"/></dataSource></environment></environments><mappers><mapper resource="mapper/UserMapper.xml"/></mappers>
</configuration>
三、CRUD操作详解
1. 实体类定义
public class User {private Long id;private String username;private String email;private LocalDateTime createTime;// 构造器、getter/setter省略
}
2. Mapper接口
public interface UserMapper {// 插入操作返回自增主键@Options(useGeneratedKeys = true, keyProperty = "id")int insertUser(User user);int updateUser(User user);int deleteUser(Long id);User selectUserById(Long id);List<User> selectAllUsers();
}
3. XML映射文件(UserMapper.xml)
<mapper namespace="com.example.mapper.UserMapper"><!-- 基础结果映射 --><resultMap id="userResultMap" type="User"><id property="id" column="id"/><result property="username" column="username"/><result property="email" column="email"/><result property="createTime" column="create_time"/></resultMap><!-- 插入用户 --><insert id="insertUser" parameterType="User">INSERT INTO users(username, email, create_time)VALUES(#{username}, #{email}, #{createTime})</insert><!-- 更新用户 --><update id="updateUser" parameterType="User">UPDATE users SETusername = #{username},email = #{email}WHERE id = #{id}</update><!-- 查询用户 --><select id="selectUserById" resultMap="userResultMap">SELECT * FROM users WHERE id = #{id}</select><!-- 分页查询 --><select id="selectAllUsers" resultMap="userResultMap">SELECT * FROM users LIMIT #{offset}, #{pageSize}</select>
</mapper>
四、参数处理与动态SQL
<select id="selectUsersByCondition" resultMap="userResultMap">SELECT * FROM usersWHERE 1=1<if test="username != null and username != ''">AND username LIKE CONCAT('%', #{username}, '%')</if><if test="email != null">AND email = #{email}</if><if test="startTime != null">AND create_time >= #{startTime}</if>
</select>
1. 多参数处理
// Mapper接口方法
List<User> selectUsersByCondition(@Param("username") String username,@Param("email") String email,@Param("startTime") LocalDateTime startTime);
<select id="selectUsersByCondition" resultMap="userResultMap">SELECT * FROM usersWHERE 1=1<if test="username != null and username != ''">AND username LIKE CONCAT('%', #{username}, '%')</if><if test="email != null">AND email = #{email}</if><if test="startTime != null">AND create_time >= #{startTime}</if>
</select>
2. 复杂动态SQL
<!-- 批量插入 -->
<insert id="batchInsertUsers" parameterType="list">INSERT INTO users(username, email) VALUES<foreach item="user" collection="list" separator=",">(#{user.username}, #{user.email})</foreach>
</insert><!-- 动态更新 -->
<update id="updateUserSelective" parameterType="User">UPDATE users<set><if test="username != null">username=#{username},</if><if test="email != null">email=#{email},</if></set>WHERE id=#{id}
</update><!-- 多条件选择 -->
<select id="findActiveUsers" resultMap="userResultMap">SELECT * FROM users<where><choose><when test="status == 'active'">AND status = 1</when><when test="status == 'inactive'">AND status = 0</when><otherwise>AND status IS NOT NULL</otherwise></choose></where>
</select>
五、高级结果映射
1. 一对一关联
public class Order {private Long id;private String orderNo;private User user; // 一对一关联
}
<resultMap id="orderResultMap" type="Order"><id property="id" column="id"/><result property="orderNo" column="order_no"/><!-- 一对一关联映射 --><association property="user" javaType="User"><id property="id" column="user_id"/><result property="username" column="username"/><result property="email" column="email"/></association>
</resultMap><select id="selectOrderWithUser" resultMap="orderResultMap">SELECT o.*, u.username, u.emailFROM orders oJOIN users u ON o.user_id = u.idWHERE o.id = #{id}
</select>
2. 一对多关联
public class Department {private Long id;private String name;private List<Employee> employees; // 一对多关联
}
<resultMap id="deptResultMap" type="Department"><id property="id" column="id"/><result property="name" column="name"/><!-- 一对多集合映射 --><collection property="employees" ofType="Employee"><id property="id" column="emp_id"/><result property="name" column="emp_name"/><result property="position" column="position"/></collection>
</resultMap><select id="selectDepartmentWithEmployees" resultMap="deptResultMap">SELECT d.*, e.id AS emp_id, e.name AS emp_name, e.positionFROM departments dLEFT JOIN employees e ON d.id = e.dept_idWHERE d.id = #{id}
</select>
六、缓存机制深度优化
1. 缓存层次结构
2. 缓存配置策略
<!-- 在Mapper.xml中配置二级缓存 -->
<cacheeviction="FIFO" <!-- 回收策略:FIFO/LRU/SOFT/WEAK -->flushInterval="60000" <!-- 刷新间隔(毫秒) -->size="512" <!-- 缓存对象数量 -->readOnly="true"/> <!-- 是否只读 --><!-- 使用自定义缓存实现 -->
<cache type="com.example.cache.RedisCache"/>
3. 缓存使用注意事项
// 手动清除缓存
sqlSession.clearCache(); // 清除一级缓存// 在Statement中控制缓存
<select id="selectUsers" useCache="false" flushCache="true">SELECT * FROM users
</select>
七、Spring Boot整合实践
1. 快速整合配置
# application.yml
mybatis:mapper-locations: classpath:mapper/**/*.xmltype-aliases-package: com.example.modelconfiguration:map-underscore-to-camel-case: truecache-enabled: truelazy-loading-enabled: true
2. 自动注入Mapper
@Mapper
public interface UserMapper {// 方法定义
}// 在Service中使用
@Service
public class UserService {private final UserMapper userMapper;public UserService(UserMapper userMapper) {this.userMapper = userMapper;}public User getUserById(Long id) {return userMapper.selectUserById(id);}
}
3. 分页插件集成
// 配置分页插件
@Configuration
public class MyBatisConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor());return interceptor;}
}// 使用分页
public Page<User> getUsersByPage(int pageNum, int pageSize) {Page<User> page = new Page<>(pageNum, pageSize);return userMapper.selectPage(page, null);
}
八、性能优化与最佳实践
1. SQL优化技巧
/* 避免SELECT * */
SELECT id, username, email FROM users/* 使用覆盖索引 */
CREATE INDEX idx_username ON users(username);/* 批量操作替代循环 */
<foreach item="item" collection="list" separator=",">(#{item.value})
</foreach>
2. 事务管理
@Transactional
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {// 减少转出账户余额userMapper.deductBalance(fromId, amount);// 增加转入账户余额userMapper.addBalance(toId, amount);// 记录交易日志logMapper.insertTransferLog(fromId, toId, amount);
}
3. 监控与诊断
# 开启SQL日志
logging:level:com.example.mapper: debug
-- 使用EXPLAIN分析查询
EXPLAIN SELECT * FROM users WHERE username = 'john';
九、高级特性应用
1. 存储过程调用
<select id="callUserProcedure" statementType="CALLABLE">{call get_user_by_id(#{id, mode=IN}, #{username, mode=OUT, jdbcType=VARCHAR})}
</select>
2. 类型处理器
// 自定义枚举处理器
public class StatusTypeHandler extends BaseTypeHandler<Status> {@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, Status parameter, JdbcType jdbcType) {ps.setInt(i, parameter.getCode());}// 其他方法实现...
}// 注册处理器
<typeHandlers><typeHandler handler="com.example.handler.StatusTypeHandler"/>
</typeHandlers>
3. 插件开发(拦截器)
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class SqlCostInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {long start = System.currentTimeMillis();Object result = invocation.proceed();long end = System.currentTimeMillis();System.out.println("SQL执行耗时: " + (end - start) + "ms");return result;}
}// 注册插件
<plugins><plugin interceptor="com.example.plugin.SqlCostInterceptor"/>
</plugins>
十、实战案例:电商订单系统
1. 复杂查询示例
<select id="selectOrderDetails" resultMap="orderDetailMap">SELECT o.id, o.order_no, o.total_amount,u.id AS user_id, u.username, u.email,p.id AS product_id, p.name AS product_name, p.price,oi.quantityFROM orders oJOIN users u ON o.user_id = u.idJOIN order_items oi ON o.id = oi.order_idJOIN products p ON oi.product_id = p.idWHERE o.status = 'COMPLETED'<if test="startDate != null">AND o.create_time >= #{startDate}</if><if test="minAmount != null">AND o.total_amount >= #{minAmount}</if>ORDER BY o.create_time DESC
</select>
2. 事务边界设计
@Service
public class OrderService {private final OrderMapper orderMapper;private final InventoryService inventoryService;private final PaymentService paymentService;@Transactional(rollbackFor = Exception.class)public void placeOrder(Order order) {// 1. 创建订单orderMapper.insertOrder(order);// 2. 扣减库存inventoryService.deductStock(order.getItems());// 3. 支付处理paymentService.processPayment(order);// 4. 更新订单状态orderMapper.updateOrderStatus(order.getId(), "PAID");}
}
结语:MyBatis在企业级应用中的定位
MyBatis作为持久层框架的选择标准:
-
适用场景:
-
需要精细控制SQL的场景
-
复杂报表查询
-
遗留数据库系统改造
-
-
性能考量:
-
与Hibernate相比,在复杂查询上通常有更好表现
-
对数据库特性利用更充分
-
-
学习建议:
-
掌握动态SQL编写技巧
-
深入理解结果集映射机制
-
合理应用缓存策略
-
结合Spring事务管理
-
"不要试图用ORM解决所有问题,MyBatis的价值在于平衡SQL控制力和开发效率"
—— MyBatis创始人 Clinton Begin