Mybatis学习笔记
1. 什么是 MyBatis?
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原生类型、接口和 Java POJO(Plain Old Java Objects)为数据库中的记录。
主要特点:
- SQL 与代码分离:将 SQL 语句放在 XML 文件或注解中,避免硬编码。
- 灵活的映射机制:支持复杂的关联查询和结果映射。
- 轻量级:相比 Hibernate 等全功能 ORM 框架,MyBatis 更轻量、灵活。
- 支持存储过程:可以方便地调用数据库存储过程。
2. 核心概念
2.1 核心组件
- SqlSessionFactory:创建 SqlSession 的工厂类,是 MyBatis 的核心配置对象。
- SqlSession:提供执行 SQL 方法的会话对象,类似于 JDBC 中的 Connection。
- Mapper 接口:定义数据库操作方法的接口,由 MyBatis 自动生成实现类。
- 映射文件(XML)或注解:定义 SQL 语句和映射规则。
2.2 工作流程
- 读取 MyBatis 配置文件(
mybatis-config.xml)和映射文件。 - 创建 SqlSessionFactory 实例。
- 通过 SqlSessionFactory 获取 SqlSession。
- 使用 SqlSession 执行 SQL 操作。
- 关闭 SqlSession。
3. 环境搭建
3.1 添加依赖(Maven)
xml
<!-- MyBatis 核心 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- 数据库驱动(以 MySQL 为例) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<!-- 日志(可选,方便调试) -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
3.2 创建 MyBatis 配置文件 mybatis-config.xml
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>
<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?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</dataSource>
</environment>
</environments>
<!-- 映射文件位置 -->
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
</configuration>
3.3 创建实体类
java
public class User {
private Long id;
private String username;
private String email;
private Integer age;
// 构造方法、Getter 和 Setter 略
}
4. 使用 XML 映射文件
4.1 创建 Mapper 接口
java
public interface UserMapper {
User selectById(Long id);
List<User> selectAll();
int insert(User user);
int update(User user);
int deleteById(Long id);
}
4.2 创建映射文件 UserMapper.xml
xml
<?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="BaseResultMap" type="com.example.entity.User">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="email" property="email" jdbcType="VARCHAR"/>
<result column="age" property="age" jdbcType="INTEGER"/>
</resultMap>
<!-- 查询单个用户 -->
<select id="selectById" parameterType="java.lang.Long" resultMap="BaseResultMap">
SELECT * FROM user WHERE id = #{id}
</select>
<!-- 查询所有用户 -->
<select id="selectAll" resultMap="BaseResultMap">
SELECT * FROM user
</select>
<!-- 插入用户 -->
<insert id="insert" parameterType="com.example.entity.User">
INSERT INTO user (username, email, age)
VALUES (#{username}, #{email}, #{age})
</insert>
<!-- 更新用户 -->
<update id="update" parameterType="com.example.entity.User">
UPDATE user
SET username = #{username},
email = #{email},
age = #{age}
WHERE id = #{id}
</update>
<!-- 删除用户 -->
<delete id="deleteById" parameterType="java.lang.Long">
DELETE FROM user WHERE id = #{id}
</delete>
</mapper>
5. 使用注解方式
5.1 简单 SQL 注解
java
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User selectById(Long id);
@Select("SELECT * FROM user")
List<User> selectAll();
@Insert("INSERT INTO user (username, email, age) VALUES (#{username}, #{email}, #{age})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insert(User user);
@Update("UPDATE user SET username=#{username}, email=#{email}, age=#{age} WHERE id=#{id}")
int update(User user);
@Delete("DELETE FROM user WHERE id = #{id}")
int deleteById(Long id);
}
5.2 复杂映射注解
java
public interface UserMapper {
@Results({
@Result(property = "id", column = "id", id = true),
@Result(property = "username", column = "username"),
@Result(property = "email", column = "email"),
@Result(property = "age", column = "age")
})
@Select("SELECT * FROM user WHERE id = #{id}")
User selectById(Long id);
}
6. 使用 MyBatis
6.1 创建 SqlSessionFactory
java
public class MyBatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
}
6.2 执行数据库操作
java
public class UserService {
public User getUserById(Long id) {
try (SqlSession session = MyBatisUtil.getSqlSessionFactory().openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
return mapper.selectById(id);
}
}
public List<User> getAllUsers() {
try (SqlSession session = MyBatisUtil.getSqlSessionFactory().openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
return mapper.selectAll();
}
}
public void addUser(User user) {
try (SqlSession session = MyBatisUtil.getSqlSessionFactory().openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
mapper.insert(user);
session.commit(); // 提交事务
}
}
public void updateUser(User user) {
try (SqlSession session = MyBatisUtil.getSqlSessionFactory().openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
mapper.update(user);
session.commit();
}
}
public void deleteUser(Long id) {
try (SqlSession session = MyBatisUtil.getSqlSessionFactory().openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
mapper.deleteById(id);
session.commit();
}
}
}
7. 高级特性
7.1 动态 SQL
MyBatis 提供了强大的动态 SQL 功能,可以根据条件动态生成 SQL 语句。
xml
<select id="findUsers" parameterType="map" resultType="User">
SELECT * 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>
7.2 关联查询
处理一对多、多对一关系。
xml
<resultMap id="UserWithOrdersMap" 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_number" property="orderNumber"/>
</collection>
</resultMap>
<select id="getUserWithOrders" resultMap="UserWithOrdersMap">
SELECT
u.id AS user_id,
u.username,
o.id AS order_id,
o.order_number
FROM user u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.id = #{id}
</select>
7.3 分页查询
java
// 使用 RowBounds 进行分页(简单但性能较低)
List<User> selectAll(RowBounds rowBounds);
// 调用时
RowBounds rowBounds = new RowBounds(10, 20); // 从第10条开始,取20条
List<User> users = mapper.selectAll(rowBounds);
7.4 插件机制
自定义插件实现分页、性能监控等功能。
java
@Intercepts({
@Signature(type = Executor.class, method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class PageInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 分页逻辑
return invocation.proceed();
}
}
8. 事务管理
8.1 自动提交事务
java
try (SqlSession session = sqlSessionFactory.openSession(true)) {
// 自动提交事务
UserMapper mapper = session.getMapper(UserMapper.class);
// 执行数据库操作
}
8.2 手动提交事务
java
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
// 执行多个数据库操作
session.commit(); // 提交事务
} catch (Exception e) {
session.rollback(); // 回滚事务
throw e;
} finally {
session.close();
}
9. 与 Spring 集成
9.1 添加依赖
xml
<dependency>
<groupId>org.mybatis.spring</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
9.2 配置 Spring 和 MyBatis
java
@Configuration
@MapperScan("com.example.mapper") // 扫描 Mapper 接口
public class MyBatisConfig {
@Bean
public DataSource dataSource() {
// 配置数据源
return new DriverManagerDataSource("jdbc:mysql://localhost:3306/test", "root", "password");
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mappers/*.xml"));
return factoryBean.getObject();
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
10. 什么是 ResultMap?
ResultMap 是 MyBatis 中最强大的特性之一,用于解决数据库表结构与 Java 对象结构之间的不匹配问题。例如:
- 数据库列名与 Java 属性名不一致(如
user_name→username)。 - 复杂的关联查询(如一对一、一对多关系)。
- 自定义类型转换(如将数据库的
INT转为 Java 的Boolean)。
1. 代码逐行解析
xml
<resultMap id="BaseResultMap" type="com.example.entity.User">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="email" property="email" jdbcType="VARCHAR"/>
<result column="age" property="age" jdbcType="INTEGER"/>
</resultMap>
1.1 根标签 <resultMap>
id:结果映射的唯一标识符,用于在 SQL 语句中引用(如<select resultMap="BaseResultMap">)。type:映射的目标 Java 类的全限定名(这里是User类)。
1.2 子标签 <id> 和 <result>
-
共同点:
column:数据库表的列名。property:Java 对象的属性名(通过 getter/setter 访问)。jdbcType:列的 JDBC 类型(如BIGINT、VARCHAR),用于处理空值等情况。
-
区别:
<id>:表示主键列,有助于提高 MyBatis 的缓存效率。<result>:表示普通列。
2. 映射原理示例
假设执行 SQL:
sql
SELECT id, username, email, age FROM user WHERE id = 1;
MyBatis 会根据 BaseResultMap 将结果映射为 User 对象:
| 数据库列 | Java 属性 | 映射后效果 |
|---|---|---|
id |
id |
user.setId(rs.getLong("id")) |
username |
username |
user.setUsername(rs.getString("username")) |
email |
email |
user.setEmail(rs.getString("email")) |
age |
age |
user.setAge(rs.getInt("age")) |
3. 为什么需要 ResultMap?
场景 1:列名与属性名不一致
若数据库列名为 user_name,而 Java 属性为 username,需显式映射:
xml
<result column="user_name" property="username"/>
场景 2:复杂关联查询
例如,查询 User 及其关联的 Order 列表:
xml
<resultMap id="UserWithOrders" 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_number" property="orderNumber"/>
</collection>
</resultMap>
4. 简化写法:自动映射
如果数据库列名与 Java 属性名完全一致(如 id → id),MyBatis 支持自动映射,无需编写 resultMap:
xml
<select id="selectById" resultType="com.example.entity.User">
SELECT * FROM user WHERE id = #{id}
</select>
但建议复杂场景下仍使用 resultMap 以提高可读性和灵活性。
11.数据库操作映射
MyBatis 中使用 XML 配置文件定义的 数据库操作映射,包含了增删改查(CRUD)的基本操作。下面我会逐行解释每个 SQL 映射的含义和工作原理。
1. 查询单个用户
xml
<select id="selectById" parameterType="java.lang.Long" resultMap="BaseResultMap">
SELECT * FROM user WHERE id = #{id}
</select>
关键属性:
id:映射的唯一标识符,对应 Mapper 接口中的方法名(如User selectById(Long id))。parameterType:输入参数的类型(这里是Long)。resultMap:指定结果集的映射规则(引用之前定义的BaseResultMap)。
执行流程:
- Mapper 接口调用
selectById(1L)。 - MyBatis 解析 SQL:
SELECT * FROM user WHERE id = ?,并将参数1L绑定到占位符?。 - 执行 SQL,返回结果集。
- 根据
BaseResultMap将结果集映射为User对象。
2. 查询所有用户
xml
<select id="selectAll" resultMap="BaseResultMap">
SELECT * FROM user
</select>
特点:
- 无
parameterType:因为不需要输入参数。 - 返回列表:对应 Mapper 接口中的
List<User> selectAll()。
执行流程:
- 执行
SELECT * FROM user。 - 将每行结果映射为
User对象。 - 返回
User列表。
3. 插入用户
xml
<insert id="insert" parameterType="com.example.entity.User">
INSERT INTO user (username, email, age)
VALUES (#{username}, #{email}, #{age})
</insert>
参数处理:
#{username}:从User对象中获取username属性(通过user.getUsername())。- 自动类型转换:MyBatis 会根据属性类型(如
String、Integer)自动设置 JDBC 参数。
执行流程:
- 传入
User对象(如new User("Alice", "alice@example.com", 25))。 - 解析 SQL:
INSERT INTO user (username, email, age) VALUES (?, ?, ?)。 - 绑定参数:
? = "Alice", "alice@example.com", 25。 - 执行插入,返回受影响的行数(
int)。
4. 更新用户
xml
<update id="update" parameterType="com.example.entity.User">
UPDATE user
SET username = #{username},
email = #{email},
age = #{age}
WHERE id = #{id}
</update>
关键逻辑:
- 动态参数:从
User对象中提取属性值。 - 主键条件:通过
id定位要更新的记录。
执行流程:
- 传入已修改的
User对象(如id=1,username="Bob")。 - 生成 SQL:
UPDATE user SET username=?, email=?, age=? WHERE id=?。 - 执行更新,返回成功更新的行数。
5. 删除用户
xml
<delete id="deleteById" parameterType="java.lang.Long">
DELETE FROM user WHERE id = #{id}
</delete>
执行流程:
- 传入
id(如1L)。 - 生成 SQL:
DELETE FROM user WHERE id = ?。 - 执行删除,返回受影响的行数。
6. 关键语法解析
#{} 与 ${} 的区别:
#{}(推荐):- 预编译处理:SQL 会被编译为
SELECT * FROM user WHERE id = ?,防止 SQL 注入。 - 类型安全:自动处理类型转换(如
Long→BIGINT)。
- 预编译处理:SQL 会被编译为
${}(慎用):- 直接替换:SQL 会被替换为
SELECT * FROM user WHERE id = 1,存在 SQL 注入风险。 - 适用场景:动态表名、列名(如
${tableName})。
- 直接替换:SQL 会被替换为
参数传递方式:
- 单个参数:直接使用
#{paramName},如#{id}。 - 多个参数:
- 使用
@Param注解(接口方法中):java
User selectUser(@Param("id") Long id, @Param("name") String name);xml
WHERE id = #{id} AND username = #{name} - 使用对象(如
User):通过属性名访问(如#{username})。
- 使用
mybatis-spring-boot-starter
mybatis-spring-boot-starter 是 MyBatis 和 Spring Boot 的集成模块,它提供了自动配置功能,使得在 Spring Boot 项目中使用 MyBatis 更加方便。这个依赖会自动配置 MyBatis 的相关组件,包括 SqlSessionFactory、SqlSessionTemplate 等,并且会自动扫描指定包下的 Mapper 接口。
特点
-
自动配置:提供了自动配置功能,减少了手动配置的工作量。
-
集成 Spring Boot:与 Spring Boot 的自动配置机制无缝集成。
-
简化开发:提供了
@MapperScan注解,方便扫描 Mapper 接口。 -
依赖管理:管理了 MyBatis 和 Spring 相关的依赖,确保版本兼容。
更多推荐

所有评论(0)