真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Spring+mybatis+mysql使用事物的幾種方法總結(jié)

前言

成都創(chuàng)新互聯(lián)2013年開創(chuàng)至今,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目網(wǎng)站制作、做網(wǎng)站網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元江川做網(wǎng)站,已為上家服務(wù),為江川各地企業(yè)和個人服務(wù),聯(lián)系電話:028-86922220

本文主要記錄下spring是如何支持事物的,以及在Spring結(jié)合mybatis時,可以怎么簡單的實(shí)現(xiàn)數(shù)據(jù)庫的事物功能,下面話不多說了,來一起看看詳細(xì)的介紹吧。

I. 前提

case1:兩張表的的事物支持情況

首先準(zhǔn)備兩張表,一個user表,一個story表,結(jié)構(gòu)如下

CREATE TABLE `user` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `name` varchar(20) NOT NULL DEFAULT '' COMMENT '用戶名',
 `pwd` varchar(26) NOT NULL DEFAULT '' COMMENT '密碼',
 `isDeleted` tinyint(1) NOT NULL DEFAULT '0',
 `created` varchar(13) NOT NULL DEFAULT '0',
 `updated` varchar(13) NOT NULL DEFAULT '0',
 PRIMARY KEY (`id`),
 KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `story` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `userId` int(20) unsigned NOT NULL DEFAULT '0' COMMENT '作者的userID',
 `name` varchar(20) NOT NULL DEFAULT '' COMMENT '作者名',
 `title` varchar(26) NOT NULL DEFAULT '' COMMENT '密碼',
 `story` text COMMENT '故事內(nèi)容',
 `isDeleted` tinyint(1) NOT NULL DEFAULT '0',
 `created` varchar(13) NOT NULL DEFAULT '0',
 `updated` varchar(13) NOT NULL DEFAULT '0',
 PRIMARY KEY (`id`),
 KEY `userId` (`userId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

我們的事物場景在于用戶修改name時,要求兩張表的name都需要一起修改,不允許出現(xiàn)不一致的情況

case2:單表的事物支持

轉(zhuǎn)賬,一個用戶減錢,另一個用戶加錢

CREATE TABLE `money` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `name` varchar(20) NOT NULL DEFAULT '' COMMENT '用戶名',
 `money` int(26) NOT NULL DEFAULT '0' COMMENT '錢',
 `isDeleted` tinyint(1) NOT NULL DEFAULT '0',
 `created` varchar(13) NOT NULL DEFAULT '0',
 `updated` varchar(13) NOT NULL DEFAULT '0',
 PRIMARY KEY (`id`),
 KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

相比上面那個case,這個更加簡單了,下面的實(shí)例則主要根據(jù)這個進(jìn)行說明,至于case1,則留待擴(kuò)展里面進(jìn)行

首先是實(shí)現(xiàn)對應(yīng)的dao和entity

@Data
public class MoneyEntity implements Serializable {
 private static final long serialVersionUID = -7074788842783160025L;
 private int id;
 private String name;
 private int money;
 private int isDeleted;
 private int created;
 private int updated;
}

public interface MoneyDao {
 MoneyEntity queryMoney(@Param("id") int userId);
 // 加錢,負(fù)數(shù)時表示減錢
 int incrementMoney(@Param("id") int userId, @Param("addMoney") int addMoney);
}

對應(yīng)的mapper文件為

<?xml version="1.0" encoding="UTF-8"?>


 
 id, `name`, `money`, `isDeleted`, `created`, `updated`
 

 

 
 update money
 set money=money + #{addMoney}
 where id=#{id}
 

對應(yīng)的mybatis連接數(shù)據(jù)源的相關(guān)配置


 
 classpath*:jdbc.properties
 




 
 
 
 

 

 
 
 
 

 
 

 
 
 
 

 
 




 
 
 





 

II. 實(shí)例演示

通過網(wǎng)上查詢,Spring事物管理總共有四種方式,下面逐一進(jìn)行演示,每種方式是怎么玩的,然后看實(shí)際項(xiàng)目中應(yīng)該如何抉擇

1. 硬編碼方式

編程式事物管理,既通過TransactionTemplate來實(shí)現(xiàn)多個db操作的事物管理

a. 實(shí)現(xiàn)

那么,我們的轉(zhuǎn)賬case可以如下實(shí)現(xiàn)

@Repository
public class CodeDemo1 {
 @Autowired
 private MoneyDao moneyDao;
 @Autowired
 private TransactionTemplate transactionTemplate;
 /**
 * 轉(zhuǎn)賬
 *
 * @param inUserId
 * @param outUserId
 * @param payMoney
 * @param status 0 表示正常轉(zhuǎn)賬, 1 表示內(nèi)部拋出一個異常, 2 表示新開一個線程,修改inUserId的錢 +200, 3 表示新開一個線程,修改outUserId的錢 + 200
 */
 public void transfor(final int inUserId, final int outUserId, final int payMoney, final int status) {
 transactionTemplate.execute(new TransactionCallbackWithoutResult() {
 protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
 MoneyEntity entity = moneyDao.queryMoney(outUserId);
 if (entity.getMoney() > payMoney) { // 可以轉(zhuǎn)賬

 // 先減錢
 moneyDao.incrementMoney(outUserId, -payMoney);

 
 testCase(inUserId, outUserId, status);

 // 再加錢
 moneyDao.incrementMoney(inUserId, payMoney);
 System.out.println("轉(zhuǎn)賬完成! now: " + System.currentTimeMillis());
 }
 }
 });
 }
 
 
 // 下面都是測試用例相關(guān)
 private void testCase(final int inUserId, final int outUserId, final int status) {
 if (status == 1) {
 throw new IllegalArgumentException("轉(zhuǎn)賬異常!!!");
 } else if(status == 2) {
 addMoney(inUserId);
 try {
 Thread.sleep(3000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 } else if (status == 3) {
 addMoney(outUserId);
 try {
 Thread.sleep(3000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
 }


 public void addMoney(final int userId) {
 System.out.printf("內(nèi)部加錢: " + System.currentTimeMillis());
 new Thread(new Runnable() {
 public void run() {
 moneyDao.incrementMoney(userId, 200);
 System.out.println(" sub modify success! now: " + System.currentTimeMillis());
 }
 }).start();
 }
}

主要看上面的transfor方法,內(nèi)部通過 transactionTemplate 來實(shí)現(xiàn)事物的封裝,內(nèi)部有三個db操作,一個查詢,兩個更新,具體分析后面說明

上面的代碼比較簡單了,唯一需要關(guān)注的就是transactionTemplate這個bean如何定義的,xml文件中與前面重復(fù)的就不貼了,直接貼上關(guān)鍵代碼, 一個是根據(jù)DataSource創(chuàng)建的TransactionManager,一個則是根據(jù)TransactionManager創(chuàng)建的TransactionTemplate



 



 

b. 測試用例

正常演示情況, 演示沒有任何異常,不考慮并發(fā)的情況

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath*:spring/service.xml", "classpath*:test-datasource1.xml"})
public class CodeDemo1Test {
 @Autowired
 private CodeDemo1 codeDemo1;

 @Autowired
 private MoneyDao moneyDao;

 @Test
 public void testTransfor() {

 System.out.println("---------before----------");
 System.out.println("id: 1 money = " + moneyDao.queryMoney(1).getMoney());
 System.out.println("id: 2 money = " + moneyDao.queryMoney(2).getMoney());


 codeDemo1.transfor(1, 2, 10, 0);

 System.out.println("---------after----------");
 System.out.println("id: 1 money = " + moneyDao.queryMoney(1).getMoney());
 System.out.println("id: 2 money = " + moneyDao.queryMoney(2).getMoney());
 }
}

輸出如下,兩個賬號的錢都沒有問題

---------before----------
id: 1 money = 10000
id: 2 money = 50000
轉(zhuǎn)賬完成! now: 1526130394266
---------after----------
id: 1 money = 10010
id: 2 money = 49990

轉(zhuǎn)賬過程中出現(xiàn)異常,特別是轉(zhuǎn)賬方錢已扣,收款方還沒收到錢時,也就是case中的status為1的場景

// 內(nèi)部拋異常的情況
@Test
public void testTransforException() {

 System.out.println("---------before----------");
 System.out.println("id: 1 money = " + moneyDao.queryMoney(1).getMoney());
 System.out.println("id: 2 money = " + moneyDao.queryMoney(2).getMoney());


 try {
 codeDemo1.transfor(1, 2, 10, 1);
 } catch (Exception e) {
 e.printStackTrace();
 }

 System.out.println("---------after----------");
 System.out.println("id: 1 money = " + moneyDao.queryMoney(1).getMoney());
 System.out.println("id: 2 money = " + moneyDao.queryMoney(2).getMoney());
}

對此,我們希望把轉(zhuǎn)賬方的錢還回去, 輸出如下,發(fā)現(xiàn)兩個的錢都沒有變化

---------before----------
id: 1 money = 10010
id: 2 money = 49990
---------after----------
id: 1 money = 10010
java.lang.IllegalArgumentException: 轉(zhuǎn)賬異常!!!
 ... // 省略異常信息
id: 2 money = 49990

當(dāng)status為2,表示在轉(zhuǎn)賬人錢已扣,收款人錢沒收到之間,又有人給收款人轉(zhuǎn)了200,此時根據(jù)MySQL的鎖機(jī)制,另外人的轉(zhuǎn)賬應(yīng)該是立馬到的(因?yàn)槭湛钊速~號沒有被鎖?。?,且金額不應(yīng)該有問題

輸出結(jié)果如下:

---------before----------
id: 1 money = 10010
id: 2 money = 49990
## 右邊是注釋: 轉(zhuǎn)賬過程中,另外存錢立馬到賬,沒有被鎖住
內(nèi)部加錢: 1526130827480
sub modify success! now: 1526130827500
## 存錢結(jié)束
轉(zhuǎn)賬完成! now: 1526130830488
---------after----------
id: 1 money = 10220
id: 2 money = 49980

當(dāng)status為3, 表示在轉(zhuǎn)賬人錢已扣,收款人錢沒收到之間,又有人給轉(zhuǎn)賬人轉(zhuǎn)了200,這時因?yàn)檗D(zhuǎn)賬人的記錄以及被加了寫鎖,因此只能等待轉(zhuǎn)賬的事物提交之后,才有可能+200成功,當(dāng)然最終的金額也得一致

輸出結(jié)果如下

---------before----------
id: 1 money = 10220
id: 2 money = 49980
## 右邊是注釋:內(nèi)部存錢了,但沒有馬上成功
## 直到轉(zhuǎn)賬完成后,才立馬存成功,注意兩個時間戳
內(nèi)部加錢: 1526131101046
轉(zhuǎn)賬完成! now: 1526131104051
sub modify success! now: 1526131104053
---------after----------
id: 1 money = 10230
id: 2 money = 50170

c. 小結(jié)

至此,編程式事物已經(jīng)實(shí)例演示ok,從上面的過程,給人的感覺就和直接寫事物相關(guān)的sql一樣,

start transaction;

-- 這中間就是 TransactionTemplate#execute 方法內(nèi)部的邏輯
-- 也就是需要事物管理的一組sql

commit;

2. 基于TransactionProxyFactoryBean方式

接下來的三個就是聲明式事物管理,這種用得也比較少,因?yàn)樾枰總€事物管理類,添加一個TransactionProxyFactoryBean

a. 實(shí)現(xiàn)

除了將 TransactionTemplate 干掉,并將內(nèi)部的sql邏輯移除之外,對比前面的,發(fā)現(xiàn)基本上沒有太多差別

public class FactoryBeanDemo2 {
 @Autowired
 private MoneyDao moneyDao;
 /**
 * 轉(zhuǎn)賬
 *
 * @param inUserId
 * @param outUserId
 * @param payMoney
 * @param status 0 表示正常轉(zhuǎn)賬, 1 表示內(nèi)部拋出一個異常, 2 表示新開一個線程,修改inUserId的錢 +200, 3 表示新開一個線程,修改outUserId的錢 + 200
 */
 public void transfor(final int inUserId, final int outUserId, final int payMoney, final int status) {

 MoneyEntity entity = moneyDao.queryMoney(outUserId);
 if (entity.getMoney() > payMoney) { // 可以轉(zhuǎn)賬

 // 先減錢
 moneyDao.incrementMoney(outUserId, -payMoney);


 testCase(inUserId, outUserId, status);


 // 再加錢
 moneyDao.incrementMoney(inUserId, payMoney);
 System.out.println("轉(zhuǎn)賬完成! now: " + System.currentTimeMillis());
 }


 }


 private void testCase(final int inUserId, final int outUserId, final int status) {
 if (status == 1) {
 throw new IllegalArgumentException("轉(zhuǎn)賬異常!!!");
 } else if (status == 2) {
 addMoney(inUserId);
 try {
 Thread.sleep(3000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 } else if (status == 3) {
 addMoney(outUserId);
 try {
 Thread.sleep(3000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
 }


 public void addMoney(final int userId) {
 System.out.println("內(nèi)部加錢: " + System.currentTimeMillis());
 new Thread(new Runnable() {
 public void run() {
 moneyDao.incrementMoney(userId, 200);
 System.out.println("sub modify success! now: " + System.currentTimeMillis());
 }
 }).start();
 }
}

重點(diǎn)來了,主要是需要配置一個 TransactionProxyBeanFactory,我們知道BeanFactory就是我們自己來創(chuàng)建Bean的一種手段,相關(guān)的xml配置如下



 






 
 
 
 
 
 
 
 
 
 PROPAGATION_REQUIRED
 
 
 
 

通過上面的配置,大致可以了解到這個通過TransactionProxyFactoryBean就是創(chuàng)建了一個FactoryBeanDemo2的代理類,這個代理類內(nèi)部封裝好事物相關(guān)的邏輯,可以看做是前面編程式的一種簡單通用抽象

b. 測試

測試代碼與前面基本相同,唯一的區(qū)別就是我們使用的應(yīng)該是上面BeanFactory生成的Bean,而不是直接使用FactoryBeanDemo2

正常演示case:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath*:spring/service.xml", "classpath*:test-datasource2.xml"})
public class FactoryBeanDemo1Test {
 @Resource(name = "factoryBeanDemoProxy")
 private FactoryBeanDemo2 factoryBeanDemo2;
 @Autowired
 private MoneyDao moneyDao;

 @Test
 public void testTransfor() {
 System.out.println("---------before----------");
 System.out.println("id: 1 money = " + moneyDao.queryMoney(1).getMoney());
 System.out.println("id: 2 money = " + moneyDao.queryMoney(2).getMoney());
 factoryBeanDemo2.transfor(1, 2, 10, 0);
 System.out.println("---------after----------");
 System.out.println("id: 1 money = " + moneyDao.queryMoney(1).getMoney());
 System.out.println("id: 2 money = " + moneyDao.queryMoney(2).getMoney());
 }
}

輸出

---------before----------
id: 1 money = 10000
id: 2 money = 50000
轉(zhuǎn)賬完成! now: 1526132058886
---------after----------
id: 1 money = 10010
id: 2 money = 49990

status為1,內(nèi)部異常的情況下,我們希望錢也不會有問題

@Test
public void testTransforException() {
 System.out.println("---------before----------");
 System.out.println("id: 1 money = " + moneyDao.queryMoney(1).getMoney());
 System.out.println("id: 2 money = " + moneyDao.queryMoney(2).getMoney());

 try {
 factoryBeanDemo2.transfor(1, 2, 10, 1);
 } catch (Exception e) {
 System.out.println(e.getMessage());;
 }

 System.out.println("---------after----------");
 System.out.println("id: 1 money = " + moneyDao.queryMoney(1).getMoney());
 System.out.println("id: 2 money = " + moneyDao.queryMoney(2).getMoney());
}

輸出為

---------before----------
id: 1 money = 10010
id: 2 money = 49990
轉(zhuǎn)賬異常!!!
---------after----------
id: 1 money = 10010
id: 2 money = 49990

status為2 時,分析結(jié)果與上面應(yīng)該相同,輸出如下

---------before----------
id: 1 money = 10010
id: 2 money = 49950
內(nèi)部加錢: 1526133325376
sub modify success! now: 1526133325387
轉(zhuǎn)賬完成! now: 1526133328381
---------after----------
id: 1 money = 10220
id: 2 money = 49940

status為3時,輸出

---------before----------
id: 1 money = 10220
id: 2 money = 49940
內(nèi)部加錢: 1526133373466
轉(zhuǎn)賬完成! now: 1526133376476
sub modify success! now: 1526133376480
---------after----------
id: 1 money = 10230
id: 2 money = 50130

c. 小結(jié)

TransactionProxyFactoryBean 的思路就是利用代理模式來實(shí)現(xiàn)事物管理,生成一個代理類,攔截目標(biāo)方法,將一組sql的操作封裝到事物中進(jìn)行;相比較于硬編碼,無侵入,而且支持靈活的配置方式

缺點(diǎn)也顯而易見,每個都要進(jìn)行配置,比較繁瑣

3. xml使用方式

Spring有兩大特點(diǎn),IoC和AOP,對于事物這種情況而言,我們可不可以使用AOP來做呢?

對于需要開啟事物的方法,攔截掉,執(zhí)行前開始事物,執(zhí)行完畢之后提交事物,出現(xiàn)異常時回滾

這樣一看,感覺還是蠻有希望的,而下面兩種姿勢正是這么玩的,因此需要加上aspect的依賴


 org.aspectj
 aspectjweaver
 1.8.7

a. 實(shí)現(xiàn)

java類與第二種完全一致,變動的只有xml


xmlns:tx="http://www.springframework.org/schema/tx" 
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="...
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx.xsd"



 
 
 
 





 
 
 
 

觀察上面的配置,再想想第二種方式,思路都差不多了,但是這種方式明顯更加通用,通過切面和切點(diǎn),可以減少大量的配置

b. 測試

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath*:spring/service.xml", "classpath*:test-datasource3.xml"})
public class XmlBeanTest {
 @Autowired
 private XmlDemo3 xmlDemo;

 @Autowired
 private MoneyDao moneyDao;


 @Test
 public void testTransfor() {

 System.out.println("---------before----------");
 System.out.println("id: 1 money = " + moneyDao.queryMoney(1).getMoney());
 System.out.println("id: 2 money = " + moneyDao.queryMoney(2).getMoney());


 xmlDemo.transfor(1, 2, 10, 0);

 System.out.println("---------after----------");
 System.out.println("id: 1 money = " + moneyDao.queryMoney(1).getMoney());
 System.out.println("id: 2 money = " + moneyDao.queryMoney(2).getMoney());
 }
}

這個測試起來,和一般的寫法就沒啥兩樣了,比第二種的FactoryBean的注入方式簡單點(diǎn)

正常輸出

---------before----------
id: 1 money = 10000
id: 2 money = 50000
轉(zhuǎn)賬完成! now: 1526135301273
---------after----------
id: 1 money = 10010
id: 2 money = 49990

status=1 出現(xiàn)異常時,輸出

---------before----------
id: 1 money = 10010
id: 2 money = 49990
轉(zhuǎn)賬異常!!!
---------after----------
id: 1 money = 10010
id: 2 money = 49990

status=2 轉(zhuǎn)賬過程中,又存錢的場景,輸出,與前面預(yù)期一致

---------before----------
id: 1 money = 10010
id: 2 money = 49990
內(nèi)部加錢: 1526135438403
sub modify success! now: 1526135438421
轉(zhuǎn)賬完成! now: 1526135441410
---------after----------
id: 1 money = 10220
id: 2 money = 49980

status=3 的輸出,與前面預(yù)期一致

---------before----------
id: 1 money = 10220
id: 2 money = 49980
內(nèi)部加錢: 1526135464341
轉(zhuǎn)賬完成! now: 1526135467349
sub modify success! now: 1526135467352
---------after----------
id: 1 money = 10230
id: 2 money = 50170

4. 注解方式

這個就是消滅xml,用注解來做的方式,就是將前面xml中的配置用 @Transactional注解替換

a. 實(shí)現(xiàn)

@Repository
public class AnnoDemo4 {
 @Autowired
 private MoneyDao moneyDao;
 /**
 * 轉(zhuǎn)賬
 *
 * @param inUserId
 * @param outUserId
 * @param payMoney
 * @param status 0 表示正常轉(zhuǎn)賬, 1 表示內(nèi)部拋出一個異常, 2 表示新開一個線程,修改inUserId的錢 +200, 3 表示新開一個線程,修改outUserId的錢 + 200
 *
 *
 * Transactional注解中的的屬性 propagation :事務(wù)的傳播行為 isolation :事務(wù)的隔離級別 readOnly :只讀
 * rollbackFor :發(fā)生哪些異?;貪L noRollbackFor :發(fā)生哪些異常不回滾
 * rollbackForClassName 根據(jù)異常類名回滾
 */
 @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
 public void transfor(final int inUserId, final int outUserId, final int payMoney, final int status) {
 MoneyEntity entity = moneyDao.queryMoney(outUserId);
 if (entity.getMoney() > payMoney) { // 可以轉(zhuǎn)賬
 // 先減錢
 moneyDao.incrementMoney(outUserId, -payMoney);
 testCase(inUserId, outUserId, status);
 // 再加錢
 moneyDao.incrementMoney(inUserId, payMoney);
 System.out.println("轉(zhuǎn)賬完成! now: " + System.currentTimeMillis());
 }
 }

 private void testCase(final int inUserId, final int outUserId, final int status) {
 if (status == 1) {
 throw new IllegalArgumentException("轉(zhuǎn)賬異常!!!");
 } else if (status == 2) {
 addMoney(inUserId);
 try {
 Thread.sleep(3000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 } else if (status == 3) {
 addMoney(outUserId);
 try {
 Thread.sleep(3000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
 }

 private void addMoney(final int userId) {
 System.out.println("內(nèi)部加錢: " + System.currentTimeMillis());
 new Thread(new Runnable() {
 public void run() {
 moneyDao.incrementMoney(userId, 200);
 System.out.println("sub modify success! now: " + System.currentTimeMillis());
 }
 }).start();
 }
}

因此需要在xml中配置,開啟事物注解



 


這樣一看,就更加清晰了,實(shí)際項(xiàng)目中,xml和注解方式也是用得最多的場景了

b. 測試case

和第三種測試case完全相同, 輸出結(jié)果也一樣,直接省略

III. 小結(jié)

上面說了Spring中四種使用事物的姿勢,其中硬編碼方式可能是最好理解的,就相當(dāng)于將我們寫sql中,使用事物的方式直接翻譯成對應(yīng)的java代碼了;而FactoryBean方式相當(dāng)于特殊情況特殊對待,為每個事物來一個代理類來增強(qiáng)事物功能;后面的兩個則原理差不多都是利用事物通知(AOP)來實(shí)現(xiàn),定義切點(diǎn)及相關(guān)信息

編程式:

  • 注入 TransactionTemplate
  • 將利用事物的邏輯封裝到 transactionTemplate#execute方法內(nèi)

代理BeanFactory:

  • 利用 TransactionProxyFactoryBean 為事物相關(guān)類生成代理
  • 使用方通過FactoryBean獲取代理類,作為使用的Bean

xml配置:

  • 利用 tx標(biāo)簽 + aop方式來實(shí)現(xiàn)
  • 標(biāo)簽定義事物通知,內(nèi)部可有較多的配置信息
  • 配置切點(diǎn),切面

注解方式:

  • 在開啟事物的方法or類上添加 @Transactional 注解即可
  • 開啟事物注解 <tx:annotation-driven transaction-manager="transactionManager"/>

IV. 其他

1. 參考

文檔

Spring事務(wù)管理的四種方式

源碼

  • 項(xiàng)目源碼:study-demo  (本地下載)
  • 主要查看包路徑: 事物demo (本地下載)
  • 測試相關(guān)代碼: 測試demo (本地下載)

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對創(chuàng)新互聯(lián)的支持。


文章標(biāo)題:Spring+mybatis+mysql使用事物的幾種方法總結(jié)
瀏覽路徑:http://weahome.cn/article/pdjepi.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部