怎么理解 Mybatis 的事務(wù)
對(duì)于數(shù)據(jù)庫(kù)事務(wù),我們都不陌生,數(shù)據(jù)庫(kù)的事務(wù)(Transaction)是數(shù)據(jù)庫(kù)管理系統(tǒng)執(zhí)行過(guò)程中的一個(gè)邏輯單位,也是一個(gè)不可分割的工作單位。它包含一個(gè)或多個(gè)SQL語(yǔ)句,這些語(yǔ)句要么全部執(zhí)行,要么全部不執(zhí)行。事務(wù)是一個(gè)原子操作單元,其對(duì)數(shù)據(jù)的修改要么全都執(zhí)行,要么全都不執(zhí)行。那么我們就得來(lái)看看這個(gè) Mybatis 是怎么處理事務(wù)的了。
ACID特性
- 原子性(Atomicity):事務(wù)是一個(gè)原子操作單元,其對(duì)數(shù)據(jù)的修改要么全都執(zhí)行,要么全都不執(zhí)行。
- 一致性(Consistency):事務(wù)必須使數(shù)據(jù)庫(kù)從一個(gè)一致性狀態(tài)變換到另一個(gè)一致性狀態(tài)。
- 隔離性(Isolation):事務(wù)的執(zhí)行不受其他事務(wù)的干擾,事務(wù)執(zhí)行的中間結(jié)果對(duì)其他事務(wù)是不可見(jiàn)的。
- 持久性(Durability):一旦事務(wù)提交,則其結(jié)果就是永久性的,即使系統(tǒng)發(fā)生崩潰,事務(wù)執(zhí)行的結(jié)果也不能丟失。
我們通過(guò)使用事務(wù),可以確保數(shù)據(jù)的完整性和一致性,特別是在多個(gè)用戶(hù)或系統(tǒng)并發(fā)訪問(wèn)和修改數(shù)據(jù)庫(kù)時(shí)。如果沒(méi)有事務(wù),那么在這些并發(fā)操作中可能會(huì)出現(xiàn)數(shù)據(jù)不一致、數(shù)據(jù)丟失或數(shù)據(jù)重復(fù)等問(wèn)題。通過(guò)使用事務(wù),可以鎖定被修改的數(shù)據(jù),直到事務(wù)完成并提交,從而確保數(shù)據(jù)的完整性和一致性。
Mybatis的事務(wù)
MyBatis 的事務(wù)控制可以從以下幾個(gè)方面入手:
(1) 事務(wù)管理機(jī)制的選擇:MyBatis 提供了兩種主要的事務(wù)管理機(jī)制,分別是 JDBC 事務(wù)管理機(jī)制和 MANAGED 事務(wù)管理機(jī)制。
- JDBC 事務(wù)管理機(jī)制:這種機(jī)制利用 java.sql.Connection 對(duì)象來(lái)完成對(duì)事務(wù)的提交(commit())、回滾(rollback())、關(guān)閉(close())等操作。MyBatis 框架自身會(huì)管理事務(wù),采用原生的 JDBC 代碼去管理事務(wù),如設(shè)置 conn.setAutoCommit(false); 來(lái)開(kāi)啟事務(wù),并在業(yè)務(wù)處理完成后手動(dòng)提交事務(wù) conn.commit();。
- MANAGED 事務(wù)管理機(jī)制:在這種機(jī)制下,MyBatis 本身不會(huì)去實(shí)現(xiàn)事務(wù)管理,而是讓程序的容器(如 JBOSS、Weblogic)來(lái)實(shí)現(xiàn)對(duì)事務(wù)的管理。
(2) 事務(wù)的配置:在 MyBatis 的 XML 配置文件中,可以通過(guò)節(jié)點(diǎn)定義連接某個(gè)數(shù)據(jù)庫(kù)的信息,而的 type 屬性決定了使用哪種類(lèi)型的事務(wù)管理機(jī)制。例如,將的 type 配置為 "JDBC" 會(huì)使用 JDBC 事務(wù)管理機(jī)制。
(3) 事務(wù)工廠的創(chuàng)建:MyBatis 的事務(wù)管理依賴(lài)于 TransactionFactory 事務(wù)工廠的創(chuàng)建。根據(jù)的 type 配置和 DataSource 實(shí)例,TransactionFactory 會(huì)創(chuàng)建一個(gè) Environment 對(duì)象,該對(duì)象表示一個(gè)數(shù)據(jù)庫(kù)的連接,并且會(huì)被設(shè)置到 Configuration 實(shí)例中,以供后續(xù)使用。
(4) 業(yè)務(wù)場(chǎng)景的應(yīng)用:在實(shí)際的業(yè)務(wù)場(chǎng)景中,如購(gòu)買(mǎi)操作包含多個(gè)執(zhí)行過(guò)程(查詢(xún)庫(kù)存、下單、更新庫(kù)存)或兩個(gè)患者賬戶(hù)之間的轉(zhuǎn)賬操作,需要確保這些操作作為一個(gè)整體進(jìn)行,要么全部成功,要么全部失敗并回滾。這時(shí)就需要引入事務(wù)控制,保證整個(gè)操作的有效性。
(5) 事務(wù)的邊界管理:合理控制事務(wù)的邊界也是非常重要的。過(guò)寬的事務(wù)邊界可能導(dǎo)致事務(wù)執(zhí)行時(shí)間過(guò)長(zhǎng),影響系統(tǒng)性能;而過(guò)窄的事務(wù)邊界則可能導(dǎo)致數(shù)據(jù)不一致。因此,在設(shè)計(jì)系統(tǒng)時(shí),需要仔細(xì)考慮每個(gè)事務(wù)的邊界。
(6) 異常處理:在事務(wù)執(zhí)行過(guò)程中,如果出現(xiàn)異常,需要根據(jù)異常類(lèi)型和業(yè)務(wù)需求決定是回滾事務(wù)還是進(jìn)行其他處理。確保在出現(xiàn)異常時(shí)能夠正確地處理事務(wù),避免數(shù)據(jù)的不一致和丟失。
如何設(shè)置Mybatis的全局事務(wù)
在 MyBatis 中,全局事務(wù)的設(shè)置通常依賴(lài)于底層的數(shù)據(jù)庫(kù)連接池和事務(wù)管理器。MyBatis 本身并不直接提供全局事務(wù)管理的功能,而是依賴(lài)于 JDBC、Spring 或其他容器提供的事務(wù)管理機(jī)制。下面是一些常見(jiàn)的方法來(lái)設(shè)置 MyBatis 的全局事務(wù):
1. 使用 JDBC 進(jìn)行事務(wù)管理
如果你的應(yīng)用沒(méi)有使用 Spring 或其他容器,你可以直接使用 JDBC 進(jìn)行事務(wù)管理。在 MyBatis 的配置文件中,你可以將事務(wù)管理器設(shè)置為 JDBC。
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!-- 數(shù)據(jù)庫(kù)連接配置 -->
</dataSource>
</environment>
</environments>
<!-- 其他配置 -->
</configuration>
在代碼中,你需要手動(dòng)管理事務(wù)的開(kāi)啟、提交和回滾。
try (SqlSession session = sqlSessionFactory.openSession()) {
// 開(kāi)啟事務(wù)
Connection conn = session.getConnection();
conn.setAutoCommit(false);
// 執(zhí)行業(yè)務(wù)邏輯...
// 提交事務(wù)
conn.commit();
} catch (Exception e) {
// 回滾事務(wù)
try (Connection conn = session.getConnection()) {
if (!conn.isClosed()) {
conn.rollback();
}
} catch (SQLException ex) {
// 處理異常
}
// 處理異常...
}
2. 使用 Spring 管理 MyBatis 事務(wù)
如果你的應(yīng)用使用了 Spring 框架,那么可以利用 Spring 的聲明式事務(wù)管理來(lái)管理 MyBatis 的事務(wù)。這通常是通過(guò)在 Spring 配置文件中配置事務(wù)管理器,并在需要事務(wù)的方法上使用 @Transactional 注解來(lái)實(shí)現(xiàn)的。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- 配置數(shù)據(jù)源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- 數(shù)據(jù)源屬性配置 -->
</bean>
<!-- 配置 SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 其他配置 -->
</bean>
<!-- 配置事務(wù)管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 開(kāi)啟注解事務(wù)管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 其他配置 -->
</beans>
Java 代碼中使用 @Transactional
@Service
public class MyService {
@Autowired
private MyMapper myMapper;
@Transactional
public void myTransactionalMethod() {
// 執(zhí)行業(yè)務(wù)邏輯...
myMapper.updateSomeData();
// 如果拋出異常,則事務(wù)回滾
}
}
在上面的例子中,@Transactional 注解告訴 Spring 在執(zhí)行 myTransactionalMethod 方法時(shí)應(yīng)該開(kāi)啟一個(gè)事務(wù)。如果方法執(zhí)行成功,則事務(wù)提交;如果方法拋出異常,則事務(wù)回滾。
3. 使用其他容器的事務(wù)管理
除了 Spring,還有其他一些容器或框架也提供了事務(wù)管理的功能,如 Java EE 容器。如果你正在使用這些容器或框架,你可以根據(jù)它們的文檔來(lái)配置和管理 MyBatis 的事務(wù)。
- 確保你的數(shù)據(jù)庫(kù)連接池支持事務(wù)。大多數(shù)現(xiàn)代連接池(如 HikariCP、c3p0、DBCP 等)都支持事務(wù)。
- 在使用 Spring 或其他容器管理事務(wù)時(shí),確保你的 MyBatis Mapper 接口或?qū)崿F(xiàn)類(lèi)被正確地掃描和注冊(cè)為 Spring Bean。
- 在使用 @Transactional 注解時(shí),注意其傳播行為(propagation behavior)、隔離級(jí)別(isolation level)等屬性的設(shè)置,以滿足你的業(yè)務(wù)需求。
所以,你對(duì)Mybatis的事務(wù)了解了么?