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

1.2 會(huì)話(huà)模塊的核心職責(zé)
會(huì)話(huà)模塊在MyBatis中承擔(dān)以下核心職責(zé):
? 數(shù)據(jù)庫(kù)操作接口 — 提供insert、update、delete、select等方法
? SqlSession生命周期管理 — 創(chuàng)建、使用、關(guān)閉SqlSession
? 事務(wù)控制 — 管理事務(wù)的開(kāi)啟、提交、回滾
? Mapper管理 — 獲取Mapper接口的代理對(duì)象
? 批量操作支持 — 提供批量執(zhí)行SQL的能力
二、SqlSession接口詳解
SqlSession是MyBatis的核心接口之一,它定義了所有數(shù)據(jù)庫(kù)操作的方法。
2.1 SqlSession核心方法分類(lèi)
// 查詢(xún)單個(gè)對(duì)象
<T> T selectOne(String statement);
<T> T selectOne(String statement, Object parameter);
// 查詢(xún)列表
<E> List<E> selectList(String statement);
<E> List<E> selectList(String statement, Object parameter);
// 查詢(xún)Map
<K, V> Map<K, V> selectMap(String statement, String mapKey);
// 游標(biāo)查詢(xún)
<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. 打開(kāi)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)類(lèi)
MyBatis提供了兩個(gè)主要的SqlSession實(shí)現(xiàn)類(lèi)。
3.1 DefaultSqlSession
DefaultSqlSession是SqlSession的默認(rèn)實(shí)現(xiàn)類(lèi),最常用的實(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使用,也可以作為工廠(chǎng)使用。
public class SqlSessionManager
implements SqlSessionFactory, SqlSession {
private final SqlSessionFactory sqlSessionFactory;
private final SqlSession sqlSessionProxy;
private ThreadLocal<SqlSession> localSqlSession
= new ThreadLocal<>();
// 開(kāi)啟本地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工廠(chǎng)
SqlSessionFactory是創(chuàng)建SqlSession的工廠(chǎng)接口。
4.1 SqlSessionFactory接口方法
public interface SqlSessionFactory {
// 常用方法:打開(kāi)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ù)工廠(chǎng)
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類(lèi)型
SqlSession session = sqlSessionFactory.openSession(
ExecutorType.BATCH);
// 方式4:事務(wù)隔離級(jí)別
SqlSession session = sqlSessionFactory.openSession(
TransactionIsolationLevel.READ_COMMITTED);
try (SqlSession session = factory.openSession()) {
// 執(zhí)行查詢(xún)
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 線(xiàn)程安全問(wèn)題
SqlSession不是線(xiàn)程安全的,每個(gè)線(xiàn)程都應(yīng)該有自己的SqlSession實(shí)例!
public class UserService {
// ? 多個(gè)線(xiàn)程共享同一個(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)前線(xiàn)程的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)前線(xiàn)程的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.插入用戶(hù)
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í)別 | 說(shuō)明 | 適用場(chǎng)景 |
|---|---|---|
| NONE | 無(wú)事務(wù)隔離 | 不推薦 |
| READ_UNCOMMITTED | 讀未提交 | 極少使用 |
| READ_COMMITTED | 讀已提交 | 大多數(shù)數(shù)據(jù)庫(kù)默認(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 通過(guò)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通過(guò)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類(lèi)的方法,直接執(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語(yǔ)句。
8.1 三種Executor類(lèi)型
// 默認(rèn)的Executor,每次執(zhí)行都會(huì)創(chuàng)建新的Statement SqlSession session = factory.openSession(ExecutorType.SIMPLE);
特點(diǎn):簡(jiǎn)單直接,每次創(chuàng)建新Statement
適用場(chǎng)景:一般查詢(xún)、單條操作
// 重用Statement,減少創(chuàng)建開(kāi)銷(xiāo) SqlSession session = factory.openSession(ExecutorType.REUSE);
特點(diǎn):重用Statement,減少創(chuàng)建開(kāi)銷(xiāo)
適用場(chǎng)景:執(zhí)行相同SQL多次
// 批量執(zhí)行SQL,性能最高 SqlSession session = factory.openSession(ExecutorType.BATCH);
特點(diǎn):批量執(zhí)行,性能最優(yōu)
適用場(chǎng)景:批量插入、更新
8.2 Executor對(duì)比表
| Executor類(lèi)型 | 性能 | Statement復(fù)用 | 適用場(chǎng)景 |
|---|---|---|---|
| SIMPLE | ??? | ? | 一般查詢(xún) |
| 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)閉
? 線(xiàn)程獨(dú)立 — 每個(gè)線(xiàn)程使用獨(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管理,無(wú)需手動(dòng)關(guān)閉
userMapper.insert(user);
}
}
9.3 常見(jiàn)問(wèn)題排查
// 錯(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é)
通過(guò)本文的學(xué)習(xí),我們深入了解了MyBatis會(huì)話(huà)模塊的核心內(nèi)容:
SqlSession接口 — 定義了所有數(shù)據(jù)庫(kù)操作方法
SqlSessionFactory — 負(fù)責(zé)創(chuàng)建和管理SqlSession實(shí)例
生命周期管理 — 方法級(jí)別創(chuàng)建,線(xiàn)程獨(dú)立使用
事務(wù)控制 — 支持手動(dòng)提交和自動(dòng)提交兩種模式
Mapper集成 — 通過(guò)動(dòng)態(tài)代理實(shí)現(xiàn)類(lèi)型安全操作
Executor類(lèi)型 — SIMPLE、REUSE、BATCH各有千秋
到此這篇關(guān)于MyBatis會(huì)話(huà)模塊詳解的文章就介紹到這了,更多相關(guān)MyBatis會(huì)話(huà)模塊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IDEA中HTML通過(guò)servlet3.0注解名提交表單到servlet類(lèi)找不到頁(yè)面的問(wèn)題
這篇文章主要介紹了IDEA中HTML通過(guò)servlet3.0注解名提交表單到servlet類(lèi)找不到頁(yè)面的問(wèn)題,本文通過(guò)場(chǎng)景描述及問(wèn)題解析,給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07
springboot實(shí)現(xiàn)rabbitmq消息確認(rèn)的示例代碼
RabbitMQ的消息確認(rèn)有兩種, 一種是消息發(fā)送確認(rèn),第二種是消費(fèi)接收確認(rèn),本文主要介紹了springboot實(shí)現(xiàn)rabbitmq消息確認(rèn)的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09
SpringBoot后端接收數(shù)組對(duì)象的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot后端接收數(shù)組對(duì)象的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
優(yōu)化Java虛擬機(jī)總結(jié)(jvm調(diào)優(yōu))
這篇文章主要介紹了優(yōu)化Java虛擬機(jī)總結(jié)(jvm調(diào)優(yōu)),具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
記一次springboot配置redis項(xiàng)目啟動(dòng)時(shí)的一個(gè)奇怪的錯(cuò)誤
這篇文章主要介紹了spring?boot配置redis項(xiàng)目啟動(dòng)時(shí)的一個(gè)奇怪的錯(cuò)誤,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
jtds1.1連接sqlserver2000測(cè)試示例
這篇文章主要介紹了jtds1.1連接sqlserver2000測(cè)試示例,需要的朋友可以參考下2014-02-02
MyBatis超詳細(xì)講解如何實(shí)現(xiàn)分頁(yè)功能
MyBatis-Plus?是一個(gè)?Mybatis?增強(qiáng)版工具,在?MyBatis?上擴(kuò)充了其他功能沒(méi)有改變其基本功能,為了簡(jiǎn)化開(kāi)發(fā)提交效率而存在,本篇文章帶用它實(shí)現(xiàn)分頁(yè)功能2022-03-03
關(guān)于IDEA創(chuàng)建spark maven項(xiàng)目并連接遠(yuǎn)程spark集群?jiǎn)栴}
這篇文章主要介紹了IDEA創(chuàng)建spark maven項(xiàng)目并連接遠(yuǎn)程spark集群,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08

