MyBatis會(huì)話模塊詳解
一、MyBatis整體架構(gòu)與會(huì)話模塊
MyBatis是一個(gè)優(yōu)秀的持久層框架,它支持定制化SQL、存儲(chǔ)過程以及高級(jí)映射。MyBatis避免了幾乎所有的JDBC代碼和手動(dòng)設(shè)置參數(shù)以及獲取結(jié)果集的工作。
1.1 MyBatis整體架構(gòu)
MyBatis采用分層架構(gòu)設(shè)計(jì),從上到下分為:
- 應(yīng)用層 — 與用戶應(yīng)用程序直接交互
- 接口層 — 提供SqlSession和Mapper接口
- 核心處理層 — 包括SQL解析、執(zhí)行、結(jié)果映射
- 基礎(chǔ)支撐層 — 包括反射、類型處理、日志、緩存、事務(wù)
- 數(shù)據(jù)層 — 數(shù)據(jù)源管理、連接池、JDBC驅(qū)動(dòng)
會(huì)話模塊位于接口層,是MyBatis與應(yīng)用程序交互的主要入口。

1.2 會(huì)話模塊的核心職責(zé)
會(huì)話模塊在MyBatis中承擔(dān)以下核心職責(zé):
? 數(shù)據(jù)庫操作接口 — 提供insert、update、delete、select等方法
? SqlSession生命周期管理 — 創(chuàng)建、使用、關(guān)閉SqlSession
? 事務(wù)控制 — 管理事務(wù)的開啟、提交、回滾
? Mapper管理 — 獲取Mapper接口的代理對(duì)象
? 批量操作支持 — 提供批量執(zhí)行SQL的能力
二、SqlSession接口詳解
SqlSession是MyBatis的核心接口之一,它定義了所有數(shù)據(jù)庫操作的方法。
2.1 SqlSession核心方法分類
// 查詢單個(gè)對(duì)象
<T> T selectOne(String statement);
<T> T selectOne(String statement, Object parameter);
// 查詢列表
<E> List<E> selectList(String statement);
<E> List<E> selectList(String statement, Object parameter);
// 查詢Map
<K, V> Map<K, V> selectMap(String statement, String mapKey);
// 游標(biāo)查詢
<T> Cursor<T> selectCursor(String statement);
// 插入
int insert(String statement);
int insert(String statement, Object parameter);
// 更新
int update(String statement);
int update(String statement, Object parameter);
// 刪除
int delete(String statement);
int delete(String statement, Object parameter);
// 提交事務(wù)
void commit();
void commit(boolean force);
// 回滾事務(wù)
void rollback();
void rollback(boolean force);
// 獲取Mapper代理對(duì)象
<T> T getMapper(Class<T> type);
// 1. 獲取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsStream("mybatis-config.xml"));
// 2. 打開SqlSession
try (SqlSession session = factory.openSession()) {
// 3. 執(zhí)行SQL
User user = session.selectOne(
"com.example.mapper.UserMapper.selectById", 1);
System.out.println(user);
}
try (SqlSession session = factory.openSession()) {
// 獲取Mapper代理對(duì)象
UserMapper mapper = session.getMapper(UserMapper.class);
// 調(diào)用Mapper方法
User user = mapper.selectById(1);
System.out.println(user);
session.commit();
}
三、SqlSession的實(shí)現(xiàn)類
MyBatis提供了兩個(gè)主要的SqlSession實(shí)現(xiàn)類。
3.1 DefaultSqlSession
DefaultSqlSession是SqlSession的默認(rèn)實(shí)現(xiàn)類,最常用的實(shí)現(xiàn)。
核心代碼片段:
public class DefaultSqlSession implements SqlSession {
private final Configuration configuration;
private final Executor executor;
@Override
public <T> T selectOne(String statement, Object parameter) {
List<T> list = this.selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException(
"Expected one result but found: " + list.size());
}
return null;
}
@Override
public void commit(boolean force) {
try {
executor.commit(isCommitOrRollbackRequired(force));
dirty = false;
} catch (Exception e) {
throw ExceptionFactory.wrapException(
"Error committing transaction.", e);
}
}
}
3.2 SqlSessionManager
SqlSessionManager同時(shí)實(shí)現(xiàn)了SqlSession和SqlSessionFactory接口,既可以作為SqlSession使用,也可以作為工廠使用。
public class SqlSessionManager
implements SqlSessionFactory, SqlSession {
private final SqlSessionFactory sqlSessionFactory;
private final SqlSession sqlSessionProxy;
private ThreadLocal<SqlSession> localSqlSession
= new ThreadLocal<>();
// 開啟本地Session
public void startManagedSession() {
this.localSqlSession.set(openSession());
}
// 關(guān)閉本地Session
public void closeManagedSession() {
SqlSession sqlSession = localSqlSession.get();
if (sqlSession != null) {
try {
sqlSession.close();
} finally {
localSqlSession.remove();
}
}
}
}

四、SqlSessionFactory工廠
SqlSessionFactory是創(chuàng)建SqlSession的工廠接口。
4.1 SqlSessionFactory接口方法
public interface SqlSessionFactory {
// 常用方法:打開Session
SqlSession openSession();
// 指定ExecutorType
SqlSession openSession(ExecutorType execType);
// 指定是否自動(dòng)提交
SqlSession openSession(boolean autoCommit);
// 指定事務(wù)隔離級(jí)別
SqlSession openSession(TransactionIsolationLevel level);
// 使用指定連接
SqlSession openSession(Connection connection);
}
4.2 DefaultSqlSessionFactory核心流程
創(chuàng)建SqlSession的完整流程:
private SqlSession openSessionFromDataSource(
ExecutorType execType,
TransactionIsolationLevel level,
boolean autoCommit) {
Transaction tx = null;
try {
//獲取環(huán)境配置
Environment environment = configuration.getEnvironment();
//創(chuàng)建事務(wù)工廠
TransactionFactory transactionFactory =
getTransactionFactoryFromEnvironment(environment);
//創(chuàng)建事務(wù)
tx = transactionFactory.newTransaction(
environment.getDataSource(), level, autoCommit);
//創(chuàng)建執(zhí)行器
Executor executor = configuration.newExecutor(tx, execType);
//創(chuàng)建DefaultSqlSession
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx);
throw ExceptionFactory.wrapException(
"Error opening session.", e);
}
}

五、SqlSession生命周期管理
SqlSession的生命周期管理非常重要,不當(dāng)使用會(huì)導(dǎo)致資源泄漏。
5.1 SqlSession的三個(gè)階段
// 方式1:默認(rèn)創(chuàng)建
SqlSession session = sqlSessionFactory.openSession();
// 方式2:自動(dòng)提交
SqlSession session = sqlSessionFactory.openSession(true);
// 方式3:指定Executor類型
SqlSession session = sqlSessionFactory.openSession(
ExecutorType.BATCH);
// 方式4:事務(wù)隔離級(jí)別
SqlSession session = sqlSessionFactory.openSession(
TransactionIsolationLevel.READ_COMMITTED);
try (SqlSession session = factory.openSession()) {
// 執(zhí)行查詢
User user = session.selectOne(
"com.example.mapper.UserMapper.selectById", 1);
// 執(zhí)行更新
User updateUser = new User();
updateUser.setId(1);
updateUser.setName("張三");
session.update(
"com.example.mapper.UserMapper.update", updateUser);
// 提交事務(wù)
session.commit();
}
// 推薦方式:try-with-resources
try (SqlSession session = factory.openSession()) {
// 使用session
} // 自動(dòng)關(guān)閉
// 傳統(tǒng)方式
SqlSession session = null;
try {
session = factory.openSession();
// 使用session
} finally {
if (session != null) {
session.close();
}
}
重要原則:SqlSession的作用域應(yīng)該是方法級(jí)別的!
// 錯(cuò)誤:SqlSession作為成員變量
public class UserService {
private SqlSession session; // ? 不要這樣做!
public User getUserById(int id) {
return session.selectOne(
"com.example.mapper.UserMapper.selectById", id);
}
}
// 正確:SqlSession在方法中創(chuàng)建和關(guān)閉
public class UserService {
private SqlSessionFactory factory;
public User getUserById(int id) {
try (SqlSession session = factory.openSession()) {
return session.selectOne(
"com.example.mapper.UserMapper.selectById", id);
}
}
}
5.2 線程安全問題
SqlSession不是線程安全的,每個(gè)線程都應(yīng)該有自己的SqlSession實(shí)例!
public class UserService {
// ? 多個(gè)線程共享同一個(gè)SqlSession
private SqlSession session = factory.openSession();
}
public class UserService {
private SqlSessionFactory factory;
public User getUserById(int id) {
// ? 每次調(diào)用都創(chuàng)建新的SqlSession
try (SqlSession session = factory.openSession()) {
return session.selectOne("...", id);
}
}
}
5.3 ThreadLocal管理模式
在某些場(chǎng)景下,可以使用ThreadLocal管理SqlSession:
public class SqlSessionManager {
private static final ThreadLocal<SqlSession> LOCAL_SESSION
= new ThreadLocal<>();
private static SqlSessionFactory factory;
// 獲取當(dāng)前線程的SqlSession
public static SqlSession getSession() {
SqlSession session = LOCAL_SESSION.get();
if (session == null) {
session = factory.openSession();
LOCAL_SESSION.set(session);
}
return session;
}
// 關(guān)閉當(dāng)前線程的SqlSession
public static void closeSession() {
SqlSession session = LOCAL_SESSION.get();
if (session != null) {
session.close();
LOCAL_SESSION.remove();
}
}
}

六、事務(wù)控制機(jī)制
SqlSession提供了完善的事務(wù)控制機(jī)制。
6.1 自動(dòng)提交 vs 手動(dòng)提交
// 不自動(dòng)提交(默認(rèn))
SqlSession session = factory.openSession();
session.insert("...");
session.commit(); // 需要手動(dòng)提交
//自動(dòng)提交
SqlSession session = factory.openSession(true);
session.insert("..."); // 自動(dòng)提交
6.2 手動(dòng)事務(wù)控制實(shí)戰(zhàn)
try (SqlSession session = factory.openSession()) {
try {
// 1.插入用戶
User user = new User();
user.setName("張三");
user.setEmail("zhangsan@example.com");
session.insert(
"com.example.mapper.UserMapper.insert", user);
//2.插入訂單
Order order = new Order();
order.setUserId(user.getId());
order.setAmount(100.0);
session.insert(
"com.example.mapper.OrderMapper.insert", order);
//3.提交事務(wù)
session.commit();
} catch (Exception e) {
//4.回滾事務(wù)
session.rollback();
throw e;
}
}
6.3 事務(wù)隔離級(jí)別
MyBatis支持設(shè)置事務(wù)隔離級(jí)別:
SqlSession session = factory.openSession(
TransactionIsolationLevel.READ_COMMITTED);
支持的隔離級(jí)別:
| 隔離級(jí)別 | 說明 | 適用場(chǎng)景 |
|---|---|---|
| NONE | 無事務(wù)隔離 | 不推薦 |
| READ_UNCOMMITTED | 讀未提交 | 極少使用 |
| READ_COMMITTED | 讀已提交 | 大多數(shù)數(shù)據(jù)庫默認(rèn) |
| REPEATABLE_READ | 可重復(fù)讀 | MySQL默認(rèn) |
| SERIALIZABLE | 串行化 | 最高隔離級(jí)別 |
6.4 批量操作的事務(wù)控制
try (SqlSession session = factory.openSession(
ExecutorType.BATCH, false)) {
try {
UserMapper mapper = session.getMapper(UserMapper.class);
// 批量插入
for (int i = 0; i < 1000; i++) {
User user = new User();
user.setName("User" + i);
user.setEmail("user" + i + "@example.com");
mapper.insert(user);
}
// 統(tǒng)一提交
session.commit();
} catch (Exception e) {
session.rollback();
throw e;
}
}

七、SqlSession與Mapper集成
SqlSession與Mapper接口的集成是MyBatis最常用的方式。
7.1 定義Mapper接口
public interface UserMapper {
User selectById(@Param("id") Integer id);
List<User> selectAll();
int insert(User user);
int update(User user);
int deleteById(@Param("id") Integer id);
}
7.2 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.UserMapper">
<resultMap id="BaseResultMap"
type="com.example.entity.User">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="name" property="name"
jdbcType="VARCHAR"/>
<result column="email" property="email"
jdbcType="VARCHAR"/>
</resultMap>
<select id="selectById" resultMap="BaseResultMap">
SELECT id, name, email, age
FROM t_user
WHERE id = #{id}
</select>
<insert id="insert" parameterType="com.example.entity.User"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO t_user (name, email, age)
VALUES (#{name}, #{email}, #{age})
</insert>
</mapper>
7.3 通過SqlSession獲取Mapper
try (SqlSession session = factory.openSession()) {
// 獲取Mapper代理對(duì)象
UserMapper mapper = session.getMapper(UserMapper.class);
//調(diào)用Mapper方法
User user = mapper.selectById(1);
//插入數(shù)據(jù)
User newUser = new User();
newUser.setName("李四");
newUser.setEmail("lisi@example.com");
mapper.insert(newUser);
//提交事務(wù)
session.commit();
}
7.4 MapperProxy工作原理
MyBatis通過JDK動(dòng)態(tài)代理為Mapper接口生成代理對(duì)象:
public class MapperProxy<T> implements InvocationHandler {
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
// 如果是Object類的方法,直接執(zhí)行
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
// 獲取Mapper方法
final MapperMethod mapperMethod =
cachedMapperMethod(method);
// 執(zhí)行Mapper方法
return mapperMethod.execute(sqlSession, args);
}
}

八、Executor執(zhí)行器詳解
Executor是SqlSession的核心組件,負(fù)責(zé)實(shí)際執(zhí)行SQL語句。
8.1 三種Executor類型
// 默認(rèn)的Executor,每次執(zhí)行都會(huì)創(chuàng)建新的Statement SqlSession session = factory.openSession(ExecutorType.SIMPLE);
特點(diǎn):簡單直接,每次創(chuàng)建新Statement
適用場(chǎng)景:一般查詢、單條操作
// 重用Statement,減少創(chuàng)建開銷 SqlSession session = factory.openSession(ExecutorType.REUSE);
特點(diǎn):重用Statement,減少創(chuàng)建開銷
適用場(chǎng)景:執(zhí)行相同SQL多次
// 批量執(zhí)行SQL,性能最高 SqlSession session = factory.openSession(ExecutorType.BATCH);
特點(diǎn):批量執(zhí)行,性能最優(yōu)
適用場(chǎng)景:批量插入、更新
8.2 Executor對(duì)比表
| Executor類型 | 性能 | Statement復(fù)用 | 適用場(chǎng)景 |
|---|---|---|---|
| SIMPLE | ??? | ? | 一般查詢 |
| REUSE | ???? | ? | 相同SQL多次執(zhí)行 |
| BATCH | ????? | ? | 批量操作 |
8.3 實(shí)戰(zhàn)示例
//BATCH執(zhí)行器批量插入示例
try (SqlSession session = factory.openSession(
ExecutorType.BATCH)) {
UserMapper mapper = session.getMapper(UserMapper.class);
for (int i = 0; i < 1000; i++) {
User user = new User();
user.setName("User" + i);
mapper.insert(user);
}
// 批量提交
session.commit();
}
九、最佳實(shí)踐
9.1 SqlSession使用黃金法則
? 及時(shí)關(guān)閉 — 使用try-with-resources確保資源釋放
? 方法作用域 — SqlSession應(yīng)該在方法級(jí)別創(chuàng)建和關(guān)閉
? 線程獨(dú)立 — 每個(gè)線程使用獨(dú)立的SqlSession
? 事務(wù)控制 — 明確提交或回滾事務(wù)
? 異常處理 — 捕獲異常并回滾事務(wù)
9.2 Spring集成最佳實(shí)踐
在Spring中使用MyBatis時(shí),SqlSession由容器管理:
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional
public void createUser(User user) {
// SqlSession由Spring管理,無需手動(dòng)關(guān)閉
userMapper.insert(user);
}
}
9.3 常見問題排查
// 錯(cuò)誤示例
SqlSession session = factory.openSession();
User user = session.selectOne("...");
//忘記關(guān)閉 → 資源泄漏
//正確示例
try (SqlSession session = factory.openSession()) {
User user = session.selectOne("...");
} // 自動(dòng)關(guān)閉
// 錯(cuò)誤示例
try (SqlSession session = factory.openSession()) {
session.insert("...");
// 忘記提交 → 數(shù)據(jù)未保存
}
//正確示例
try (SqlSession session = factory.openSession()) {
session.insert("...");
session.commit(); // 記得提交
}
//錯(cuò)誤示例
private SqlSession session = factory.openSession();
//正確示例
public User getUserById(Integer id) {
try (SqlSession session = factory.openSession()) {
return session.selectOne("...", id);
}
}
十、總結(jié)
通過本文的學(xué)習(xí),我們深入了解了MyBatis會(huì)話模塊的核心內(nèi)容:
SqlSession接口 — 定義了所有數(shù)據(jù)庫操作方法
SqlSessionFactory — 負(fù)責(zé)創(chuàng)建和管理SqlSession實(shí)例
生命周期管理 — 方法級(jí)別創(chuàng)建,線程獨(dú)立使用
事務(wù)控制 — 支持手動(dòng)提交和自動(dòng)提交兩種模式
Mapper集成 — 通過動(dòng)態(tài)代理實(shí)現(xiàn)類型安全操作
Executor類型 — SIMPLE、REUSE、BATCH各有千秋
到此這篇關(guān)于MyBatis會(huì)話模塊詳解的文章就介紹到這了,更多相關(guān)MyBatis會(huì)話模塊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot結(jié)合JWT登錄權(quán)限控制的實(shí)現(xiàn)
本文主要介紹了SpringBoot結(jié)合JWT登錄權(quán)限控制的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
Spring Boot開啟虛擬線程ScopedValue上下文傳遞的使用方式
本文給大家介紹了ScopedValue在Java虛擬線程中的應(yīng)用,解決了傳統(tǒng)ThreadLocal在大量短生命周期線程場(chǎng)景下的問題,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2026-02-02
基于IDEA 的遠(yuǎn)程調(diào)試 Weblogic的操作過程
這篇文章主要介紹了基于IDEA 的遠(yuǎn)程調(diào)試 Weblogic的操作過程,本文通過圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-09-09

