日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
深入理解Spring事務(wù):入門、使用、原理

?大家好,我是樹哥。

Spring 事務(wù)是復(fù)雜一致性業(yè)務(wù)必備的知識點(diǎn),掌握好 Spring 事務(wù)可以讓我們寫出更好地代碼。這篇文章我們將介紹 Spring 事務(wù)的誕生背景,從而讓我們可以更清晰地了解 Spring 事務(wù)存在的意義。

接著,我們會介紹如何快速使用 Spring 事務(wù)。接著,我們會介紹 Spring 事務(wù)的一些特性,從而幫助我們更好地使用 Spring 事務(wù)。最后,我們會總結(jié)一些 Spring 事務(wù)常見的問題,避免大家踩坑。

Spring 事務(wù) - 思維導(dǎo)圖

誕生背景

當(dāng)我們聊起事務(wù)的時候,我們需要明白「事務(wù)」這個詞代表著什么。

事務(wù)其實(shí)是一個并發(fā)控制單位,是用戶定義的一個操作序列,這些操作要么全部完成,要不全部不完成,是一個不可分割的工作單位。事務(wù)有 ACID 四個特性,即:

  • Atomicity(原子性):事務(wù)中的所有操作,或者全部完成,或者全部不完成,不會結(jié)束在中間某個環(huán)節(jié)。
  • 一致性(Consistency):在事務(wù)開始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫的完整性沒有被破壞。
  • 事務(wù)隔離(Isolation):多個事務(wù)之間是獨(dú)立的,不相互影響的。
  • 持久性(Durability):事務(wù)處理結(jié)束后,對數(shù)據(jù)的修改就是永久的,即便系統(tǒng)故障也不會丟失。

而我們說的 Spring 事務(wù),其實(shí)是事務(wù)在 Spring 中的實(shí)現(xiàn)。

明白了什么是事務(wù)之后,我們來聊聊:為什么要有 Spring 事務(wù)?

為了解釋清楚這個問題,我們舉個簡單的例子:銀行里樹哥要給小黑轉(zhuǎn) 1000 塊錢,這時候會有兩個必要的操作:

  • 將樹哥的賬戶余額減少 1000 元。
  • 將小黑的賬戶余額增加 1000 元。

這兩個操作,要么一起都完成,要么都不完成。如果其中某個成功,另外一個失敗,那么就會出現(xiàn)嚴(yán)重的問題。而我們要保證這個操作的原子性,就必須通過 Spring 事務(wù)來完成,這就是 Spring 事務(wù)存在的原因。

如果你深入了解過 MySQL 事務(wù),那么你應(yīng)該知道:MySQL 默認(rèn)情況下,對于所有的單條語句都作為一個單獨(dú)的事務(wù)來執(zhí)行。我們要使用 MySQL 事務(wù)的時候,可以通過手動提交事務(wù)來控制事務(wù)范圍。Spring 事務(wù)的本質(zhì),其實(shí)就是通過 Spring AOP 切面技術(shù),在合適的地方開啟事務(wù),接著在合適的地方提交事務(wù)或回滾事務(wù),從而實(shí)現(xiàn)了業(yè)務(wù)編程層面的事務(wù)操作。

使用指南

Spring 事務(wù)支持兩種使用方式,分別是:聲明式事務(wù)(注解方式)、編程式事務(wù)(代碼方式)。一般來說,我們使用聲明式事務(wù)比較多,這里我們就演示聲明式事務(wù)的使用方法。

項(xiàng)目準(zhǔn)備

為了較好地進(jìn)行講解,我們需要搭建一個具備數(shù)據(jù)庫 CURD 功能的項(xiàng)目,并創(chuàng)建 tablea 和 tableb 兩張表。

首先,創(chuàng)建 tablea 和 tableb 兩張表,兩張表都只有 id 和 name 兩列,建表語句如下圖所示。

CREATE TABLE `tablea` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1;
CREATE TABLE `tableb` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1;

接著,創(chuàng)建一個 SpringBoot 項(xiàng)目,隨后加入 MyBatis 及 MySQL 的 POM 依賴。


mysql
mysql-connector-java


org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.0

最后,我們創(chuàng)建對應(yīng)的 controller 接口、service 接口、mapper 接口,代碼如下所示。

創(chuàng)建 controller 接口:

@SpringBootApplication
@RestController
@RequestMapping("/api")
public class SpringTransactionController {

@Autowired
private TransactionServiceA transactionServiceA;

@RequestMapping("/spring-transaction")
public String testTransaction() {
transactionServiceA.methodA();
return "SUCCESS";
}
}

創(chuàng)建 TableService 接口。

public interface TableService {
void insertTableA(TableEntity tableEntity);
void insertTableB(TableEntity tableEntity);
}

創(chuàng)建 Service 接口實(shí)現(xiàn)類 TransactionServiceA 類,在 methodA () 方法中先往 tablea 表格插入一條數(shù)據(jù),隨后會調(diào)用 TransactionServiceB 服務(wù)的 methodB () 方法。

@Service
public class TransactionServiceA {

@Autowired
private TableService tableService;

@Autowired
private TransactionServiceB transactionServiceB;

public void methodA(){
System.out.println("methodA");
tableService.insertTableA(new TableEntity());
transactionServiceB.methodB();
}
}

創(chuàng)建 TransactionServiceB 類實(shí)現(xiàn),在 methodB () 方法中往 tableb 表格插入一條數(shù)據(jù)。

@Service
public class TransactionServiceB {

@Autowired
private TableService tableService;

public void methodB(){
System.out.println("methodB");
tableService.insertTableB(new TableEntity());
}
}

創(chuàng)建 Mapper 接口方法:

@Mapper
public interface TableMapper {
@Insert("INSERT INTO tablea(id, name) " +
"VALUES(#{id}, #{name})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insertTableA(TableEntity tableEntity);

@Insert("INSERT INTO tableb(id, name) " +
"VALUES(#{id}, #{name})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insertTableB(TableEntity tableEntity);
}

數(shù)據(jù)庫表對應(yīng)的 TableEntity:

@Data
public class TableEntity {
private static final long serialVersionUID = 1L;

private Long id;

private String name;

public TableEntity() {
}

public TableEntity(String name) {
this.name = name;
}
}

最后,我們在配置文件中配置好數(shù)據(jù)庫地址:

spring:
datasource:
url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
# MyBatis 配置
mybatis:
type-aliases-package: tech.shuyi.javacodechip.spring_transaction.model
configuration:
map-underscore-to-camel-case: true

最后,我們運(yùn)行 SpringBoot 項(xiàng)目。通過瀏覽器訪問地址:localhost:8080/api/spring-transaction,正常的話應(yīng)該是接口請求成功。

查看數(shù)據(jù)庫表,會看到 tablea 和 tableb 都插入了一條數(shù)據(jù)。

到這里,我們用于測試 Spring 事務(wù)的 Demo 就準(zhǔn)備完畢了!

快速入門

使用聲明式事務(wù)的方法很簡單,其實(shí)就是在 Service 層對應(yīng)方法上配置 @Transaction 注解即可。

假設(shè)我們的業(yè)務(wù)需求是:往 tablea 和 tableb 插入的數(shù)據(jù),要么都完成,要么都不完成。

這時候,我們應(yīng)該怎么操作呢?

首先,我們需要在 TransactionServiceA 類的 methodA () 方法上配置 @Transaction? 注解,同時也在 TransactionServiceB 類的 methodB () 方法上配置 @Transaction 注解。修改之后的 TransactionServiceA 和 TransactionServiceB 代碼如下所示。

// TransactionServiceA
@Transactional
public void methodA(){
System.out.println("methodA");
tableService.insertTableA(new TableEntity());
transactionServiceB.methodB();
}
// TransactionServiceB
@Transactional
public void methodB(){
System.out.println("methodB");
tableService.insertTableB(new TableEntity());
throw new RuntimeException();
}

可以看到,我們在 methodB () 中模擬了業(yè)務(wù)異常,我們看看是否 tablea 和 tableb 都沒有插入數(shù)據(jù)。

修改之后重新啟動項(xiàng)目,此時我們繼續(xù)訪問地址:localhost:8080/api/spring-transaction,我們會發(fā)現(xiàn)執(zhí)行錯誤,并且控制臺也報錯了。

這時候我們查看數(shù)據(jù)庫,會發(fā)現(xiàn) tablea 和 tableb 都沒有插入數(shù)據(jù)。這說明事務(wù)起作用了。

事務(wù)傳播類型

事務(wù)傳播類型,指的是事務(wù)與事務(wù)之間的交互策略。例如:在事務(wù)方法 A 中調(diào)用事務(wù)方法 B,當(dāng)事務(wù)方法 B 失敗回滾時,事務(wù)方法 A 應(yīng)該如何操作?這就是事務(wù)傳播類型。Spring 事務(wù)中定義了 7 種事務(wù)傳播類型,分別是:REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED。其中最常用的只有 3 種,即:REQUIRED、REQUIRES_NEW、NESTED。

針對事務(wù)傳播類型,我們要弄明白的是 4 個點(diǎn):

  • 子事務(wù)與父事務(wù)的關(guān)系,是否會啟動一個新的事務(wù)?
  • 子事務(wù)異常時,父事務(wù)是否會回滾?
  • 父事務(wù)異常時,子事務(wù)是否會回滾?
  • 父事務(wù)捕捉異常后,父事務(wù)是否還會回滾?

REQUIRED

REQUIRED 是 Spring 默認(rèn)的事務(wù)傳播類型,該傳播類型的特點(diǎn)是:當(dāng)前方法存在事務(wù)時,子方法加入該事務(wù)。此時父子方法共用一個事務(wù),無論父子方法哪個發(fā)生異?;貪L,整個事務(wù)都回滾。即使父方法捕捉了異常,也是會回滾。而當(dāng)前方法不存在事務(wù)時,子方法新建一個事務(wù)。 為了驗(yàn)證 REQUIRED 事務(wù)傳播類型的特點(diǎn),我們來做幾個測試。

還是上面 methodA 和 methodB 的例子。當(dāng) methodA 不開啟事務(wù),methodB 開啟事務(wù),這時候 methodB 就是獨(dú)立的事務(wù),而 methodA 并不在事務(wù)之中。因此當(dāng) methodB 發(fā)生異?;貪L時,methodA 中的內(nèi)容就不會被回滾。用如下的代碼就可以驗(yàn)證我們所說的。

public void methodA(){
System.out.println("methodA");
tableService.insertTableA(new TableEntity());
transactionServiceB.methodB();
}

@Transactional
public void methodB(){
System.out.println("methodB");
tableService.insertTableB(new TableEntity());
throw new RuntimeException();
}

最終的結(jié)果是:tablea 插入了數(shù)據(jù),tableb 沒有插入數(shù)據(jù),符合了我們的猜想。

當(dāng) methodA 開啟事務(wù),methodB 也開啟事務(wù)。按照我們的結(jié)論,此時 methodB 會加入 methodA 的事務(wù)。此時,我們驗(yàn)證當(dāng)父子事務(wù)分別回滾時,另外一個事務(wù)是否會回滾。

我們先驗(yàn)證第一個:當(dāng)父方法事務(wù)回滾時,子方法事務(wù)是否會回滾?

@Transactional
public void methodA(){
tableService.insertTableA(new TableEntity());
transactionServiceB.methodB();
throw new RuntimeException();
}

@Transactional
public void methodB(){
tableService.insertTableB(new TableEntity());
}

結(jié)果是:talbea 和 tableb 都沒有插入數(shù)據(jù),即:父事務(wù)回滾時,子事務(wù)也回滾了。

我們繼續(xù)驗(yàn)證第二個:當(dāng)子方法事務(wù)回滾時,父方法事務(wù)是否會回滾?

@Transactional
public void methodA(){
tableService.insertTableA(new TableEntity());
transactionServiceB.methodB();
}

@Transactional
public void methodB(){
tableService.insertTableB(new TableEntity());
throw new RuntimeException();
}

結(jié)果是:talbea 和 tableb 都沒有插入數(shù)據(jù),即:子事務(wù)回滾時,父事務(wù)也回滾了。

我們繼續(xù)驗(yàn)證第三個:當(dāng)字方法事務(wù)回滾時,父方法捕捉了異常,父方法事務(wù)是否會回滾?

@Transactional
public void methodA() {
tableService.insertTableA(new TableEntity());
try {
transactionServiceB.methodB();
} catch (Exception e) {
System.out.println("methodb occur exp.");
}
}

@Transactional
public void methodB() {
tableService.insertTableB(new TableEntity());
throw new RuntimeException();
}

結(jié)果是:talbea 和 tableb 都沒有插入數(shù)據(jù),即:子事務(wù)回滾時,父事務(wù)也回滾了。所以說,這也進(jìn)一步驗(yàn)證了我們之前所說的:REQUIRED 傳播類型,它是父子方法共用同一個事務(wù)的。

REQUIRES_NEW

REQUIRES_NEW 也是常用的一個傳播類型,該傳播類型的特點(diǎn)是:無論當(dāng)前方法是否存在事務(wù),子方法都新建一個事務(wù)。此時父子方法的事務(wù)時獨(dú)立的,它們都不會相互影響。但父方法需要注意子方法拋出的異常,避免因子方法拋出異常,而導(dǎo)致父方法回滾。 為了驗(yàn)證 REQUIRES_NEW 事務(wù)傳播類型的特點(diǎn),我們來做幾個測試。

首先,我們來驗(yàn)證一下:當(dāng)父方法事務(wù)發(fā)生異常時,子方法事務(wù)是否會回滾?

@Transactional
public void methodA(){
tableService.insertTableA(new TableEntity());
transactionServiceB.methodB();
throw new RuntimeException();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB(){
tableService.insertTableB(new TableEntity());
}

結(jié)果是:tablea 沒有插入數(shù)據(jù),tableb 插入了數(shù)據(jù),即:父方法事務(wù)回滾了,但子方法事務(wù)沒回滾。這可以證明父子方法的事務(wù)是獨(dú)立的,不相互影響。

下面,我們來看看:當(dāng)子方法事務(wù)發(fā)生異常時,父方法事務(wù)是否會回滾?

@Transactional
public void methodA(){
tableService.insertTableA(new TableEntity());
transactionServiceB.methodB();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB(){
tableService.insertTableB(new TableEntity());
throw new RuntimeException();
}

結(jié)果是:tablea 沒有插入了數(shù)據(jù),tableb 沒有插入數(shù)據(jù)。

從這個結(jié)果來看,貌似是子方法事務(wù)回滾,導(dǎo)致父方法事務(wù)也回滾了。但我們不是說父子事務(wù)都是獨(dú)立的,不會相互影響么?怎么結(jié)果與此相反呢?

其實(shí)是因?yàn)樽臃椒⊕伋隽水惓?,而父方法并沒有做異常捕捉,此時父方法同時也拋出異常了,于是 Spring 就會將父方法事務(wù)也回滾了。如果我們在父方法中捕捉異常,那么父方法的事務(wù)就不會回滾了,修改之后的代碼如下所示。

@Transactional
public void methodA(){
tableService.insertTableA(new TableEntity());
// 捕捉異常
try {
transactionServiceB.methodB();
} catch (Exception e) {
e.printStackTrace();
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB(){
tableService.insertTableB(new TableEntity());
throw new RuntimeException();
}

結(jié)果是:tablea 插入了數(shù)據(jù),tableb 沒有插入數(shù)據(jù)。這正符合我們剛剛所說的:父子事務(wù)是獨(dú)立的,并不會相互影響。

這其實(shí)就是我們上面所說的:父方法需要注意子方法拋出的異常,避免因子方法拋出異常,而導(dǎo)致父方法回滾。因?yàn)槿绻麍?zhí)行過程中發(fā)生 RuntimeException 異常和 Error 的話,那么 Spring 事務(wù)是會自動回滾的。

NESTED

NESTED 也是常用的一個傳播類型,該方法的特性與 REQUIRED 非常相似,其特性是:當(dāng)前方法存在事務(wù)時,子方法加入在嵌套事務(wù)執(zhí)行。當(dāng)父方法事務(wù)回滾時,子方法事務(wù)也跟著回滾。當(dāng)子方法事務(wù)發(fā)送回滾時,父事務(wù)是否回滾取決于是否捕捉了異常。如果捕捉了異常,那么就不回滾,否則回滾。

可以看到 NESTED 與 REQUIRED 的區(qū)別在于:父方法與子方法對于共用事務(wù)的描述是不一樣的,REQUIRED 說的是共用同一個事務(wù),而 NESTED 說的是在嵌套事務(wù)執(zhí)行。這一個區(qū)別的具體體現(xiàn)是:在子方法事務(wù)發(fā)生異常回滾時,父方法有著不同的反應(yīng)動作。

對于 REQUIRED 來說,無論父子方法哪個發(fā)生異常,全都會回滾。而 REQUIRED 則是:父方法發(fā)生異常回滾時,子方法事務(wù)會回滾。而子方法事務(wù)發(fā)送回滾時,父事務(wù)是否回滾取決于是否捕捉了異常。

為了驗(yàn)證 NESTED 事務(wù)傳播類型的特點(diǎn),我們來做幾個測試。

首先,我們來驗(yàn)證一下:當(dāng)父方法事務(wù)發(fā)生異常時,子方法事務(wù)是否會回滾?

@Transactional
public void methodA() {
tableService.insertTableA(new TableEntity());
transactionServiceB.methodB();
throw new RuntimeException();
}
@Transactional(propagation = Propagation.NESTED)
public void methodB() {
tableService.insertTableB(new TableEntity());
}

結(jié)果是:tablea 和 tableb 都沒有插入數(shù)據(jù),即:父子方法事務(wù)都回滾了。這說明父方法發(fā)送異常時,子方法事務(wù)會回滾。

接著,我們繼續(xù)驗(yàn)證一下:當(dāng)子方法事務(wù)發(fā)生異常時,如果父方法沒有捕捉異常,父方法事務(wù)是否會回滾?

@Transactional
public void methodA() {
tableService.insertTableA(new TableEntity());
transactionServiceB.methodB();
}
@Transactional(propagation = Propagation.NESTED)
public void methodB() {
tableService.insertTableB(new TableEntity());
throw new RuntimeException();
}

結(jié)果是:tablea 和 tableb 都沒有插入數(shù)據(jù),即:父子方法事務(wù)都回滾了。這說明子方法發(fā)送異?;貪L時,如果父方法沒有捕捉異常,那么父方法事務(wù)也會回滾。

最后,我們驗(yàn)證一下:當(dāng)子方法事務(wù)發(fā)生異常時,如果父方法捕捉了異常,父方法事務(wù)是否會回滾?

@Transactional
public void methodA() {
tableService.insertTableA(new TableEntity());
try {
transactionServiceB.methodB();
} catch (Exception e) {

}
}
@Transactional(propagation = Propagation.NESTED)
public void methodB() {
tableService.insertTableB(new TableEntity());
throw new RuntimeException();
}

結(jié)果是:tablea 插入了數(shù)據(jù),tableb 沒有插入數(shù)據(jù),即:父方法事務(wù)沒有回滾,子方法事務(wù)回滾了。這說明子方法發(fā)送異?;貪L時,如果父方法捕捉了異常,那么父方法事務(wù)就不會回滾。

看到這里,相信大家已經(jīng)對 REQUIRED、REQUIRES_NEW 和 NESTED 這三個傳播類型有了深入的理解了。最后,讓我們來總結(jié)一下:

事務(wù)傳播類型

特性

REQUIRED

當(dāng)前方法存在事務(wù)時,子方法加入該事務(wù)。此時父子方法共用一個事務(wù),無論父子方法哪個發(fā)生異常回滾,整個事務(wù)都回滾。即使父方法捕捉了異常,也是會回滾。而當(dāng)前方法不存在事務(wù)時,子方法新建一個事務(wù)。

REQUIRES_NEW

無論當(dāng)前方法是否存在事務(wù),子方法都新建一個事務(wù)。此時父子方法的事務(wù)時獨(dú)立的,它們都不會相互影響。但父方法需要注意子方法拋出的異常,避免因子方法拋出異常,而導(dǎo)致父方法回滾。

NESTED

當(dāng)前方法存在事務(wù)時,子方法加入在嵌套事務(wù)執(zhí)行。當(dāng)父方法事務(wù)回滾時,子方法事務(wù)也跟著回滾。當(dāng)子方法事務(wù)發(fā)送回滾時,父事務(wù)是否回滾取決于是否捕捉了異常。如果捕捉了異常,那么就不回滾,否則回滾。

 應(yīng)該怎么用?

看完了事務(wù)的傳播類型,我們對 Spring 事務(wù)又有了深刻的理解。

看到這里,你應(yīng)該也明白:使用事務(wù),不再是簡單地使用 @Transaction 注解就可以,還需要根據(jù)業(yè)務(wù)場景,選擇合適的傳播類型。那么我們再升華一下使用 Spring 事務(wù)的方法論。一般來說,使用 Spring 事務(wù)的步驟為:

根據(jù)業(yè)務(wù)場景,分析要達(dá)成的事務(wù)效果,確定使用的事務(wù)傳播類型。

在 Service 層使用 @Transaction 注解,配置對應(yīng)的 propogation 屬性。

下次遇到要使用事務(wù)的情況,記得按照這樣的步驟去做哦~

Spring 事務(wù)失效

什么時候 Spring 事務(wù)會失效?

若同一類中的其他沒有 @Transactional 注解的方法內(nèi)部調(diào)用有 @Transactional 注解的方法,有 @Transactional 注解的方法的事務(wù)會失效。

這是由于 Spring AOP 代理的原因造成的,因?yàn)橹挥挟?dāng) @Transactional 注解的方法在類以外被調(diào)用的時候,Spring 事務(wù)管理才生效。

另外,如果直接調(diào)用,不通過對象調(diào)用,也是會失效的。因?yàn)?Spring 事務(wù)是通過 AOP 實(shí)現(xiàn)的。

@Transactional 注解只有作用到 public 方法上事務(wù)才生效。

被 @Transactional 注解的方法所在的類必須被 Spring 管理。

底層使用的數(shù)據(jù)庫必須支持事務(wù)機(jī)制,否則不生效。

彩蛋

Spring 事務(wù)執(zhí)行過程中,如果拋出非 RuntimeException 和非 Error 錯誤的其他異常,那么是不會回滾的哦。例如下面的代碼執(zhí)行后,tablea 和 tableb 兩個表格,都會插入一條數(shù)據(jù)。

@Transactional
public void methodA() throws Exception {
tableService.insertTableA(new TableEntity());
transactionServiceB.methodB();
}
@Transactional
public void methodB() throws Exception {
tableService.insertTableB(new TableEntity());
// 非 RuntimeException
throw new Exception();
}

參考資料

  • 咱們從頭到尾說一次 Spring 事務(wù)管理(器) - SegmentFault 思否
  • 【技術(shù)干貨】Spring 事務(wù)原理一探 - 知乎
  • Spring 事務(wù)詳解 | JavaGuide
  • 事務(wù)之六:spring 嵌套事務(wù) - duanxz - 博客園
  • 例子很詳細(xì),不錯!VIP!NESTED 區(qū)別!spring 事務(wù)傳播行為詳解 - 雙間 - 博客園
  • Spring Boot 實(shí)戰(zhàn) —— MyBatis(注解版)使用方法 | Michael 翔
  • 記一次事務(wù)的坑 Transaction rolled back because it has been marked as rollback-only - 云揚(yáng)四海?

名稱欄目:深入理解Spring事務(wù):入門、使用、原理
分享URL:http://www.5511xx.com/article/cddhcsp.html