前言
在前面的內容,基本已經學習了事務的基本概念以及事務隔離級別等,接下來的幾個小節,將學習怎么使用Spring進行事務管理,在Spring中,對事務進行管理有多種方法,主要分別編程式和聲明式,本小節主要學習編程式事務管理,后面講學習Spring的聲明式事務管理
編程式事務管理
所謂的編程式事務管理,其實就是通過編寫代碼的方式來進行事務管理,也就是通過將事務管理的代碼硬編碼在代碼中從而達到事務管理的作用,不過Spring的事務管理不同于JDBC原始的事務管理,在JDBC中,對事務進行管理首先要關閉自動提交,然后采用手動配置的方式來控制提交以及異常時回滾,而在Spring中,主要是使用Spring的接口來管理,具體如下代碼所示
這里模擬銀行轉賬的業務,正如我們所知道的,轉賬其實就是從一個賬號減去金額并且給另外一個賬號增加對應的金額
Spring配置文件
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
<? xml version = "1.0" encoding = "UTF-8" ?> < beans xmlns = " http://www.springframework.org/schema/beans " xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance " xsi:schemaLocation = " http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd " > <!--開啟自動掃描--> < context:component-scan base-package = "cn.xuhuanfeng.transaction" /> <!--配置數據源,這里采用dbcp--> < bean id = "dataSource" class = "org.apache.commons.dbcp.BasicDataSource" > < property name = "url" value = "jdbc: mysql://localhost:3306/spring " /> < property name = "driverClassName" value = "com.mysql.jdbc.Driver" /> < property name = "username" value = "root" /> < property name = "password" value = "huanfeng" /> </ bean > <!--配置JdbcTemplate--> < bean id = "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate" > <!--注入數據源--> < property name = "dataSource" ref = "dataSource" /> </ bean > <!--配置事務管理--> < bean id = "transactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" > <!--注入數據源--> < property name = "dataSource" ref = "dataSource" /> </ bean > <!--配置事務管理操作類--> < bean id = "transactionTemplate" class = "org.springframework.transaction.support.TransactionTemplate" > <!--注入事務管理--> < property name = "transactionManager" ref = "transactionManager" /> <!--定義事務隔離級別,這里-1代表默認--> < property name = "isolationLevel" value = "-1" /> <!--配置傳播行為,0代表PROPAGATION_REQUIRED--> < property name = "propagationBehavior" value = "0" /> <!--由于進行讀寫操作,所以這里的只讀設置為false,默認也是false,所以可以不用設置--> < property name = "readOnly" value = "false" /> </ bean > </ beans > |
在配置事務隔離級別的時候,由于這里是采用整數的形式,而不是字符串,一開始在配置的時候有點摸不著頭腦,后來查看了對應的源代碼之后,發現了對應的常量,將其記錄如下
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// 事務傳播行為 int PROPAGATION_REQUIRED = 0 ; int PROPAGATION_SUPPORTS = 1 ; int PROPAGATION_MANDATORY = 2 ; int PROPAGATION_REQUIRES_NEW = 3 ; int PROPAGATION_NOT_SUPPORTED = 4 ; int PROPAGATION_NEVER = 5 ; int PROPAGATION_NESTED = 6 ; // 事務隔離級別 int ISOLATION_DEFAULT = - 1 ; int ISOLATION_READ_UNCOMMITTED = 1 ; int ISOLATION_READ_COMMITTED = 2 ; int ISOLATION_REPEATABLE_READ = 4 ; int ISOLATION_SERIALIZABLE = 8 ; int TIMEOUT_DEFAULT = - 1 ; |
持久層代碼如下所示
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@Repository public class AccountDao { @Autowired private JdbcTemplate jdbcTemplate; public void transferIn(String name, double money){ String sql = "update account set money = money + ? where name = ?" ; jdbcTemplate.update(sql, money, name); } public void transferOut(String name, double money){ String sql = "update account set money = money - ? where name = ?" ; jdbcTemplate.update(sql, money, name); } } |
業務層代碼如下所示
1
|
2
3
4
5
6
7
8
9
10
11
12
13
|
@Service public class AccountService { @Autowired private AccountDao accountDao; // 轉賬 public void transfer(String fromName, String toName, double money){ accountDao.transferOut(fromName, money); accountDao.transferIn(toName, money); } } |
對業務層代碼進行檢查測試,可以看到,結果是沒有問題的,也就是轉賬是成功的
如果此時在業務代碼執行過程中發生錯誤或者異常,那么結果會是如何呢
比如說,通過修改transfer代碼,手動模擬異常,如下所示
1
|
2
3
|
accountDao.transferOut(fromName, money); int d = 1 / 0 ; // 除0異常 accountDao.transferIn(toName, money); |
此時運行測試代碼,可以發現,數據出現了不一致,金額已經轉出了,但是由于在轉入之前發生了異常,所以無法轉入,導致了有一部分金額莫名其妙丟失了,這也就是為什么需要進行事務管理了。
對業務層代碼添加事務管理,如下所示
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
@Service public class AccountService { @Autowired private AccountDao accountDao; // 配置事務管理操作類 @Autowired private TransactionTemplate transactionTemplate; public void transfer( final String fromName, final String toName, final double money){ // 通過transactionTemplate進行事務的管理 transactionTemplate.execute( new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { accountDao.transferOut(fromName, money); int d = 1 / 0 ; // 除0異常 accountDao.transferIn(toName, money); } }); } } |
此時再運行代碼,可以發現,不管是有沒有異常,數據的一致性都得到了保證,這也就是說,事務管理起了作用
上面的內容就是使用Spring進行事務管理的一種方式,不過這種方式是不太方便的,因為除了要配置事務管理操作類,也就是TransactionTemplate之外,當需要進行事務管理的時候,還需要在對應的代碼中為其編寫相應的管理代碼,如上所示,所以這種方式在日常的開發中比較少使用。
總結
本小節我們主要學習了如何在Spring配置事務管理器,并且通過編碼的方式,使用Spring的編程式事務管理對業務操作進行事務管理,不過這種方式使用起來不是很方便,所以使用的頻率非常少,接下來的小節我們將學習Spring的聲明式事務管理。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://www.jianshu.com/p/4a716cf71007?utm_source=tuicool&utm_medium=referral