spring 之事務管理
標簽: spring事務管理
1、基本概念
事務(Transaction),一般是指要做的或所做的事情。在計算機術語中是指訪問并可能更新數據庫中各種數據項的一個程序執行單元(unit)。
事務應該具有4個屬性:原子性、一致性、隔離性、持久性。這四個屬性通常稱為ACID特性。
2、spring中配置c3p0連接池
(1)mysql
<!-- 配置c3p0連接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///mydb_329"/>
<property name="user" value="root"/>
<property name="password" value=""/>
</bean>
(2)oracle
<!--c3p0連接池配置--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="oracle.jdbc.driver.OracleDriver"/> <property name="jdbcUrl" value="jdbc:oracle:thin:@127.0.0.1:1521:orclht"/> <property name="user" value="hscon"/> <property name="password" value="hscon"/> </bean>
3、spring核心配置文件中完成注入操作
<!--創建jdbcTemplate對象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="bankDao" class="com.spring.dao.BankDao"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <bean id="bankService" class="com.spring.service.BankServcie"> <property name="bankDao" ref="bankDao"></property> </bean>
4、編寫代碼模擬轉賬交易
Dao
public class BankDao { JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public void addBankCount(long id,double money){ String sql="UPDATE hscon.USER_BALANCE SET balance = balance + ? WHERE id = ?"; jdbcTemplate.update(sql,money,id); } public void deductBankCount(long id,double money) throws Exception{ String sql="UPDATE hscon.USER_BALANCE SET balance = balance - ? WHERE id = ?"; jdbcTemplate.update(sql,money,id); } }
Servcice
public class BankServcie { private BankDao bankDao; public void setBankDao(BankDao bankDao) { this.bankDao = bankDao; } //銀行轉賬為例解釋事物 public void transfer(long fromID,long toID,double money) throws Exception{ bankDao.addBankCount(toID,money); bankDao.deductBankCount(fromID,money); } }
測試代碼
public class TestDemo { //測試的方法 public static void main(String args[]){ ApplicationContext ap= new ClassPathXmlApplicationContext("applicationContext.xml"); BankServcie bankService = (BankServcie) ap.getBean("bankService"); try{ bankService.transfer(1,2,10); }catch (Exception e){ e.printStackTrace(); } } }
目錄結構
5、spring聲明式事務處理
(1)實現Spring的事務管理,需要使用到事務管理器(PlatformTransactionManager)。Spring為不同的持久化框架提供了不同的PlatformTransactionManager接口實現。如下:
事務 | 說明 |
---|---|
org.springframework.jdbc.datasource.DataSourceTransactionManager | 使用Spring JDBC或iBatis進行持久化數據時使用 |
org.springframework.orm.hibernate5.HibernateTransactionManager | 使用Hibernate5.0版本進行持久化數據時使用 |
org.springframework.orm.jpa.JpaTransactionManager | 使用JPA進行持久化時使用 |
org.springframework.jdo.JdoTransactionManager | 使用JDO進行持久化時使用 |
org.springframework.transaction.jta.JtaTransactionManager | 使用一個JTA實現來管理事務,在一個事務跨多個資源時必須使用 |
注:在本案例中采用的Spring JDBC操作數據庫,即使用DataSourceTransactionManager
這一事務管理器實現類
(2)配置xml
在項目的Spring核心配置文件中進行配置,如下:
a、配置事務管理器,即配置DataSourceTransactionManager
,設置數據源;
b、配置事務增強;
c、配置切面,定義切入點,應用事務增強。
具體如下:
<!-- 配置事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事務增強 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 設置進行事務操作的方法匹配規則 -->
<!-- name: Service層中需要事務增強的方法名,其中這里表示名稱以transfer開頭的所有方法 -->
<!-- propagation="REQUIRED"代表支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇 -->
<tx:method name="transfer*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<!-- 切入點 -->
<aop:pointcut id="bankPointcut" expression="execution(* com.wm103.tx.BankService.transfer*(..))"/>
<!-- 切面 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="bankPointcut"/>
</aop:config>
(3)事務配置說明
tx:method
的屬性如下:
a. name
,該屬性必須設置值,其值表示與事務關聯的方法(名)。該屬性值可以使用通配符*
,用來指定一批關聯到相同的事務屬性的方法,如get*
、insert*
等。應用事務的方法需要存在滿足該屬性值的tx:method
(事務屬性配置),同時在定義切入點后該方法“受到”事務的增強,才能真正的實現事務;
b. propagation
,默認值為REQUIRED
,事務的傳播行為(所謂事務的傳播行為是指,如果在開始當前事務之前,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執行行為。),包括:REQUIRED
,REQUIRES_NEW
,SUPPORTS
,NOT_SUPPORTED
,NEVER
,MANDATORY
,NESTED
。這些屬性值在TransactionDefinition中也對應定義了如下幾個表示傳播行為的常量:
常量名 | 說明 |
---|---|
PROPAGATION_REQUIRED | 如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務 |
PROPAGATION_REQUIRES_NEW | 創建一個新的事務,如果當前存在事務,則把當前事務掛起 |
PROPAGATION_SUPPORTS | 如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行 |
PROPAGATION_NOT_SUPPORTED | 以非事務方式運行,如果當前存在事務,則把當前事務掛起 |
PROPAGATION_NEVER | 以非事務方式運行,如果當前存在事務,則拋出異常 |
PROPAGATION_MANDATORY | 如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常 |
PROPAGATION_NESTED | 如果當前存在事務,則創建一個事務作為當前事務的嵌套事務來運行;如果當前沒有事務,則該取值等價于TransactionDefinition.PROPAGATION_REQUIRED |
c. isolation
,默認值為DEFAULT
,表示事務隔離級別(事務隔離級別指若干個并發的事務之間的隔離程度),該屬性值默認為對應數據庫設置的隔離級別。具體如下:
隔離級別 | 含義 |
---|---|
DEFAULT | 使用后端數據庫默認的隔離級別(Spring中的選擇項),對大部分數據庫而言,通常這值就是READ_COMMITTED ;但是MySQL的默認隔離級別是REPEATABLE_READ |
READ_UNCOMMITTED | 一個事務可以讀取另一個事務修改但還沒有提交的數據,可能導致臟讀、幻讀、不可重復讀,因此很少使用該隔離級別 |
READ_COMMITTED | 一個事務只能讀取另一個事務已經提交的數據,可防止臟讀,但幻讀和不可重復讀仍可發生,這也是大多數情況下的推薦值 |
REPEATABLE_READ | 一個事務在整個過程中可以多次重復執行某個查詢,并且每次返回的記錄都相同,除非數據被事務本身改變。即使在多次查詢之間有新增的數據滿足該查詢,這些新增的記錄也會被忽略。可防止臟讀、不可重復讀,但幻讀仍可能發生 |
SERIALIZABLE | 所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,完全服從ACID的隔離級別,確保不發生臟讀、幻讀、不可重復讀。這在所有的隔離級別中是最慢的,它是典型地通過完全鎖定在事務中涉及的數據表來完成的,因此通常情況下也不會用到該級別 |
d. timeout
,默認值為-1(表示永不超時),事務超時的時間,單位為秒;
e. read-only
,默認值為false,即事務不是只讀的,該屬性表示事務是否只讀。對于該屬性值,針對事務內均為查詢操作時才可以設置為true,對于增加刪除修改的操作則不允許read-only設置為true。至于該字段的含義或者存在的意義,可以參考如下資料的說明:
百度知道 標題:spring事務管理屬性為只讀是什么意思?
您好
如果你一次執行單條查詢語句,則沒有必要啟用事務支持,數據庫默認支持SQL執行期間的讀一致性;
如果你一次執行多條查詢語句,例如統計查詢,報表查詢,在這種場景下,多條查詢SQL必須保證整體的讀一致性,否則,在前條SQL查詢之后,后條SQL查詢之前,數據被其他用戶改變,則該次整體的統計查詢將會出現讀數據不一致的狀態,此時,應該啟用事務支持read-only=”true”表示該事務為只讀事務,比如上面說的多條查詢的這種情況可以使用只讀事務,
由于只讀事務不存在數據的修改,因此數據庫將會為只讀事務提供一些優化手段,例如Oracle對于只讀事務,不啟動回滾段,不記錄回滾log。
(1)在JDBC中,指定只讀事務的辦法為: connection.setReadOnly(true);
(2)在Hibernate中,指定只讀事務的辦法為: session.setFlushMode(FlushMode.NEVER);
此時,Hibernate也會為只讀事務提供Session方面的一些優化手段;
(3)在Spring的Hibernate封裝中,指定只讀事務的辦法為: bean配置文件中,prop屬性增加“read-Only”或者用注解方式@Transactional(readOnly=true)。Spring中設置只讀事務是利用上面兩種方式(根據實際情況)。
在將事務設置成只讀后,相當于將數據庫設置成只讀數據庫,此時若要進行寫的操作,會出現錯誤。
希望對你有幫助。
我們可以使用上述案例,在配置文件中進行如下修改(即加入read-only屬性的設置,并設置true):
<tx:method name="transfer*" propagation="REQUIRED" read-only="true"/>
原因即設置read-only="true"
后,我們在事務中進行了寫操作,結果拋出異常。
f. rollback-for
,可不設置,表示被觸發進行回滾的異常,設置多個異常類則以逗號分隔,如:com.wm103.MyException,ServletException
;
g. no-rollback-for
,可不設置,表示不被觸發進行回滾的異常,設置多個異常類則以逗號分隔,如:com.wm103.MyException,ServletException
。
涉及到這兩個屬性值,那么這里要對Spring聲明式事務管理的默認回滾規則加以說明。在Spring事務管理中默認的回滾規則為:如果在事務中拋出了未檢查異常(繼承自 RuntimeException 的異常),則默認將回滾事務。如果沒有拋出任何異常,或者拋出了已檢查異常(必檢異常),則仍然提交事務。
為了驗證上述的結論,我們將對上述案例進行修改,修改Service類中的transfer1方法,讓其拋出一個必檢異常,這里我拋出一個IOException,如下:
(實際上,在上述案例中模擬轉賬過程中出現的異常int err = 10 / 0
即為運行異常,測試后,我們可以發現確實事務發生了回滾。)
修改后,再運行測試類的測試方法,我們可以發現用戶A扣錢后,發生異常,到事務并未回滾。為使得發生這樣的異常時也觸發回滾操作,需要設置rollback-for
屬性,如下:
<tx:method name="transfer*" propagation="REQUIRED" rollback-for="Exception"/>
相反地,如果想讓發生運行時異常時不觸發回滾操作,那可以設置屬性no-rollback-for="RuntimeException"
。
(4)完整的spring核心配置文件
<!--c3p0連接池配置--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="oracle.jdbc.driver.OracleDriver"/> <property name="jdbcUrl" value="jdbc:oracle:thin:@127.0.0.1:1521:orclht"/> <property name="user" value="hscon"/> <property name="password" value="hscon"/> </bean> <!--創建jdbcTemplate對象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="bankDao" class="com.spring.dao.BankDao"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <bean id="bankService" class="com.spring.service.BankServcie"> <property name="bankDao" ref="bankDao"></property> </bean> <!-- 配置事務管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 配置事務增強 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 設置進行事務操作的方法匹配規則 --> <!-- name: Service層中需要事務增強的方法名,其中這里表示名稱以transfer開頭的所有方法 --> <!-- propagation="REQUIRED"代表支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇 --> <tx:method name="transfer*" propagation="REQUIRED" no-rollback-for="Exception"/> </tx:attributes> </tx:advice> <!-- 配置切面 --> <aop:config> <!-- 切入點 --> <aop:pointcut id="bankPointcut" expression="execution(* com.spring.service.*.transfer*(..))"/> <!-- 切面 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="bankPointcut"/> </aop:config>
6、spring注解方式實現事務的管理
完整配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--c3p0連接池配置--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="oracle.jdbc.driver.OracleDriver"/> <property name="jdbcUrl" value="jdbc:oracle:thin:@127.0.0.1:1521:orclht"/> <property name="user" value="hscon"/> <property name="password" value="hscon"/> </bean> <!--創建jdbcTemplate對象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="bankDao" class="com.spring.dao.BankDao"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <bean id="bankService" class="com.spring.service.BankServcie"> <property name="bankDao" ref="bankDao"></property> </bean> <!-- 配置事務管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 配置開啟事務注解 --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
在類或者方法上應用@Transactional
注解,如:
import org.springframework.transaction.annotation.Transactional;
//@Transactional
@Transactional(rollbackFor = Exception.class)
public class BankService {
- 1
- 2
- 3
- 4
- 5
或者
@Transactional(rollbackFor = Exception.class)
public void transfer1(final long formId, final long toId, double amount) throws IOException {
因此為修改Spring默認事務的回滾規則,可以設置注解@Transactional
的rollbackFor
為Exception.class
,即@Transactional(rollbackFor = Exception.class)
。同樣地,如果不希望運行時異常觸發回滾操作,可以設置@Transactional(noRollbackFor = RuntimeException.class)
。
@Transactional注意事項
摘錄自“Transactional注解中常用參數說明”一文,鏈接在“知識點擴展或參考”這一部分
1. @Transactional 注解應該只被應用到 public 可見度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不會報錯, 但是這個被注解的方法將不會展示已配置的事務設置。
2. @Transactional 注解可以被應用于接口定義和接口方法、類定義和類的 public 方法上。然而,請注意僅僅 @Transactional 注解的出現不足于開啟事務行為,它僅僅 是一種元數據,能夠被可以識別 @Transactional 注解和上述的配置適當的具有事務行為的beans所使用。上面的例子中,其實正是 元素的出現 開啟 了事務行為。
3. Spring團隊的建議是你在具體的類(或類的方法)上使用 @Transactional 注解,而不要使用在類所要實現的任何接口上。你當然可以在接口上使用 @Transactional 注解,但是這將只能當你設置了基于接口的代理時它才生效。因為注解是 不能繼承 的,這就意味著如果你正在使用基于類的代理時,那么事務的設置將不能被基于類的代理所識別,而且對象也將不會被事務代理所包裝(將被確認為嚴重的)。因此,請接受Spring團隊的建議并且在具體的類上使用 @Transactional 注解。
遇到問題
warning no match for this type name: com.spring.service [Xlint:invalidAbsoluteTypeName]
配置事務時,一定注意expression="execution(* com.zrm.service.*(..))" 應該為
expression="execution(* com.zrm.service.*.*(..))" ,這樣,切點才定位到方法上了
智能推薦
spring事務管理
一、理論儲備 1.1 數據庫事務 數據庫事務有嚴格的定義,一個數據庫事務是一個單一的工作單元操作序列,它必須同時滿足4個特性:原子性(Atomic)、一致性(Consistency)、隔離性(Isolation)、和持久性(Durability),簡稱ACID。 原子性:表示組成一個事務的多個數據庫操作是一個不可分割的單元,只有整個事務操作成功整個事務才提交,否則所有操作回...
Spring事務管理
Spring 事務管理機制 事務的概念和特性 事務:一起成功、一起失敗 什么是事務呢? 事務指的是邏輯上的一組操作,這組操作要么全部成功,要么全部失敗 事務的特性: 原子性、一致性、隔離性、持久性 原子性:原子性是值事務是一個不可分割的工作單位,事務中的操作要么都發生,要么都不發生 一致性:一致性指事務前后數據的完整性必須保持一致 隔離性:隔離性是指多個用戶并發訪問數據庫時,一個用戶的事務不能被其...
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
猜你喜歡
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...
styled-components —— React 中的 CSS 最佳實踐
https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...