日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

深入spring事務(wù)管理

 印度阿三17 2018-09-26

Spring事務(wù)的本質(zhì)其實就是數(shù)據(jù)庫對事務(wù)的支持,在沒有spring提供事務(wù)管理之前,純JDBC事務(wù)管理機制是利用java.sql.Connection對象完成對事務(wù)的提交;示例如下:

public static void main(String[] args) throws SQLException {
	//1.獲取連接
	Connection conn = null;
	try {  
		conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/xx_db", "root", "root");
		//2.開啟事務(wù):將自動提交設(shè)置為false   
		conn.setAutoCommit(false);                        
		//3.執(zhí)行CRUD操作
		//4.當兩個操作成功后手動提交 
		conn.commit();       
	} catch (Exception e) { 
		//一旦其中一個操作出錯都將回滾,所有操作都不成功
		if(conn!=null){conn.rollback(); }
		e.printStackTrace();  
	} finally {
		//5.關(guān)閉連接
		if(conn!=null){conn.close();}
	}
}

而使用Spring的事務(wù)管理功能后,我們可以不再寫步驟 1、2 、4、5 的代碼,而是由Spring 自動完成,即通過AOP,Spring擦除了大量的try…catch…finally語句、打開關(guān)閉數(shù)據(jù)庫和事務(wù)回滾提交等冗余代碼。

接下來我們主要來講下Spring數(shù)據(jù)庫事務(wù)管理:
1.事務(wù)管理器的設(shè)計與配置
Spring提供能夠事務(wù)管理器的模板是org.springframework.transaction.support.TransactionTemplate,其源碼里主要包含一個PlatformTransactionManager接口,事務(wù)的創(chuàng)建、提交、回滾都是通過這個接口完成的,默認事務(wù)異常時會回滾,我們也可以通過配置修改在某些異常發(fā)生時不回滾事務(wù);
PlatformTransactionManager是一個事務(wù)管理器,也是根管理器,其實在spring中有多種事務(wù)管理器,例如DataSourceTransactionManager,HibernateTransactionManager,WebSphereTransactionManager,JtaTransactionManager 等等;PlatformTransactionManager接口源碼如下:

public interface PlatformTransactionManager {
	//獲取事務(wù)狀態(tài)
	TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
	//提交事務(wù)
	void commit(TransactionStatus status) throws TransactionException;
	//回滾事務(wù)
	void rollback(TransactionStatus status) throws TransactionException;
}

了解了事務(wù)管理的設(shè)計思路,接下來就以DataSourceTransactionManager為例配置事務(wù)管理器(MyBatis框架):
(1)XML配置
-XML的命名空間里引入事務(wù)命名空間:
http://www./schema/tx
http://www./schema/tx/spring-tx-4.0.xsd
-XML中定義一個數(shù)據(jù)庫連接池的
-配置數(shù)據(jù)源事務(wù)管理器,注入數(shù)據(jù)庫連接池,內(nèi)容如下:

<bean id="transactionManager"
	class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource" />
</bean>

經(jīng)過如上三步配置,Spring就知道已將數(shù)據(jù)庫事務(wù)委托給事務(wù)管理器了;
(2)Java配置

@Configuration
@ComponentScan("cn.infocore.transaction.*")
@EnableTransactionManagement  //使用事務(wù)驅(qū)動管理器
public class JavaConfig implements TransactionManagementConfigurer{
	private DataSource ds=null;
	
	//配置數(shù)據(jù)源
	@Bean(name="ds")
	public DataSource initDB(){
		if(ds!=null){
			return ds;
		}
		Properties props=new Properties();
		props.setProperty("driverClassName", "com.mysql.jdbc.Driver");
		props.setProperty("url", "jdbc:mysql://localhost:3306/xx_db");
		props.setProperty("username", "root");
		props.setProperty("password", "root");
		props.setProperty("maxActive", "200");
		props.setProperty("maxIdle", "20");
		props.setProperty("maxWait", "30000");
		try {
			ds=BasicDataSourceFactory.createDataSource(props);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return ds;
	}
	
	//配置JdbcTemplate
	@Bean(name="jdbcTemplate")
	public JdbcTemplate initJdbcTemplate(){
		JdbcTemplate jdbc=new JdbcTemplate();
		jdbc.setDataSource(initDB());
		return jdbc;
	}

	//實現(xiàn)接口方法,使得返回數(shù)據(jù)庫事務(wù)管理
	@Override
	public PlatformTransactionManager annotationDrivenTransactionManager() {
		DataSourceTransactionManager manager=new DataSourceTransactionManager();
		manager.setDataSource(initDB());
		return manager;
	}
}

2.在spring中可以使用聲明式事務(wù)和編程式事務(wù),后者由于會產(chǎn)生冗余代碼,現(xiàn)已幾乎不用;聲明式事務(wù)又可分為XML配置和注解事務(wù),XML也已不常用,目前主流事務(wù)處理方法是@Transactional;
(1)編程式事務(wù):事務(wù)的定義獲取、SQL執(zhí)行、事務(wù)的提交回滾都由開發(fā)者自己實現(xiàn);唯一的優(yōu)點就是代碼流程清晰,但不推薦使用,代碼就不詳述了;
(2)聲明式事務(wù):一種約定型事務(wù),spring給了一個約定,AOP技術(shù);當業(yè)務(wù)正常或異常時,spring會讓事務(wù)管理器提交或回滾事務(wù);介于聲明式事務(wù)是重點,因此會詳細分析,先看下流程圖和Transactional源碼:
在這里插入圖片描述

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
	//定義事務(wù)管理器,值是IoC容器中的一個beanId,這個bean需實現(xiàn)接口PlatformTransactionManager
	@AliasFor("transactionManager")
	String value() default ""; 
	//同上
	@AliasFor("value")
	String transactionManager() default "";
	//傳播行為
	Propagation propagation() default Propagation.REQUIRED;
	//隔離級別
	Isolation isolation() default Isolation.DEFAULT;
	//超時時間,單位秒,會引發(fā)異常,默認會導(dǎo)致事務(wù)回滾
	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
	//是否開啟只讀事務(wù),默認false
	boolean readOnly() default false;
	//回滾事務(wù)的異常類定義:當產(chǎn)生所定義異常時,才會回滾
	Class<? extends Throwable>[] rollbackFor() default {};
	//回滾事務(wù)異常類名定義,同上,只是這個是使用類名稱定義
	String[] rollbackForClassName() default {};
	//當產(chǎn)生哪些異常時不回滾事務(wù)
	Class<? extends Throwable>[] noRollbackFor() default {};
	//當產(chǎn)生哪些類名稱定義的異常時,不回滾事務(wù)
	String[] noRollbackForClassName() default {};
}

Transactional源碼所定義的屬性都會被spring放到事務(wù)定義類TransactionDefinition中,接下來就是如何使用了;以最常使用的@Transactional注解為例:
-XML配置事務(wù)攔截器:定義事務(wù)屬性與作用類

<!--配置注解驅(qū)動,加入下面一行,就可以使用@Transactional配置事務(wù)了-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 事務(wù)攔截器:攔截正則表達式匹配的方法 -->
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
	<property name="transactionManager" value="transactionManager" /> <!-- 事務(wù)管理器 -->
	<property name="transactionAttributes"><!-- 配置事務(wù)屬性 -->
		<props>
			<!-- key代表業(yè)務(wù)方法的正則表達式,內(nèi)容是配置各類事務(wù)定義參數(shù) -->
			<prop key="insert*">PROPAGATION_REQUIRED,ISOLATION_READ_UNCOMMITTED</prop>
			<prop key="select*">PROPAGATION_REQUIRED,readOnly</prop>
		</props>
	</property>
</bean>
<!-- 事務(wù)攔截器:攔截哪些類 -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
	<property name="beanNames">
		<list><value>*ServiceImpl</value></list>
	</property>
	<property name="interceptorNames">
		<list><value>transactionInterceptor</value></list>
	</property>
</bean>

在定義完事務(wù)管理器、攔截器后,接下來就是編寫業(yè)務(wù)代碼了,示例如下:

@Autowired
private RoleDao roleDao=null;

@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,timeout=3)
public int insertRole(Role role){
	return roleDao.insert(role);
}

3.數(shù)據(jù)庫相關(guān)
(1)數(shù)據(jù)庫事務(wù)ACID特性:
原子性Atomicity:整個事務(wù)中所有操作要么全部成功要么全部失敗,中間異常會回滾;
一致性Consistency:事務(wù)在完成時,必須是所有的數(shù)據(jù)都保持一致狀態(tài);
隔離性Isolation:并發(fā)事務(wù)執(zhí)行之間無影響,在一個事務(wù)內(nèi)部的操作對其他事務(wù)是不產(chǎn)生影響,這需要事務(wù)隔離級別來指定隔離性;
持久性Durability:一旦事務(wù)完成,數(shù)據(jù)庫的改變必須是持久化的;

主要說一下隔離性,這個涉及到隔離級別,需要設(shè)置隔離級別是因為當同一數(shù)據(jù)被多個事務(wù)同時訪問時,壓制丟失更新的產(chǎn)生;注意只是壓制,而不是消除,因為考慮到性能問題,過多的鎖會導(dǎo)致大量線程被掛起和恢復(fù),從而導(dǎo)致系統(tǒng)緩慢;
第一類丟失更新:操作同一數(shù)據(jù),一個事務(wù)回滾而另一個事務(wù)操作后提交而引發(fā)數(shù)據(jù)不一致;目前大部分數(shù)據(jù)庫已克服這類丟失;
第二類丟失更新:操作同一數(shù)據(jù),多個事務(wù)同時提交而引發(fā)數(shù)據(jù)不一致;此類丟失目前有如下4中隔離級別:
(1)未提交讀READ UNCOMMITTED
允許一個事務(wù)讀取另一個事務(wù)未提交的數(shù)據(jù);最低隔離,最危險(讀取到另一個事務(wù)的未提交數(shù)據(jù)操作后,另一個事務(wù)回滾了,就出現(xiàn)臟讀),應(yīng)用不大;優(yōu)點是并發(fā)能力高,適合對數(shù)據(jù)一致性沒有高要求而追求高并發(fā)的場景;
(2)讀寫提交READ COMMITTED
一個事務(wù)只能讀取另外一個事務(wù)已提交數(shù)據(jù);會出現(xiàn)不可重復(fù)讀(針對一條記錄)問題;
(3)可重復(fù)讀
針對(2)中出現(xiàn)的不可重復(fù)讀,如某個數(shù)據(jù)被一個事務(wù)讀取,另一個事務(wù)再去讀取只能阻塞直到前一個事務(wù)提交;會出現(xiàn)幻讀(針對多條記錄)問題;
(4)串行化SERIALIZABLE
所有SQL按照順序執(zhí)行,最高隔離;
總之,(1)可能出現(xiàn)臟讀、不可重復(fù)讀、幻讀;(2)可能出現(xiàn)不可重復(fù)讀、幻讀;(3)可能出現(xiàn)幻讀;所以使用時,要結(jié)合性能和數(shù)據(jù)一致性一起考慮,一般會以讀寫提交為主;Oracle只支持讀寫提交和串行化,默認讀寫提交;MySQL都支持,默認可重復(fù)讀;當業(yè)務(wù)并發(fā)量不是很大的情況,可以使用串行化來保證數(shù)據(jù)一致性;

(2)傳播行為
方法之間調(diào)用事務(wù)采取的策略問題;一般情況下,數(shù)據(jù)庫事務(wù)都是要么全部成功要么全部失敗的機制,但也會出現(xiàn)其他情況,例如批量操作,只需要回滾失敗操作即可,這就涉及到事務(wù)的傳播行為;
傳播行為有如下7種:
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED):需要事務(wù),默認,如當前存在事務(wù),就沿用,否則新建一個事務(wù)運行子方法;
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS):支持事務(wù),如當前存在事務(wù),就沿用,不存在就繼續(xù)采用無事務(wù)方式;
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY):必須使用事務(wù),如當前存在事務(wù),就沿用,否則拋出異常;
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW):新建事務(wù),無論當前事務(wù)是否存在,都新建新事務(wù),新事務(wù)有自己獨立的隔離級別與鎖等特性;
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED):不支持事務(wù),當前存在事務(wù)時,掛起事務(wù);
NEVER(TransactionDefinition.PROPAGATION_NEVER):不支持事務(wù),當前存在事務(wù)時,拋出異常,否則繼續(xù)采用無事務(wù)方式;
NESTED(TransactionDefinition.PROPAGATION_NESTED):當前方式調(diào)用子方法時,子方法發(fā)生異常,只回滾子方法SQL,新事務(wù)沿用當前事務(wù)的隔離級別和鎖等機制;如果數(shù)據(jù)庫支持保存點技術(shù),就啟用,否則就等價于REQUIRES_NEW;

4.一些注意點
(1)@Transactional,可以注解在類或方法或接口上,注解在類上表示這個類的所有public非靜態(tài)方法都將啟用事務(wù)功能,推薦放在實現(xiàn)類上;其底層實現(xiàn)是Spring AOP技術(shù),而AOP使用的是動態(tài)代理,那對于靜態(tài)方法和非public方法,注釋@Transactional是失效的;
(2)@Transactional自調(diào)用是失效的,即在@Transactional注解的方法或類中調(diào)用自己類中定義的方法是失效的,是因為AOP的原理是動態(tài)代理,自調(diào)用是類自身的調(diào)用,而不是代理對象去調(diào)用,就不會產(chǎn)生AOP,Spring就不能把代碼織入約定流程;
解決方法:
-用一個Service去調(diào)用另一個Servic,即再寫一個Service;
-從Spring IoC容器中獲取代理對象getBean()去啟用AOP;
(3)典型錯誤
–使用帶有事務(wù)的Service定義的方法時(有@Transactional注解),多次調(diào)用,并不在同一個事務(wù)里,spring每次都會創(chuàng)建新的數(shù)據(jù)庫事務(wù),完成后就會釋放,因此這種操作是不可能解決都成功或失敗的提交或回滾的;
–過長時間占用事務(wù):使用數(shù)據(jù)庫事務(wù)過程中,有占用時間比較久的且與數(shù)據(jù)庫事務(wù)無關(guān)的操作(讀寫文件、通信連接等),在并發(fā)請求多且性能要求高的環(huán)境就會出現(xiàn)請求卡頓的情況,嚴重的可能會出現(xiàn)宕機;建議將這類操作提取出來,在事務(wù)關(guān)閉后執(zhí)行,這樣就可以避免長時間占用事務(wù)導(dǎo)致系統(tǒng)性能降低;
–錯誤捕捉異常:主要是開發(fā)者在代碼中使用try…catch…捕獲了異常,導(dǎo)致spring在數(shù)據(jù)庫事務(wù)所約定的流程中再也得不到任何異常信息了,因此就會提交事務(wù),并不會因為異常而回滾了;
解決方法:在catch里
-手動拋出異常:throw new RuntimException(ex);
-手動事務(wù)回滾: TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
–異常種類:Spring管理事務(wù)默認是RuntimeException或者Error,對于非運行時異常來說,可以通過設(shè)置rollbackfor(發(fā)生指定異常時回滾)、rollbackForClassName、noRollbackFor(發(fā)生指定異常時不會滾)、noRollbackForClassName來指定在什么異常的情況下依舊提交事務(wù),在什么異常下回滾事務(wù);例如:@Transactional(rollbackFor = Exception.class),表示發(fā)生非運行時異常時回滾;

來源:http://www./content-4-24736.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多