MyBatis基础详解
MyBatis 基础详解
本章位置:第二阶段 Java 核心框架
前置知识:JavaSE、JDBC、DAO 思想、配置文件、JavaBean、反射
下一篇:Servlet
学习目标:掌握 MyBatis 项目搭建、核心配置、Mapper 接口、Mapper XML、CRUD、参数传递、结果映射、日志、事务与常见报错。
一、MyBatis 是什么
MyBatis 是一个 Java 持久层框架,主要帮助我们:
减少 JDBC 重复代码
自动绑定 SQL 参数
自动封装查询结果
使用 Mapper 接口操作数据库
把 SQL 从 Java 代码中分离出来
它底层仍然使用 JDBC:
Java
↓
MyBatis
↓
JDBC
↓
MySQL Driver
↓
MySQL
所以学 MyBatis 并不是抛弃 JDBC,而是让框架帮我们封装 JDBC 模板代码。
二、为什么需要 MyBatis
JDBC 查询通常要自己完成:
获取 Connection
创建 PreparedStatement
绑定参数
执行 SQL
遍历 ResultSet
创建 JavaBean
给属性赋值
关闭资源
处理异常
而 MyBatis 让我们把重点放到:
SQL
参数
结果映射
例如 JDBC:
PreparedStatement ps =
connection.prepareStatement(
"SELECT id,name FROM student WHERE id=?"
);
ps.setLong(
1,
id
);
ResultSet rs =
ps.executeQuery();
MyBatis:
Student student =
studentMapper.findById(
id
);
三、MyBatis 核心对象
初学阶段先记住:
SqlSessionFactoryBuilder
SqlSessionFactory
SqlSession
Mapper
关系:
mybatis-config.xml
↓
SqlSessionFactoryBuilder
↓
SqlSessionFactory
↓
SqlSession
↓
Mapper
↓
SQL
↓
数据库
四、SqlSessionFactoryBuilder
负责:
读取配置
创建 SqlSessionFactory
通常只在应用初始化阶段使用。
五、SqlSessionFactory
负责:
创建 SqlSession
一般整个应用复用一个:
SqlSessionFactory
不要每次查询都重新 build。
六、SqlSession
SqlSession 可以理解为:
一次数据库会话
主要负责:
获取 Mapper
执行 SQL
提交事务
回滚事务
七、Mapper
Mapper 是数据库访问接口。
例如:
public interface StudentMapper {
Student findById(
Long id
);
}
正常情况下不用写:
StudentMapperImpl
MyBatis 会动态生成代理对象。
八、为什么 Mapper 没有实现类还能运行
StudentMapper mapper =
sqlSession.getMapper(
StudentMapper.class
);
这里得到的是:
MyBatis 代理对象
调用:
mapper.findById(
1L
);
MyBatis 会:
找到对应 SQL
绑定参数
执行 JDBC
封装结果
返回 Student
九、创建 Maven 项目
IDEA:
File
→ New
→ Project
→ Maven
建议:
JDK 17
项目名:
mybatis-demo
十、推荐目录结构
mybatis-demo
│
├─ pom.xml
│
└─ src
└─ main
├─ java
│ └─ com.example.mybatis
│ ├─ entity
│ │ └─ Student.java
│ ├─ mapper
│ │ └─ StudentMapper.java
│ ├─ util
│ │ └─ MyBatisUtil.java
│ └─ MyBatisDemo.java
│
└─ resources
├─ jdbc.properties
├─ mybatis-config.xml
└─ mapper
└─ StudentMapper.xml
十一、Maven 依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.19</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.4.0</version>
</dependency>
</dependencies>
版本不是学习重点,项目已有兼容版本时不必机械修改。
十二、创建数据库
CREATE DATABASE IF NOT EXISTS mybatis_demo
CHARACTER SET utf8mb4;
使用:
USE mybatis_demo;
创建表:
CREATE TABLE student (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
student_no VARCHAR(30) NOT NULL UNIQUE,
name VARCHAR(50) NOT NULL,
age INT,
major VARCHAR(100),
score DECIMAL(5,2)
);
测试数据:
INSERT INTO student
(
student_no,
name,
age,
major,
score
)
VALUES
(
'20260001',
'张三',
20,
'软件工程',
90.50
),
(
'20260002',
'李四',
21,
'计算机科学与技术',
85.00
);
十三、Student 实体类
package com.example.mybatis.entity;
import java.math.BigDecimal;
public class Student {
private Long id;
private String studentNo;
private String name;
private Integer age;
private String major;
private BigDecimal score;
public Student() {
}
public Long getId() {
return id;
}
public void setId(
Long id
) {
this.id = id;
}
public String getStudentNo() {
return studentNo;
}
public void setStudentNo(
String studentNo
) {
this.studentNo = studentNo;
}
public String getName() {
return name;
}
public void setName(
String name
) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(
Integer age
) {
this.age = age;
}
public String getMajor() {
return major;
}
public void setMajor(
String major
) {
this.major = major;
}
public BigDecimal getScore() {
return score;
}
public void setScore(
BigDecimal score
) {
this.score = score;
}
@Override
public String toString() {
return "Student{"
+ "id=" + id
+ ", studentNo='" + studentNo + '\''
+ ", name='" + name + '\''
+ ", age=" + age
+ ", major='" + major + '\''
+ ", score=" + score
+ '}';
}
}
MyBatis 经常通过反射创建对象,所以传统 JavaBean 风格:
无参构造
Getter
Setter
非常常见。
十四、jdbc.properties
位置:
src/main/resources/jdbc.properties
内容:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_demo
jdbc.username=root
jdbc.password=123456
把账号密码改成自己的实际配置。
十五、mybatis-config.xml
位置:
src/main/resources/mybatis-config.xml
<?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>
<properties
resource="jdbc.properties"/>
<settings>
<setting
name="mapUnderscoreToCamelCase"
value="true"/>
<setting
name="logImpl"
value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package
name="com.example.mybatis.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>
<mappers>
<mapper
resource="mapper/StudentMapper.xml"/>
</mappers>
</configuration>
十六、配置标签顺序
MyBatis 核心配置标签有固定顺序,常见:
properties
settings
typeAliases
typeHandlers
objectFactory
plugins
environments
databaseIdProvider
mappers
顺序错了可能导致 XML 校验失败。
十七、properties
<properties
resource="jdbc.properties"/>
负责加载外部配置。
后面:
${jdbc.url}
就是读取对应属性。
十八、settings
用于调整 MyBatis 全局行为。
例如:
驼峰映射
日志
缓存
懒加载
十九、驼峰映射
<setting
name="mapUnderscoreToCamelCase"
value="true"/>
可以把:
student_no
→ studentNo
create_time
→ createTime
这是实际项目非常常见的配置。
二十、日志
<setting
name="logImpl"
value="STDOUT_LOGGING"/>
学习阶段可以看到:
Preparing
Parameters
Total
非常适合排查 SQL。
二十一、typeAliases
<typeAliases>
<package
name="com.example.mybatis.entity"/>
</typeAliases>
配置后 XML 可以写:
resultType="Student"
而不用每次写全限定名。
二十二、environments
用于配置:
数据库运行环境
例如:
development
test
production
二十三、transactionManager
<transactionManager
type="JDBC"/>
表示使用 JDBC 事务管理。
后面整合 Spring 后,事务一般由 Spring 接管。
二十四、dataSource
<dataSource
type="POOLED">
表示使用 MyBatis 自带简单连接池。
常见:
UNPOOLED
POOLED
JNDI
二十五、创建 StudentMapper
package com.example.mybatis.mapper;
import com.example.mybatis.entity.Student;
import java.util.List;
public interface StudentMapper {
Student findById(
Long id
);
List<Student> findAll();
int insert(
Student student
);
int update(
Student student
);
int deleteById(
Long id
);
}
二十六、创建 Mapper XML
位置:
src/main/resources/mapper/StudentMapper.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">
<mapper
namespace="com.example.mybatis.mapper.StudentMapper">
</mapper>
二十七、namespace
namespace="com.example.mybatis.mapper.StudentMapper"
必须对应:
Mapper 接口全限定名
可以记:
namespace → Mapper 接口
二十八、id
例如:
<select
id="findById">
id 对应:
findById(...)
所以:
id → Mapper 方法名
二十九、查询单个学生
<select
id="findById"
resultType="Student">
SELECT
id,
student_no,
name,
age,
major,
score
FROM student
WHERE id = #{id}
</select>
三十、#{id}
#{} 是 MyBatis 最重要的参数绑定语法。
WHERE id = #{id}
底层类似:
WHERE id = ?
再由 PreparedStatement 绑定值。
三十一、第一个运行程序
package com.example.mybatis;
import com.example.mybatis.entity.Student;
import com.example.mybatis.mapper.StudentMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.*;
import java.io.InputStream;
public class MyBatisDemo {
public static void main(
String[] args
)
throws Exception {
InputStream input =
Resources
.getResourceAsStream(
"mybatis-config.xml"
);
SqlSessionFactory factory =
new SqlSessionFactoryBuilder()
.build(
input
);
try (
SqlSession sqlSession =
factory.openSession()
) {
StudentMapper mapper =
sqlSession.getMapper(
StudentMapper.class
);
Student student =
mapper.findById(
1L
);
System.out.println(
student
);
}
}
}
三十二、运行过程
读取 mybatis-config.xml
↓
创建 SqlSessionFactory
↓
打开 SqlSession
↓
获取 Mapper 代理
↓
调用 findById
↓
找到 Mapper XML
↓
执行 SQL
↓
ResultSet 映射 Student
↓
返回对象
三十三、Could not find resource
如果出现:
Could not find resource mybatis-config.xml
重点检查:
文件是否在 src/main/resources
文件名是否一致
大小写是否一致
target/classes 是否有该文件
正确:
Resources.getResourceAsStream(
"mybatis-config.xml"
);
不要:
Resources.getResourceAsStream(
"src/main/resources/mybatis-config.xml"
);
因为 Resources 按 classpath 查找。
三十四、查询全部
Mapper:
List<Student> findAll();
XML:
<select
id="findAll"
resultType="Student">
SELECT
id,
student_no,
name,
age,
major,
score
FROM student
ORDER BY id
</select>
MyBatis 会自动把每一行映射成 Student,再组合成 List。
三十五、新增
Mapper:
int insert(
Student student
);
XML:
<insert
id="insert">
INSERT INTO student
(
student_no,
name,
age,
major,
score
)
VALUES
(
#{studentNo},
#{name},
#{age},
#{major},
#{score}
)
</insert>
三十六、对象参数为什么能直接写 #{name}
因为参数是:
Student student
MyBatis 会按照 JavaBean 属性读取:
studentNo
name
age
major
score
这和之前学习的:
JavaBean
反射
内省
直接相关。
三十七、增删改为什么要 commit
默认:
factory.openSession()
一般不会自动提交。
所以:
mapper.insert(
student
);
sqlSession.commit();
否则可能:
代码没报错
数据库却没有数据
三十八、自动提交
也可以:
factory.openSession(
true
);
表示:
autoCommit=true
但学习阶段建议手动使用 commit,理解事务。
三十九、修改
<update
id="update">
UPDATE student
SET
name = #{name},
age = #{age},
major = #{major},
score = #{score}
WHERE id = #{id}
</update>
四十、删除
<delete
id="deleteById">
DELETE
FROM student
WHERE id = #{id}
</delete>
四十一、CRUD 标签
必须掌握:
<select>
<insert>
<update>
<delete>
四十二、主键回填
如果 id 是:
AUTO_INCREMENT
插入后希望:
student.getId()
直接获得数据库生成的主键。
可以:
<insert
id="insert"
useGeneratedKeys="true"
keyProperty="id">
INSERT INTO student
(
student_no,
name,
age,
major,
score
)
VALUES
(
#{studentNo},
#{name},
#{age},
#{major},
#{score}
)
</insert>
四十三、useGeneratedKeys
获取数据库自动生成主键
keyProperty:
把主键回填到 JavaBean 对应属性
四十四、多参数
例如:
Student findByNameAndAge(
String name,
Integer age
);
推荐:
Student findByNameAndAge(
@Param("name")
String name,
@Param("age")
Integer age
);
XML:
WHERE
name = #{name}
AND age = #{age}
四十五、@Param
作用:
明确 Mapper 方法参数
在 SQL 中叫什么
多参数方法建议养成使用 @Param 的习惯。
四十六、Map 参数
也可以:
List<Student> find(
Map<String, Object> params
);
Map 中:
params.put(
"name",
"张三"
);
params.put(
"age",
20
);
SQL:
#{name}
#{age}
四十七、查询对象参数
条件较多时,可以创建:
public class StudentQuery {
private String name;
private Integer minAge;
private Integer maxAge;
}
Mapper:
List<Student> findByCondition(
StudentQuery query
);
SQL 可以直接:
#{name}
#{minAge}
#{maxAge}
四十八、#{ } 和 ${ } 区别
必须掌握:
#{}
参数占位
${}
字符串直接拼接
四十九、#{ } 更安全
WHERE name = #{name}
底层类似:
WHERE name = ?
使用 PreparedStatement,可以有效降低 SQL 注入风险。
五十、${ } 直接拼接
例如:
ORDER BY ${column}
如果:
column=score
最终:
ORDER BY score
它不是 PreparedStatement 参数。
五十一、什么时候可能用 ${ }
例如:
动态列名
动态表名
ORDER BY 字段
因为 SQL 标识符通常不能通过 ? 参数绑定。
但一定:
做白名单校验
不要直接使用用户输入。
五十二、模糊查询
接口:
List<Student> findByName(
@Param("keyword")
String keyword
);
XML:
<select
id="findByName"
resultType="Student">
SELECT
id,
student_no,
name,
age,
major,
score
FROM student
WHERE
name LIKE CONCAT(
'%',
#{keyword},
'%'
)
</select>
不要写成:
LIKE '%${keyword}%'
五十三、分页查询
Mapper:
List<Student> findPage(
@Param("offset")
int offset,
@Param("pageSize")
int pageSize
);
XML:
<select
id="findPage"
resultType="Student">
SELECT
id,
student_no,
name,
age,
major,
score
FROM student
ORDER BY id
LIMIT
#{offset},
#{pageSize}
</select>
offset:
int offset =
(pageNum - 1)
* pageSize;
五十四、resultType
简单查询:
resultType="Student"
MyBatis 会根据:
列名
属性名
自动映射。
五十五、数据库下划线和 Java 驼峰
数据库:
student_no
Java:
studentNo
可以用:
AS 别名
驼峰映射
resultMap
解决。
五十六、SQL 别名
SELECT
student_no AS studentNo
FROM student;
五十七、resultMap
复杂映射:
<resultMap
id="studentResultMap"
type="Student">
<id
property="id"
column="id"/>
<result
property="studentNo"
column="student_no"/>
<result
property="name"
column="name"/>
<result
property="age"
column="age"/>
<result
property="major"
column="major"/>
<result
property="score"
column="score"/>
</resultMap>
五十八、使用 resultMap
<select
id="findById"
resultMap="studentResultMap">
SELECT
id,
student_no,
name,
age,
major,
score
FROM student
WHERE id = #{id}
</select>
五十九、resultType 和 resultMap 怎么选
resultType
简单自动映射
resultMap
字段差异大
多表查询
一对一
一对多
复杂对象结构
六十、统计查询
Mapper:
long count();
XML:
<select
id="count"
resultType="long">
SELECT
COUNT(*)
FROM student
</select>
六十一、查询单列 List
List<String> findAllMajors();
XML:
<select
id="findAllMajors"
resultType="string">
SELECT DISTINCT
major
FROM student
</select>
六十二、事务
提交:
sqlSession.commit();
回滚:
sqlSession.rollback();
标准思路:
try {
mapper.update(...);
mapper.insert(...);
sqlSession.commit();
} catch (
Exception e
) {
sqlSession.rollback();
throw e;
}
六十三、一个事务要用同一个 SqlSession
如果两次数据库操作必须:
一起成功
或
一起失败
就要确保它们属于:
同一个数据库事务
基础 MyBatis 中通常意味着:
同一个 SqlSession
六十四、MyBatisUtil
package com.example.mybatis.util;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.*;
import java.io.InputStream;
public final class MyBatisUtil {
private static final
SqlSessionFactory FACTORY;
static {
try {
InputStream input =
Resources
.getResourceAsStream(
"mybatis-config.xml"
);
FACTORY =
new SqlSessionFactoryBuilder()
.build(
input
);
} catch (
Exception e
) {
throw new ExceptionInInitializerError(
e
);
}
}
private MyBatisUtil() {
}
public static SqlSession
openSession() {
return FACTORY
.openSession();
}
}
六十五、使用工具类
try (
SqlSession sqlSession =
MyBatisUtil.openSession()
) {
StudentMapper mapper =
sqlSession.getMapper(
StudentMapper.class
);
Student student =
mapper.findById(
1L
);
System.out.println(
student
);
}
六十六、Mapper 调用底层流程
mapper.findById()
↓
Mapper 动态代理拦截
↓
根据接口名 + 方法名
查找 MappedStatement
↓
得到 SQL
↓
绑定参数
↓
JDBC 执行
↓
处理 ResultSet
↓
创建 Student
↓
属性映射
↓
返回结果
六十七、MappedStatement
MyBatis 解析:
<select>
<insert>
<update>
<delete>
后会保存成内部的:
MappedStatement
其中包含:
SQL
参数映射
结果映射
缓存配置
Statement 类型
当前了解概念即可。
六十八、为什么前面的反射很重要
现在可以看到:
Mapper 代理
结果自动封装
JavaBean 属性读取
动态对象创建
都和:
反射
JavaBean
内省
动态代理
有关。
六十九、一级缓存简单了解
MyBatis 默认:
一级缓存
作用范围:
SqlSession
同一个 SqlSession 里重复查询相同数据,有可能直接使用缓存。
例如:
mapper.findById(
1L
);
mapper.findById(
1L
);
第二次不一定再次访问数据库。
缓存详细原理放到 MyBatis 进阶。
七十、常见错误:Invalid bound statement
报错:
Invalid bound statement (not found)
优先检查:
namespace 是否正确
XML id 是否等于方法名
Mapper XML 是否加载
XML 路径是否正确
接口全限定名是否一致
七十一、常见错误:Parameter not found
例如:
Parameter 'name' not found
多参数时推荐:
@Param("name")
String name
然后:
#{name}
七十二、常见错误:属性值为 null
例如数据库:
student_no 有值
Java:
studentNo=null
检查:
驼峰映射
resultMap
SQL AS
属性 Getter/Setter
七十三、常见错误:增删改后数据库没有变化
最常见:
忘记 commit
七十四、常见错误:Mapper XML 找不到
例如:
Could not find resource mapper/StudentMapper.xml
检查:
resources/mapper
文件名
resource 路径
大小写
target/classes
七十五、常见错误:namespace 写错
不推荐:
namespace="StudentMapper"
推荐:
namespace=
"com.example.mybatis.mapper.StudentMapper"
七十六、常见错误:resultType 别名无法识别
如果:
resultType="Student"
但没有配置 typeAliases,可能找不到。
解决:
配置 typeAliases
或写全限定类名。
七十七、常见错误:XML 小于号
例如:
age < 18
XML 中可以写:
age < 18
或者:
<![CDATA[
age < 18
]]>
七十八、常见错误:SQL 语法错误
开启:
STDOUT_LOGGING
重点看:
Preparing
Parameters
把 SQL 复制到 MySQL 客户端直接执行,是非常有效的排查方式。
七十九、常见错误:使用 ${} 接收用户输入
不推荐:
WHERE name = '${name}'
推荐:
WHERE name = #{name}
八十、常见错误:长期使用 SELECT *
学习时可以:
SELECT *
项目中更推荐:
SELECT
id,
student_no,
name,
age,
major,
score
FROM student;
原因:
字段明确
减少无用数据
映射清晰
表结构变化风险更低
八十一、Mapper 和 DAO 的关系
JDBC 阶段:
StudentDao
StudentDaoImpl
MyBatis 阶段:
StudentMapper
Mapper 本质上承担:
DAO 数据访问职责
但实现类由 MyBatis 代理生成。
八十二、完整 Mapper 接口
public interface StudentMapper {
Student findById(
Long id
);
List<Student> findAll();
List<Student> findByName(
@Param("keyword")
String keyword
);
List<Student> findPage(
@Param("offset")
int offset,
@Param("pageSize")
int pageSize
);
int insert(
Student student
);
int update(
Student student
);
int deleteById(
Long id
);
long count();
}
八十三、推荐练习顺序
不要一开始把全部 CRUD 一次写完。
推荐:
1. findById
2. findAll
3. insert
4. update
5. delete
6. @Param 多参数
7. 模糊查询
8. 分页
9. resultMap
10. 事务
每完成一步:
马上运行
马上验证
八十四、IDEA 快捷操作
生成 Getter/Setter:
Alt + Insert
构造方法:
Alt + Insert
→ Constructor
toString:
Alt + Insert
→ toString()
八十五、练习题
建议依次完成:
1. 根据 id 查询学生
2. 查询全部学生
3. 姓名模糊查询
4. 新增学生
5. 自增主键回填
6. 修改学生
7. 删除学生
8. @Param 多条件查询
9. resultMap 显式映射
10. 开启驼峰映射
11. LIMIT 分页
12. 同一 SqlSession 事务回滚测试
八十六、必须掌握的 API
Resources
.getResourceAsStream()
new SqlSessionFactoryBuilder()
.build(...)
SqlSessionFactory
.openSession()
SqlSession
.getMapper()
SqlSession
.commit()
SqlSession
.rollback()
八十七、必须掌握的 XML 标签
<configuration>
<properties>
<settings>
<typeAliases>
<environments>
<transactionManager>
<dataSource>
<mappers>
<mapper>
<select>
<insert>
<update>
<delete>
<resultMap>
<id>
<result>
八十八、必须掌握的参数方式
单参数
@Param
JavaBean 参数
Map 参数
#{}
${}
八十九、必须回答的问题
学完后应该能够回答:
1. MyBatis 是什么?
2. MyBatis 和 JDBC 是什么关系?
3. SqlSessionFactory 是什么?
4. SqlSession 是什么?
5. Mapper 接口为什么不需要实现类?
6. namespace 有什么作用?
7. Mapper XML 的 id 对应什么?
8. #{} 和 ${} 有什么区别?
9. 为什么 #{} 更安全?
10. 多参数为什么推荐 @Param?
11. resultType 和 resultMap 有什么区别?
12. 驼峰映射是什么?
13. 增删改为什么要 commit?
14. useGeneratedKeys 有什么作用?
15. MyBatis 为什么能自动封装 JavaBean?
16. Invalid bound statement 怎么排查?
17. Could not find resource 怎么排查?
九十、MyBatis 知识结构
MyBatis
│
├─ 配置
│ ├─ properties
│ ├─ settings
│ ├─ typeAliases
│ ├─ environments
│ └─ mappers
│
├─ 核心对象
│ ├─ SqlSessionFactoryBuilder
│ ├─ SqlSessionFactory
│ └─ SqlSession
│
├─ Mapper
│ ├─ Interface
│ ├─ namespace
│ └─ id
│
├─ SQL
│ ├─ select
│ ├─ insert
│ ├─ update
│ └─ delete
│
├─ 参数
│ ├─ @Param
│ ├─ JavaBean
│ ├─ Map
│ ├─ #{}
│ └─ ${}
│
├─ 映射
│ ├─ resultType
│ ├─ resultMap
│ └─ 驼峰映射
│
└─ 事务
├─ commit
└─ rollback
九十一、从 JDBC 到 MyBatis
JDBC:
自己创建 Statement
自己绑定参数
自己处理 ResultSet
自己封装对象
MyBatis:
写 Mapper 接口
写 SQL
定义结果映射
框架负责 JDBC 模板代码
但底层仍然是:
JDBC
九十二、从反射到 MyBatis
前面学过:
JavaBean
反射
内省
动态代理
现在都能看到实际作用:
Mapper 动态代理
JavaBean 属性读取
结果自动映射
参数绑定
对象创建
九十三、从 MyBatis 到 SpringBoot
后面 SpringBoot 整合 MyBatis 后,通常不需要自己:
build SqlSessionFactory
openSession
getMapper
Spring 会帮助管理:
DataSource
SqlSessionFactory
Mapper Bean
事务
所以现在学习原生 MyBatis 的意义是:
理解以后 SpringBoot 到底帮你省略了什么
九十四、本章总结
MyBatis 最核心的一句话:
MyBatis 是建立在 JDBC 之上的持久层框架,它减少 JDBC 模板代码,同时保留开发者对 SQL 的控制。
核心流程:
mybatis-config.xml
↓
SqlSessionFactory
↓
SqlSession
↓
Mapper 代理
↓
Mapper XML
↓
SQL
↓
JDBC
↓
数据库
↓
结果映射
↓
JavaBean
必须牢记:
namespace
对应 Mapper 接口
id
对应 Mapper 方法
#{}
优先用于参数绑定
${}
直接拼接,必须谨慎
resultType
适合简单映射
resultMap
适合复杂映射
commit
提交增删改事务
常见报错建议按:
配置文件路径
↓
Mapper 是否加载
↓
namespace
↓
id
↓
参数
↓
SQL
↓
结果映射
↓
事务
逐层排查。
下一篇按照课程表正式进入:
Servlet
开始学习:
Tomcat
HTTP
请求
响应
Servlet 生命周期
浏览器与 Java 后端交互