久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
    分享

    深入spring事務管理

     印度阿三17 2018-09-26

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

    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.開啟事務:將自動提交設置為false   
    		conn.setAutoCommit(false);                        
    		//3.執行CRUD操作
    		//4.當兩個操作成功后手動提交 
    		conn.commit();       
    	} catch (Exception e) { 
    		//一旦其中一個操作出錯都將回滾,所有操作都不成功
    		if(conn!=null){conn.rollback(); }
    		e.printStackTrace();  
    	} finally {
    		//5.關閉連接
    		if(conn!=null){conn.close();}
    	}
    }
    

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

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

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

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

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

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

    @Configuration
    @ComponentScan("cn.infocore.transaction.*")
    @EnableTransactionManagement  //使用事務驅動管理器
    public class JavaConfig implements TransactionManagementConfigurer{
    	private DataSource ds=null;
    	
    	//配置數據源
    	@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;
    	}
    
    	//實現接口方法,使得返回數據庫事務管理
    	@Override
    	public PlatformTransactionManager annotationDrivenTransactionManager() {
    		DataSourceTransactionManager manager=new DataSourceTransactionManager();
    		manager.setDataSource(initDB());
    		return manager;
    	}
    }
    

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

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

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

    <!--配置注解驅動,加入下面一行,就可以使用@Transactional配置事務了-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!-- 事務攔截器:攔截正則表達式匹配的方法 -->
    <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
    	<property name="transactionManager" value="transactionManager" /> <!-- 事務管理器 -->
    	<property name="transactionAttributes"><!-- 配置事務屬性 -->
    		<props>
    			<!-- key代表業務方法的正則表達式,內容是配置各類事務定義參數 -->
    			<prop key="insert*">PROPAGATION_REQUIRED,ISOLATION_READ_UNCOMMITTED</prop>
    			<prop key="select*">PROPAGATION_REQUIRED,readOnly</prop>
    		</props>
    	</property>
    </bean>
    <!-- 事務攔截器:攔截哪些類 -->
    <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>
    

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

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

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

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

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

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

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

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

      0條評論

      發表

      請遵守用戶 評論公約

      類似文章 更多

      主站蜘蛛池模板: 亚洲小说乱欧美另类| 亚洲精品无码日韩国产不卡av| 色悠久久久久综合网伊| 亚洲V天堂V手机在线| 国产成人欧美日韩在线电影| 国产免费看插插插视频| 一卡二卡三卡四卡视频区| 国内精品伊人久久久久影院对白| 日韩有码av中文字幕| 精品国产一区二区三区2021| 四虎国产精品永久在线| 久久SE精品一区精品二区| 国产一区二区四区不卡| 午夜免费国产体验区免费的| 中文国产不卡一区二区| 中文字幕AV无码一二三区电影 | 国色天香天天影院综合网| 国产高清一区二区不卡| 无码国产精品一区二区免费式芒果 | 又大又粗欧美成人网站| 欧洲一区二区中文字幕| 国产精品久久久久久无码五月| 二区三区亚洲精品国产| 国产精品 视频一区 二区三区| 国产超高清麻豆精品传媒麻豆精品 | 两个人看的WWW在线观看| 美女被强奷到抽搐的动态图| 国产猛男猛女超爽免费视频| 97夜夜澡人人爽人人模人人喊| 亚洲中文久久久精品无码| 国产精品久久久久AV福利动漫| 日韩丝袜欧美人妻制服| 免费无码又爽又刺激毛片| 三级网站视频在在线播放| 午夜免费无码福利视频麻豆| 播放灌醉水嫩大学生国内精品| 国产成人亚洲精品无码电影不卡 | 成人3D动漫一区二区三区| 无码人妻蜜肉动漫中文字幕| 亚洲制服无码一区二区三区| 日韩精品国产二区三区|