MyBatis 全面解析
MyBatis 是一款优秀的持久层框架,它消除了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的操作,支持定制化 SQL、存储过程以及高级映射,通过 XML 或注解的方式将 SQL 语句与 Java 代码解耦,是 Java 生态中主流的 ORM(对象关系映射)框架之一。
一、核心优势
- 灵活可控:相比 Hibernate 等全自动 ORM 框架,MyBatis 不强制封装 SQL,允许开发者手写 SQL,适配复杂业务场景(如多表联查、复杂条件筛选)。
- 低侵入性:基于接口编程,无需继承/实现特定类,与业务代码解耦。
- 简化 JDBC 操作:自动处理连接、参数绑定、结果集映射,减少重复的 try-catch 代码。
- 动态 SQL:支持
<if>、<where>、<foreach>等标签,灵活拼接 SQL,避免硬编码。 - 缓存机制:内置一级缓存(SqlSession 级别)和二级缓存(Mapper 级别),提升查询性能。
二、核心组件
1. 核心接口/类
| 组件 | 作用 |
|---|---|
SqlSessionFactory | 会话工厂,创建 SqlSession 的核心类(单例,通过配置初始化) |
SqlSession | 会话对象,用于执行 SQL、获取 Mapper 接口、管理事务(线程不安全) |
Mapper 接口 | 自定义接口,方法与 XML/注解中的 SQL 绑定(MyBatis 动态生成实现类) |
Configuration | 全局配置类,存储 MyBatis 所有配置信息(数据源、映射规则、插件等) |
Executor | 执行器,SqlSession 的底层执行器,处理 SQL 执行逻辑(默认 SimpleExecutor) |
2. 核心配置文件(mybatis-config.xml)
全局配置文件,定义 MyBatis 的核心规则,示例:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 环境配置:数据源、事务管理器 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/> <!-- 事务管理:JDBC/MANAGED -->
<dataSource type="POOLED"> <!-- 数据源:POOLED/UNPOOLED/JNDI -->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 映射器:指定 Mapper XML/接口位置 -->
<mappers>
<mapper resource="com/example/mapper/UserMapper.xml"/>
<!-- 或注解方式:<mapper class="com.example.mapper.UserMapper"/> -->
</mappers>
</configuration>三、基本使用步骤
步骤 1:引入依赖(Maven)
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.16</version> <!-- 最新稳定版 -->
</dependency>
<!-- MySQL 驱动(按需替换) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
<scope>runtime</scope>
</dependency>步骤 2:定义实体类
public class User {
private Long id;
private String username;
private Integer age;
// getter/setter/toString
}步骤 3:定义 Mapper 接口
public interface UserMapper {
// 根据ID查询用户
User selectById(Long id);
// 新增用户
int insert(User user);
// 更新用户
int update(User user);
// 删除用户
int delete(Long id);
}步骤 4:编写 Mapper XML 文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 绑定对应的 Mapper 接口 -->
<mapper namespace="com.example.mapper.UserMapper">
<!-- 结果集映射:字段名 -> 实体类属性名(字段与属性不一致时需配置) -->
<resultMap id="UserResultMap" type="com.example.entity.User">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="age" property="age"/>
</resultMap>
<!-- 查询:id 对应接口方法名 -->
<select id="selectById" resultMap="UserResultMap">
SELECT id, username, age FROM user WHERE id = #{id}
</select>
<!-- 新增 -->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (username, age) VALUES (#{username}, #{age})
</insert>
<!-- 更新 -->
<update id="update">
UPDATE user
SET username = #{username}, age = #{age}
WHERE id = #{id}
</update>
<!-- 删除 -->
<delete id="delete">
DELETE FROM user WHERE id = #{id}
</delete>
</mapper>步骤 5:获取 SqlSession 并执行操作
public class MyBatisDemo {
public static void main(String[] args) throws IOException {
// 1. 加载核心配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2. 创建 SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 3. 打开 SqlSession(true 表示自动提交事务)
try (SqlSession session = sqlSessionFactory.openSession(true)) {
// 4. 获取 Mapper 代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
// 5. 执行 CRUD
User user = userMapper.selectById(1L);
System.out.println(user);
// 新增示例
User newUser = new User();
newUser.setUsername("test");
newUser.setAge(20);
userMapper.insert(newUser);
}
}
}四、核心特性详解
1. 动态 SQL
通过标签动态拼接 SQL,解决硬编码问题,示例:
<select id="selectByCondition" resultMap="UserResultMap">
SELECT id, username, age FROM user
<where>
<if test="username != null and username != ''">
AND username LIKE CONCAT('%', #{username}, '%')
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>常用动态标签:<if>、<where>、<set>、<foreach>、<choose/when/otherwise>。
2. 参数传递
- 单个参数:直接用
#{参数名}(MyBatis 自动识别,参数名可任意)。 多个参数:
方式 1:使用
@Param注解命名参数User selectByUsernameAndAge(@Param("username") String username, @Param("age") Integer age);- 方式 2:封装为实体类/Map。
集合参数:通过
<foreach>遍历<select id="selectByIds" resultMap="UserResultMap"> SELECT id, username, age FROM user WHERE id IN <foreach collection="ids" item="id" open="(" separator="," close=")"> #{id} </foreach> </select>
3. 结果映射
- 简单映射:字段名与属性名一致时,直接用
resultType。 复杂映射:
- 一对一:
<association>(如用户关联订单)。 一对多:
<collection>(如用户关联多个订单)。
示例(一对多):<resultMap id="UserWithOrdersResultMap" type="User"> <id column="user_id" property="id"/> <result column="username" property="username"/> <collection property="orders" ofType="Order"> <id column="order_id" property="id"/> <result column="order_name" property="name"/> </collection> </resultMap>
- 一对一:
4. 缓存
- 一级缓存:默认开启,SqlSession 级别,同一 SqlSession 内多次查询相同 SQL 会缓存结果,关闭/提交 SqlSession 后失效。
二级缓存:Mapper 级别,需手动开启:
- 全局配置:
<setting name="cacheEnabled" value="true"/>。 - Mapper XML 中添加
<cache/>。 - 实体类实现
Serializable。
- 全局配置:
5. 注解开发
简单 SQL 可直接用注解替代 XML,示例:
public interface UserMapper {
@Select("SELECT id, username, age FROM user WHERE id = #{id}")
User selectById(Long id);
@Insert("INSERT INTO user (username, age) VALUES (#{username}, #{age})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insert(User user);
}注意:复杂 SQL(如动态 SQL、多表联查)建议用 XML 方式,更易维护。
五、MyBatis 进阶
1. 插件(Interceptor)
可拦截 MyBatis 核心方法(如执行器、参数处理器),实现分页、日志、权限控制等,示例(分页插件 PageHelper):
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<property name="helperDialect" value="mysql"/>
</plugin>
</plugins>2. 集成 Spring/Spring Boot
实际开发中,MyBatis 通常与 Spring/Spring Boot 集成,核心依赖:
<!-- Spring Boot 整合 MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>通过 application.yml 配置替代 XML,简化开发:
mybatis:
mapper-locations: classpath:mapper/*.xml # Mapper XML 位置
type-aliases-package: com.example.entity # 实体类别名包
configuration:
map-underscore-to-camel-case: true # 自动下划线转驼峰
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useSSL=false
username: root
password: 1234563. 分页查询
除了 PageHelper,也可手动实现分页:
<select id="selectPage" resultMap="UserResultMap">
SELECT id, username, age FROM user
LIMIT #{offset}, #{size}
</select>六、常见问题与最佳实践
- SQL 注入风险:使用
#{}(预编译)而非${}(字符串拼接),${}仅用于表名/列名等动态场景。 性能优化:
- 关闭不必要的二级缓存。
- 合理使用
fetchSize、timeout配置。 - 避免 N+1 查询(用
<association>/<collection>关联查询)。
- 字段与属性映射:开启
map-underscore-to-camel-case自动下划线转驼峰,减少手动映射。 - 事务管理:Spring 环境下使用
@Transactional注解管理事务,避免手动提交。
七、总结
MyBatis 以“灵活”为核心,兼顾 SQL 可控性和开发效率,是中大型 Java 项目中持久层的首选框架之一。掌握其核心配置、动态 SQL、结果映射等特性,结合 Spring Boot 集成,可高效实现数据库操作。
评论0
暂时没有评论