事務(wù)在項目里也是不可或缺的一部分朵栖,建議形成一個統(tǒng)一的事務(wù)管理規(guī)范责循,不要出現(xiàn)讓程序員根據(jù)業(yè)務(wù)自行添加撮珠,團隊成員能力有高有低,很容易就出現(xiàn)需要事務(wù)時沒添加事務(wù)塌忽,這種問題又很難測試出來拍埠,運行時卻會不定時出現(xiàn)數(shù)據(jù)的不一致土居。
想實現(xiàn)類似原spring項目里通過aop方式配置事務(wù)的效果,各種嘗試棉圈,目前還未找到十分可行的方式迄损。測試可用的事務(wù)配置方式有兩種:在service上添加@Transactional注解 和 引入xml配置文件(不推薦)账磺,建議使用@Transactional注解來進行事務(wù)配置垮抗。
1冒版、@Transactional實現(xiàn)事務(wù)
spring boot項目內(nèi)使用事務(wù)最簡單直接的方式就是在每個service類上添加@Transactional注解,即可自動開啟對事務(wù)的支持捆等,不需要進行額外操作。
@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED)
該注解也可添加在方法上谒养,對事物進行更精細化的管理明郭,注意引用spring包下的薯定,不要引用javax包下的话侄。
2、引入xml配置實現(xiàn)事務(wù)
1径簿、 創(chuàng)建com.onecoderspace.transaction.xml文件
<?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:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd"
default-lazy-init="false" default-autowire="no">
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" />
<!-- 對于service使用annotation聲明事物 -->
<tx:annotation-driven mode="proxy" proxy-target-class="true" transaction-manager="transactionManager" order="100" />
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insert*" isolation="REPEATABLE_READ" />
<tx:method name="save*" isolation="REPEATABLE_READ" />
<tx:method name="update*" isolation="REPEATABLE_READ" />
<tx:method name="del*" isolation="REPEATABLE_READ" />
<tx:method name="do*" isolation="REPEATABLE_READ" />
<tx:method name="*" isolation="REPEATABLE_READ" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true">
<aop:advisor pointcut="execution(* com.onecoderspace..*.service..*.*(..))" advice-ref="txAdvice" order="200" />
</aop:config>
</beans>
2锄贷、引入xml配置文件
@Configuration
@ImportResource("classpath:com.onecoderspace.transaction.xml")
public class AopTransactionConfig {
}
3谊却、小結(jié)
- service層需要統(tǒng)一添加事務(wù)哑芹,避免部分人員忘記事務(wù)處理聪姿,在運行過程中導(dǎo)致數(shù)據(jù)不一致末购;
- 在每個service上添加注解實現(xiàn)事務(wù):定好項目整體事務(wù)隔離級別和傳播屬性即可在項目級別形成規(guī)范盟榴,勝在簡單,可執(zhí)行性更高羽德,目前本公司使用該方式;
- 在service方法上添加注解實現(xiàn)事務(wù):事務(wù)管理更靈活银觅,更有針對性究驴,缺點是難以形成統(tǒng)一規(guī)范匀伏,依賴編程人員的經(jīng)驗和能力,如果團隊內(nèi)存在經(jīng)驗不很充足的成員不推薦使用該方式熙侍;
- 通過引入xml配置實現(xiàn)事務(wù):配置簡單蛉抓,在xml內(nèi)一處配置即可實現(xiàn)事務(wù)管理巷送,耦合性更低矛辕;缺點就是使用了xml配置聊品,因此不太推薦使用該方式翻屈;
- 隔離級別(isolation)通常選擇REPEATABLE_READ;傳播屬性通常使用默認值(REQUIRED)即可惊窖。
4爬坑、擴展閱讀
隔離級別(isolation)
隔離級別是指若干個并發(fā)的事務(wù)之間的隔離程度盾计,與我們開發(fā)時候主要相關(guān)的場景包括:臟讀取族铆、重復(fù)讀哥攘、幻讀材鹦。
我們可以看 org.springframework.transaction.annotation.Isolation 枚舉類中定義了五個表示隔離級別的值:
public enum Isolation {
DEFAULT(-1),
READ_UNCOMMITTED(1),
READ_COMMITTED(2),
REPEATABLE_READ(4),
SERIALIZABLE(8);
}
- DEFAULT :這是默認值逝淹,表示使用底層數(shù)據(jù)庫的默認隔離級別。對大部分數(shù)據(jù)庫而言桶唐,通常這值就是: READ_COMMITTED栅葡,mysql5.6默認是REPEATABLE-READ,可以通過select @@tx_isolation查看尤泽。
- READ_UNCOMMITTED :該隔離級別表示一個事務(wù)可以讀取另一個事務(wù)修改但還沒有提交的數(shù)據(jù)欣簇。該級別不能防止臟讀和不可重復(fù)讀,因此很少使用該隔離級別坯约。
- READ_COMMITTED :該隔離級別表示一個事務(wù)只能讀取另一個事務(wù)已經(jīng)提交的數(shù)據(jù)熊咽。該級別可以防止臟讀,這也是大多數(shù)情況下的推薦值闹丐。
- REPEATABLE_READ :該隔離級別表示一個事務(wù)在整個過程中可以多次重復(fù)執(zhí)行某個查詢横殴,并且每次返回的記錄都相同。即使在多次查詢之間有新增的數(shù)據(jù)滿足該查詢妇智,這些新增的記錄也會被忽略滥玷。該級別可以防止臟讀和不可重復(fù)讀。
- SERIALIZABLE :所有的事務(wù)依次逐個執(zhí)行巍棱,這樣事務(wù)之間就完全不可能產(chǎn)生干擾,也就是說蛋欣,該級別可以防止臟讀航徙、不可重復(fù)讀以及幻讀。但是這將嚴重影響程序的性能陷虎。通常情況下也不會用到該級別到踏。
傳播屬性(propagation)
所謂事務(wù)的傳播行為是指,如果在開始當前事務(wù)之前尚猿,一個事務(wù)上下文已經(jīng)存在窝稿,此時有若干選項可以指定一個事務(wù)性方法的執(zhí)行行為。
我們可以看 org.springframework.transaction.annotation.Propagation 枚舉類中定義了6個表示傳播行為的枚舉值:
public enum Propagation {
REQUIRED(0),
SUPPORTS(1),
MANDATORY(2),
REQUIRES_NEW(3),
NOT_SUPPORTED(4),
NEVER(5),
NESTED(6);
}
- REQUIRED :如果當前存在事務(wù)凿掂,則加入該事務(wù)伴榔;如果當前沒有事務(wù)纹蝴,則創(chuàng)建一個新的事務(wù)。
- SUPPORTS :如果當前存在事務(wù)踪少,則加入該事務(wù)塘安;如果當前沒有事務(wù),則以非事務(wù)的方式繼續(xù)運行援奢。
- MANDATORY :如果當前存在事務(wù)兼犯,則加入該事務(wù);如果當前沒有事務(wù)集漾,則拋出異常切黔。
- REQUIRES_NEW :創(chuàng)建一個新的事務(wù),如果當前存在事務(wù)具篇,則把當前事務(wù)掛起纬霞。
- NOT_SUPPORTED :以非事務(wù)方式運行,如果當前存在事務(wù)栽连,則把當前事務(wù)掛起险领。
- NEVER :以非事務(wù)方式運行,如果當前存在事務(wù)秒紧,則拋出異常绢陌。
- NESTED :如果當前存在事務(wù),則創(chuàng)建一個事務(wù)作為當前事務(wù)的嵌套事務(wù)來運行熔恢;如果當前沒有事務(wù)脐湾,則該取值等價于 REQUIRED 。
如有更好實現(xiàn)方式叙淌,敬請指出秤掌。
《spring boot項目實戰(zhàn)》之事務(wù)使用,本人搭建好的spring boot web后端開發(fā)框架已上傳至GitHub鹰霍,歡迎吐槽闻鉴!
https://github.com/q7322068/rest-base,已用于多個正式項目,當前可能因為版本問題不是很完善茂洒,后續(xù)持續(xù)優(yōu)化孟岛,希望你能有所收獲!