MyBatis 入门完整指南
概述
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO 为数据库中的记录。
💡 核心优势:
- 灵活性高:完全控制 SQL 语句,便于优化
- 学习成本低:SQL 与 Java 代码分离,易于理解
- 映射灵活:支持复杂的结果集映射
- 缓存机制:一级缓存和二级缓存提升性能
MyBatis 简介
1. 框架定位
在典型的 SSM(Spring + SpringMVC + MyBatis)架构中:
- Spring:负责业务层逻辑和依赖注入
- SpringMVC:负责表现层,处理 HTTP 请求
- MyBatis:负责持久层,处理数据库操作
2. ORM 概念
ORM(Object Relational Mapping):对象关系映射,是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
| 数据库概念 | Java 概念 | MyBatis 映射 |
|---|---|---|
| 表(Table) | 类(Class) | <resultMap> |
| 行(Row) | 对象(Object) | 实例 |
| 列(Column) | 属性(Field) | <result> |
3. 相关概念
- POJO(Plain Old Java Object):普通的 Java 对象,没有任何限制
- PO(Persistent Object):持久化对象,对应数据库中的记录
- VO(Value Object):值对象,用于业务层之间的数据传输
- DTO(Data Transfer Object):数据传输对象,用于层间数据传输
环境搭建
1. 数据库准备
-- 创建数据库
CREATE DATABASE mybatis_demo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE mybatis_demo;
-- 创建客户表
CREATE TABLE customer (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL COMMENT '客户名称',
jobs VARCHAR(50) COMMENT '职业',
phone VARCHAR(20) COMMENT '电话',
created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户信息表';
-- 插入测试数据
INSERT INTO customer (username, jobs, phone) VALUES
('张三', '软件工程师', '13800138001'),
('李四', '产品经理', '13800138002'),
('王五', 'UI设计师', '13800138003'),
('赵六', '测试工程师', '13800138004');
2. Maven 依赖配置
<dependencies>
<!-- MyBatis 核心 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- 日志实现 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- Lombok(可选) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
<scope>provided</scope>
</dependency>
</dependencies>
3. 项目结构
mybatis-demo/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/
│ │ │ ├── entity/ # 实体类
│ │ │ ├── mapper/ # Mapper接口
│ │ │ └── utils/ # 工具类
│ │ └── resources/
│ │ ├── mapper/ # Mapper XML文件
│ │ ├── mybatis-config.xml # MyBatis核心配置
│ │ ├── db.properties # 数据库配置
│ │ └── log4j.properties # 日志配置
│ └── test/
└── pom.xml
核心组件
1. SqlSessionFactory
SqlSessionFactory 是 MyBatis 的核心对象,用于创建 SqlSession。
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}
2. SqlSession
SqlSession 代表和数据库的一次会话,用于执行 SQL 命令。
| 方法 | 说明 | 使用场景 |
|---|---|---|
| selectOne() | 查询单条记录 | 根据 ID 查询 |
| selectList() | 查询多条记录 | 列表查询 |
| insert() | 插入记录 | 新增数据 |
| update() | 更新记录 | 修改数据 |
| delete() | 删除记录 | 删除数据 |
| commit() | 提交事务 | 确认更改 |
| rollback() | 回滚事务 | 撤销更改 |
3. Mapper
Mapper 是 MyBatis 的映射器,负责 SQL 语句与 Java 方法的映射。
入门示例
基于 MyBatis 的客户管理系统
1. 实体类定义
package com.example.entity;
import lombok.Data;
import java.util.Date;
@Data
public class Customer {
private Integer id; // 客户ID
private String username; // 客户名称
private String jobs; // 职业
private String phone; // 电话
private Date createdTime; // 创建时间
private Date updatedTime; // 更新时间
}
2. Mapper 接口
package com.example.mapper;
import com.example.entity.Customer;
import java.util.List;
public interface CustomerMapper {
// 1. 根据id查询客户
Customer findCustomerById(Integer id);
// 2. 根据姓名模糊查询
List<Customer> findCustomerByName(String username);
// 3. 添加客户
int addCustomer(Customer customer);
// 4. 更新客户
int updateCustomer(Customer customer);
// 5. 删除客户
int deleteCustomer(Integer id);
// 6. 查询所有客户
List<Customer> findAllCustomers();
// 7. 分页查询
List<Customer> findCustomersByPage(Map<String, Object> params);
// 8. 统计客户数量
Long countCustomers();
}
3. Mapper 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.CustomerMapper">
<!-- 结果映射配置 -->
<resultMap id="customerMap" type="com.example.entity.Customer">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="jobs" column="jobs"/>
<result property="phone" column="phone"/>
<result property="createdTime" column="created_time"/>
<result property="updatedTime" column="updated_time"/>
</resultMap>
<!-- 1. 根据id查询客户 -->
<select id="findCustomerById" parameterType="Integer"
resultMap="customerMap">
SELECT * FROM customer WHERE id = #{id}
</select>
<!-- 2. 根据姓名模糊查询 -->
<select id="findCustomerByName" parameterType="String"
resultMap="customerMap">
SELECT * FROM customer
WHERE username LIKE CONCAT('%', #{username}, '%')
</select>
<!-- 3. 添加客户 -->
<insert id="addCustomer" parameterType="com.example.entity.Customer"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO customer (username, jobs, phone)
VALUES (#{username}, #{jobs}, #{phone})
</insert>
<!-- 4. 更新客户 -->
<update id="updateCustomer" parameterType="com.example.entity.Customer">
UPDATE customer
SET username = #{username},
jobs = #{jobs},
phone = #{phone},
updated_time = NOW()
WHERE id = #{id}
</update>
<!-- 5. 删除客户 -->
<delete id="deleteCustomer" parameterType="Integer">
DELETE FROM customer WHERE id = #{id}
</delete>
<!-- 6. 查询所有客户 -->
<select id="findAllCustomers" resultMap="customerMap">
SELECT * FROM customer ORDER BY id DESC
</select>
<!-- 7. 分页查询 -->
<select id="findCustomersByPage" parameterType="Map"
resultMap="customerMap">
SELECT * FROM customer
ORDER BY id DESC
LIMIT #{offset}, #{pageSize}
</select>
<!-- 8. 统计客户数量 -->
<select id="countCustomers" resultType="Long">
SELECT COUNT(*) FROM customer
</select>
</mapper>
4. MyBatis 核心配置
<?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>
<!-- 引入外部配置文件 -->
<properties resource="db.properties"/>
<!-- 全局设置 -->
<settings>
<!-- 开启驼峰命名自动映射 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
<!-- 打印SQL语句 -->
<setting name="logImpl" value="LOG4J"/>
</settings>
<!-- 类型别名 -->
<typeAliases>
<!-- 单个类型别名 -->
<typeAlias type="com.example.entity.Customer" alias="Customer"/>
<!-- 包扫描别名 -->
<package name="com.example.entity"/>
</typeAliases>
<!-- 数据库环境 -->
<environments default="development">
<environment id="development">
<!-- 事务管理器 -->
<transactionManager type="JDBC"/>
<!-- 数据源 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- Mapper 映射文件 -->
<mappers>
<!-- 单个映射文件 -->
<mapper resource="mapper/CustomerMapper.xml"/>
<!-- 包扫描 -->
<!-- <package name="com.example.mapper"/> -->
</mappers>
</configuration>
5. 数据库配置文件
# db.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false&serverTimezone=UTC&characterEncoding=utf8
jdbc.username=root
jdbc.password=password
6. 日志配置
# log4j.properties
log4j.rootLogger=DEBUG, Console
# Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
# MyBatis SQL 输出
log4j.logger.com.example.mapper=DEBUG
(2)导入依赖:mybatis、mysql-connector-java
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
<!-- 版本号与自己mysql版本一致-->
</dependency>
</dependencies>
(3)创建持久化类(实体类)
作用:和表进行数据转换 — 增:实体类对象 转换 表中的记录 — 查:表中的记录 转换 实体类对象 注意:成员变量的名字、数据类型 需要和 表中字段的名字、数据类型 保持一致
生成setter、getter 和 toString()方法
package com.owlbay.po;
public class Customer {
private int id;
private String username;
private String jobs;
private String phone;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getJobs() {
return jobs;
}
public void setJobs(String jobs) {
this.jobs = jobs;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", username='" + username + '\'' +
", jobs='" + jobs + '\'' +
", phone='" + phone + '\'' +
'}';
}
}
(4)在resources文件夹下创建CustomerMapper.xml文件,用来写sql语句
1.首先创建模板
在 file (文件)中的 setting (设置)中搜索 File and Code Templates (文件和代码模板),在其中首页 Files (文件)下创建文件 Mapper.xml,然后在下面填入以下代码,选择 OK (确定) 退出
<?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="">
</mapper>

2.创建CustomerMapper.xml文件
在 resources 文件夹右击选择 new(新建)Mapper

3.写sql语句
1.namespace属性的值:copy path(复制路径/引用)中 file name(文件名),去掉.xml
<mapper namespace="CustomerMapper">
2.#{id}占位符
3.parameterType是来设置占位符对应的参数的数据类型
4.resultType用来设置接收查询结果的持久化类,注意的是resultType属性值是全类名(全限定名)
<select id="findCustomerById" parameterType="int"resultType="com.owlbay.po.Customer">
select * from t_customer where id=#{id}
</select>

(5)在resources文件夹下创建mybatis-config.xml文件,该文件是MyBatis框架的配置文件
1.首先创建模板
在 file (文件)中的 setting (设置)中搜索 File and Code Templates (文件和代码模板),在其中首页 Files (文件)下创建文件 mybatis-config.xml,然后在下面填入以下代码,选择 OK (确定) 退出
<?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>
</configuration>

2.创建mybatis-config.xml文件
在 resources 文件夹右击选择 new(新建)mybatis-config

3.配置MyBatis框架
<configuration>
<!-- 1.连接数据库-->
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<!-- 四个成员变量不能错-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="8520"/>
</dataSource>
</environment>
</environments>
<!-- 2.加载Mapper文件-->
<mappers>
<!-- resource 从 copy path(复制路径/引用)中 file name(文件名)-->
<mapper resource="CustomerMapper.xml"/>
</mappers>
</configuration>

(6)单元测试:查询
在 com.owlbay.po 包下创建测试类MybatisTest
1.加载配置文件和 Mapper 文件
通过 CustomerMapper.xml 文件中的 select 的 id 的值来命名测试类

在输入 Resources 时通过提示导入名为 org 开头的包

在此输入完此行代码后 getResourceAsStream 会爆红,不用管后续处理
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
2.构建会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
3.构建会话 SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
因为要测试多个方法,所以将以上构造剪切到成员变量

4.处理爆红错误
将鼠标放置到爆红的 resourceAsStream 处 Alt+回车 处理问题,选择添加类默认构造函数签名的异常

5.导包 Test ,并写完查询类
selectOne()中的参数 = CustomerMapper.xml文件中 namespace + select id
MybatisTest.java 总体代码如下:
package com.owlbay.po;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MybatisTest {
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
public MybatisTest() throws IOException {
}
@Test
public void findCustomerById(){
// s: = CustomerMapper.xml文件中 namespace + select id
Customer o = sqlSession.selectOne("CustomerMapper.findCustomerById", 1);
System.out.println(o);
}
}
运行结果如下:

1.根据id查询客户
<select id="findCustomerById" parameterType="int" resultType="com.owlbay.po.Customer">
select * from t_customer where id=#{id}
</select>
@Test
public void findCustomerById() {
Customer o = sqlSession.selectOne("com.CustomerMapper.findCustomerById", 1);
System.out.println(o);
}

2.根据姓名模糊查询
<select id="findCustomerByName" parameterType="String" resultType="com.owlbay.po.Customer">
select * from t_customer where username like '%${value}%'
</select>
@Test
public void findCustomerByName() {
List<Customer> o = sqlSession.selectList("CustomerMapper.findCustomerByName", "j");
for (Customer customer : o){
System.out.println(customer);
}
}

3.添加客户
<insert id="addCustomer" parameterType="com.owlbay.po.Customer">
insert into t_customer values (#{id},#{username},#{jobs},#{phone})
</insert>
@Test
public void addCustomer(){
Customer customer = new Customer();
customer.setId(1);
customer.setUsername("zhangsan");
customer.setJobs("student");
customer.setPhone("110");
sqlSession.insert("CustomerMapper.addCustomer",customer);
sqlSession.commit();//只要更改数据库中的数据,就需要调用该方法完成数据的
sqlSession.close();//关闭数据库的连接
}

4.更新客户
<update id="updateCustomer" parameterType="com.owlbay.po.Customer">
update t_customer set username = #{username},jobs = #{jobs},phone = #{phone} where id = #{id}
</update>
@Test
public void updateCustomer() {
Customer customer = new Customer();
customer.setId(4);
customer.setUsername("zhangsan");
customer.setJobs("teacher");
customer.setPhone("18888888888");
sqlSession.update("CustomerMapper.updateCustomer", customer);
sqlSession.commit();
sqlSession.close();
}

5.删除客户
<delete id="deleteCustomer" parameterType="int">
delete from t_customer where id = #{id}
</delete>
@Test
public void deleteCustomer() {
sqlSession.delete("CustomerMapper.deleteCustomer", 1);
sqlSession.commit();
sqlSession.close();
}

如何在控制台输入SQL语句?
(1) 导包 log4j
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
(2) 复制log4j.properties文件到resources.文件夹下
(3) resources下新建directory,名为com
(4) 将CustomerMapper.xml文件复制到com下

(5) 复制后的CustomerMapper.Xml中的namespacel的值修改:com.CustomerMapper

(6) 修改mybatis-config.xml文件中resource属性的值:

(7) 修改测试方法中的值:

运行测试结果如下:

配置详解
1. MyBatis 配置文件结构
MyBatis 配置文件的元素顺序必须遵循以下顺序:
configuration(配置)
├─ properties(属性)
├─ settings(设置)
├─ typeAliases(类型别名)
├─ typeHandlers(类型处理器)
├─ objectFactory(对象工厂)
├─ plugins(插件)
├─ environments(环境配置)
│ ├─ environment(环境变量)
│ ├─ transactionManager(事务管理器)
│ └─ dataSource(数据源)
└─ mappers(映射器)
2. 重要设置项
| 设置项 | 说明 | 默认值 |
|---|---|---|
| cacheEnabled | 全局二级缓存开关 | true |
| lazyLoadingEnabled | 延迟加载开关 | false |
| mapUnderscoreToCamelCase | 驼峰命名自动映射 | false |
| logImpl | 日志实现 | 未设置 |
| defaultExecutorType | 执行器类型 | SIMPLE |
映射器开发
1. 注解方式
public interface CustomerMapper {
@Select("SELECT * FROM customer WHERE id = #{id}")
Customer findCustomerById(Integer id);
@Insert("INSERT INTO customer(username, jobs, phone) VALUES(#{username}, #{jobs}, #{phone})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int addCustomer(Customer customer);
@Update("UPDATE customer SET username=#{username}, jobs=#{jobs}, phone=#{phone} WHERE id=#{id}")
int updateCustomer(Customer customer);
@Delete("DELETE FROM customer WHERE id=#{id}")
int deleteCustomer(Integer id);
// 复杂查询建议使用 XML 配置
@Select({
"<script>",
"SELECT * FROM customer",
"<where>",
" <if test='username != null'>",
" AND username LIKE CONCAT('%', #{username}, '%')",
" </if>",
" <if test='jobs != null'>",
" AND jobs = #{jobs}",
" </if>",
"</where>",
"</script>"
})
List<Customer> findCustomersByCondition(@Param("username") String username,
@Param("jobs") String jobs);
}
2. 测试类实现
public class CustomerMapperTest {
private SqlSession sqlSession;
private CustomerMapper customerMapper;
@Before
public void setUp() {
sqlSession = MyBatisUtils.getSqlSession();
customerMapper = sqlSession.getMapper(CustomerMapper.class);
}
@After
public void tearDown() {
sqlSession.close();
}
@Test
public void testFindCustomerById() {
Customer customer = customerMapper.findCustomerById(1);
System.out.println(customer);
}
@Test
public void testAddCustomer() {
Customer customer = new Customer();
customer.setUsername("张三");
customer.setJobs("程序员");
customer.setPhone("13900139000");
int rows = customerMapper.addCustomer(customer);
sqlSession.commit();
System.out.println("影响行数:" + rows);
System.out.println("新增ID:" + customer.getId());
}
@Test
public void testUpdateCustomer() {
Customer customer = customerMapper.findCustomerById(1);
customer.setUsername("李四");
customer.setJobs("高级工程师");
int rows = customerMapper.updateCustomer(customer);
sqlSession.commit();
System.out.println("更新行数:" + rows);
}
}
动态 SQL
1. if 标签
<select id="findCustomersByCondition" resultMap="customerMap">
SELECT * FROM customer
WHERE 1=1
<if test="username != null and username != ''">
AND username LIKE CONCAT('%', #{username}, '%')
</if>
<if test="jobs != null and jobs != ''">
AND jobs = #{jobs}
</if>
</select>
2. where 标签
<select id="findCustomersByCondition" resultMap="customerMap">
SELECT * FROM customer
<where>
<if test="username != null and username != ''">
AND username LIKE CONCAT('%', #{username}, '%')
</if>
<if test="jobs != null and jobs != ''">
AND jobs = #{jobs}
</if>
</where>
</select>
3. choose-when-otherwise
<select id="findCustomersByChoose" resultMap="customerMap">
SELECT * FROM customer
<where>
<choose>
<when test="username != null">
username = #{username}
</when>
<when test="jobs != null">
jobs = #{jobs}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</where>
</select>
4. foreach 标签
<select id="findCustomersByIds" resultMap="customerMap">
SELECT * FROM customer
WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
最佳实践
1. 配置优化
<settings>
<!-- 开启驼峰命名转换 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 积极加载关闭 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
2. 性能优化
- 使用缓存:合理配置一级和二级缓存
- 批量操作:使用 batch 执行器
- 延迟加载:避免 N+1 查询问题
- SQL 优化:使用索引,避免全表扫描
3. 开发建议
- 简单 SQL 使用注解,复杂 SQL 使用 XML
- 利用 IDE 插件:MyBatis Plugin 等
- 代码生成器:MyBatis Generator
- 日志调试:开启 SQL 日志输出
常见问题
问题 1:TypeException
错误信息:TypeException: Could not resolve type alias
解决方案:
- 检查类型别名配置是否正确
- 确认类路径存在
- 使用全限定类名
问题 2:BindingException
错误信息:BindingException: Invalid bound statement
解决方案:
- 检查 namespace 和接口全限定名是否一致
- 检查方法名和 id 是否匹配
- 确认 mapper.xml 已正确加载
问题 3:中文乱码
解决方案:
jdbc.url=jdbc:mysql://localhost:3306/db?characterEncoding=utf8&useUnicode=true
问题 4:事务不生效
解决方案:
// 手动提交事务
sqlSession.commit();
// 或者开启自动提交
SqlSession sqlSession = sqlSessionFactory.openSession(true);
总结
MyBatis 作为一个半自动化的 ORM 框架,具有以下特点:
🎯 核心优势
- SQL 控制力强:完全掌控 SQL 语句,便于优化
- 简单易学:XML 和注解两种配置方式
- 动态 SQL:强大的动态 SQL 生成能力
- 二级缓存:提升查询性能
📊 适用场景
- 需求变化频繁:SQL 语句需要经常调整
- 性能要求高:需要精细优化 SQL
- 复杂查询多:大量的联表查询和统计
- 团队 SQL 能力强:DBA 参与开发
🚀 学习路线
- 基础使用:配置、CRUD 操作
- 动态 SQL:if、where、foreach 等标签
- 关系映射:一对一、一对多、多对多
- 性能优化:缓存、延迟加载、批处理
- 框架整合:Spring + MyBatis 集成