Spring交易隔離等級與傳播機制,spring+mybatis+atomikos實現分散式交易管理,mybatisatomikos
本文轉載於【http://blog.csdn.net/liaohaojian/article/details/68488150】1.事務的定義:事務是指多個操作單元組成的合集,多個單元操作是整體不可分割的,要麼都操作不成功,要麼都成功。其必須遵循四個原則(ACID)。2.事務的類型3.Spring交易隔離等級:spring有五大隔離等級,其在TransactionDefinition介面中定義。看源碼可知,其默isolation_default(底層資料庫預設層級),其他四個隔離等級跟資料庫隔離等級一致。
幻讀與不可重複讀取的區別:幻讀的重點在於插入與刪除,即第二次查詢會發現比第一次查詢資料變少或者變多了,以至於給人一種幻象一樣,而不可重複讀取重點在於修改,即第二次查詢會發現查詢結果比第一次查詢結果不一致,即第一次結果已經不可重現了。
資料庫隔離等級越高,執行代價越高,並發執行能力越差,因此在實際項目開發使用時要綜合考慮,為了考慮並發效能一般使用提交讀隔離等級,它能避免丟失更新和髒讀,儘管不可重複讀取和幻讀不能避免,但可以在可能出現的場合使用悲觀鎖或樂觀鎖來解決這些問題。
悲觀鎖與樂觀鎖可參考:http://blog.csdn.net/liaohaojian/article/details/62416972
4.傳播行為:有七大傳播行為,也是在TransactionDefinition介面中定義。5.Spring事務支援
1.spring提供了很多內建交易管理員,支援不同資料來源。常見的有三大類
- DataSourceTransactionManager:org.springframework.jdbc.datasource包下,資料來源交易管理類,提供對單個javax.sql.DataSource資料來源的交易管理,只要用於JDBC,Mybatis架構交易管理。
- HibernateTransactionManager:org.springframework.orm.hibernate3包下,資料來源交易管理類,提供對單個org.hibernate.SessionFactory事務支援,用於整合Hibernate架構時的交易管理;注意:該交易管理員只支援Hibernate3+版本,且Spring3.0+版本只支援Hibernate 3.2+版本;
- JtaTransactionManager:位於org.springframework.transaction.jta包中,提供對分散式交易管理的支援,並將交易管理委託給Java EE應用伺服器,或者自訂一個本地JTA交易管理員,嵌套到應用程式中。
內建交易管理員都繼承了抽象類別AbstractPlatformTransactionManager,而AbstractPlatformTransactionManager又繼承了介面PlatformTransactionManager
Spring架構支援交易管理的核心是交易管理員抽象,對於不同的資料訪問架構通過實現策略介面PlatformTransactionManager,從而能支援多鐘資料訪問架構的交易管理。
PlatformTransactionManager介面定義如下
public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;//返回一個已經啟用的事務或建立一個新的事務(具體由TransactionDefinition參數定義的事務屬性決定),返回的TransactionStatus對象代表了當前事務的狀態,其中該方法拋出TransactionException(未檢查異常)表示事務由於某種原因失敗。 void commit(TransactionStatus status) throws TransactionException;//用於提交TransactionStatus參數代表的事務。 void rollback(TransactionStatus status) throws TransactionException;//用於復原TransactionStatus參數代表的事務。}TransactionDefinition介面定義如下:
public interface TransactionDefinition { int getPropagationBehavior(); //返回定義的事務傳播行為 int getIsolationLevel(); //返回交易隔離等級 int getTimeout(); //返回定義的事務逾時時間 boolean isReadOnly(); //返回定義的事務是否是唯讀 String getName(); //返回事務名稱} TransactionStatus介面定義如下:
public interface TransactionStatus extends SavepointManager { boolean isNewTransaction(); //返回當前事務是否是新的事務 boolean hasSavepoint(); //返回當前事務是否有儲存點 void setRollbackOnly(); //設定交易回復 boolean isRollbackOnly(); //設定當前事務是否應該復原 void flush(); //用於重新整理底層會話中的修改到資料庫,一般用於重新整理如Hibernate/JPA的會話,可能對如JDBC類型的事務無任何影響; boolean isCompleted(); //返回事務是否完成} 2.Spring分散式交易配置
- 引用應用伺服器(如Tomcat)的JNDI資料來源,間接實現JTA交易管理,依賴於應用伺服器
- 直接整合JOTM(官網:http://jotm.objectweb.org/)、Atomikos(官網:https://www.atomikos.com/)提供JTA交易管理(無應用伺服器支援,常用於單元測試)
- 使用特定於應用伺服器的交易管理員,使用JTA事務的進階功能(Weblogic,Websphere)
1).引用應用伺服器(如Tomcat)的JNDI資料來源,間接實現JTA交易管理,配置如下
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd"> <!-- JNDI資料來源 --> <jee:jndi-lookup id="dataSource" jndi-name="jdbc/test"/> <!-- JTA交易管理員 --> <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <!--transactionManagerName指定JTA交易管理員的JNDI名字,從而將交易管理委託給該交易管理員 --> <property name="transactionManagerName" value="java:comp/TransactionManager"/> </bean></beans>
2)使用Atomikos實現分散式交易管理,配置如下:
<?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:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/taskhttp://www.springframework.org/schema/task/spring-task-3.0.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <context:component-scan base-package="com.suicai.*.service.impl" /><context:component-scan base-package="com.suicai.util" /> <!-- 此方法載入的設定檔僅僅在xml中使用,但是工具類都採用註解的方式 --><bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="location" value="classpath:conn.properties" /></bean><!-- 僅僅支援註解不支援在xml配置中使用properties檔案 在類中可以使用SPEL運算式來載入相應的值 --><bean id="temp" class="org.springframework.beans.factory.config.PropertiesFactoryBean"><property name="locations"><array><value>classpath:public.properties</value></array></property></bean><bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close" abstract="true"> <property name="borrowConnectionTimeout" value="60"/> <!--擷取串連失敗重新獲等待最大時間,在這個時間內如果有可用串連,將返回--> <property name="reapTimeout" value="20"/> <!--最大擷取資料時間,如果不設定這個值,Atomikos使用預設的5分鐘,那麼在處理大批量資料讀取的時候,一旦超過5分鐘,就會拋出類似 Resultset is close 的錯誤.--> <property name="maintenanceInterval" value="60" /> <!--串連回收時間--> <property name="loginTimeout" value="60" /> <!--java資料庫連接池,最大可等待擷取datasouce的時間--> <property name="logWriter" value="60"/> <property name=""></property> <property name="minPoolSize" value="1" /> <!-- 串連池中保留的最小串連數 --> <property name="maxPoolSize" value="3" /> <!-- 串連池中保留的最大串連數 --> <property name="maxIdleTime" value="60" /> <!-- 最大空閑時間,60秒內未使用則串連被丟棄。若為0則永不丟棄。Default: 0 --> </bean> <!-- 配置2個資料來源 mysql --> <bean id="ds_suicai" parent="abstractXADataSource"> <!-- uniqueResourceName表示唯一資源名,如有多個資料來源不可重複; --> <property name="uniqueResourceName" value="suicaifortest" /> <!-- xaDataSourceClassName是具體分布式資料來源廠商實現; --> <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/> <!-- xaProperties屬性指定具體廠商資料庫屬性 --> <property name="xaProperties"> <props> <prop key="URL">${db.jdbcUrlOne}</prop> <prop key="user">${user}</prop> <prop key="password">${password}</prop> </props> </property> </bean> <bean id="ds_kaizhi" parent="abstractXADataSource"> <!-- uniqueResourceName表示唯一資源名,如有多個資料來源不可重複; --><property name="uniqueResourceName" value="puildingpurchasefortest" /><!-- xaDataSourceClassName是具體分布式資料來源廠商實現; --><property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/><!-- xaProperties屬性指定具體廠商資料庫屬性 --><property name="xaProperties"> <props> <prop key="URL">${db.jdbcUrlTwo}</prop> <prop key="user">${user}</prop> <prop key="password">${password}</prop> </props> </property> </bean> <!-- 動態配置資料來源 --> <bean id="dataSource2" class="com.suicai.common.datasource.DynamicDataSource"> <property name="targetDataSources"> <map key-type ="java.lang.String"> <entry value-ref ="ds_suicai" key="ds_suicai"></entry > <entry value-ref ="ds_kaizhi" key="ds_kaizhi"></entry > </map > </property> <property name ="defaultTargetDataSource" ref="ds_suicai"></property> </bean> <bean id ="sqlSessionFactoryBeanA" class="org.mybatis.spring.SqlSessionFactoryBean" > <!-- 指定資料來源 --> <property name ="dataSource" ref="ds_suicai" /> <!-- 指定mybatis 的設定檔 --> <property name ="configLocation" value="classpath:mybatis.cfg.xml" /> </bean><bean id ="sqlSessionFactoryBeanB" class="org.mybatis.spring.SqlSessionFactoryBean" > <!-- 指定資料來源 --> <property name ="dataSource" ref="ds_kaizhi" /> <!-- 指定mybatis 的設定檔 --> <property name ="configLocation" value="classpath:mybatis.cfg.xml" /> </bean><!--CustomSqlSessionTemplate繼承SqlSessionTemplate重寫getSqlSessionFactory方法,具體請下載查看--> <bean id="sqlSessionTemplate" class="com.suicai.util.CustomSqlSessionTemplate" scope="prototype"> <constructor-arg ref="sqlSessionFactoryBeanA" /> <property name="targetSqlSessionFactorys"> <map> <entry value-ref ="sqlSessionFactoryBeanA" key="ds_suicai1"></entry > <entry value-ref ="sqlSessionFactoryBeanB" key="ds_kaizhi1"></entry > </map> </property> </bean> <!-- 配置atomikos交易管理員 --><bean id="atomikosTransactionManager" class = "com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method = "close"> <property name="forceShutdown" value="true"/> </bean> <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp"></bean><!-- 配置spring交易管理員 --><bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManager"> <ref bean="atomikosTransactionManager"/> </property> <property name="userTransaction"> <ref bean="atomikosUserTransaction"/> </property> <!-- 必須設定,否則程式出現異常 JtaTransactionManager does not support custom isolation levels by default --> <property name="allowCustomIsolationLevels" value="true"/> </bean><tx:advice id="advice" transaction-manager="transactionManager"><tx:attributes> <!-- REQUIRED:必須要有事務, 如果沒有就在上下文建立一個 --><tx:method name="save*" propagation="REQUIRED"/><tx:method name="creat*" propagation="REQUIRED"/><tx:method name="add*" propagation="REQUIRED"/><tx:method name="update*" propagation="REQUIRED"/><tx:method name="delete*" propagation="REQUIRED"/><!-- 支援,如果有就有,沒有就沒有 --><tx:method name="*" propagation="SUPPORTS"/></tx:attributes></tx:advice><aop:config> <aop:pointcut expression="execution(* com.suicai.*.service.impl.*.*(..))" id="pointcut"/> <!-- 吧 tx與aop的配置關聯,才是完整的聲明事務配置 --> <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/></aop:config><!-- 採用包掃描機制,自動會把指定的包裡面的所有dao註冊 --><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!-- 注意注入sqlSessionTemplate --> <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/><property name="basePackage" value="com.suicai.*.dao" /></bean><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="viewClass"><value>org.springframework.web.servlet.view.InternalResourceView</value></property><!--jsp存放的目錄--><property name="prefix"><value>/</value></property><!--jsp檔案的尾碼--><property name="suffix"><value>.jsp</value></property></bean><!-- 驗證碼 --><bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha"> <property name="config"> <bean class="com.google.code.kaptcha.util.Config"> <constructor-arg> <props> <prop key="kaptcha.border">no</prop> <prop key="kaptcha.border.color">105,179,90</prop> <prop key="kaptcha.textproducer.font.color">red</prop> <prop key="kaptcha.image.width">200</prop> <prop key="kaptcha.textproducer.font.size">60</prop> <prop key="kaptcha.image.height">80</prop> <prop key="kaptcha.session.key">code</prop> <prop key="kaptcha.textproducer.char.length">4</prop> <prop key="kaptcha.textproducer.font.names">宋體,楷體,微軟雅黑</prop> </props> </constructor-arg> </bean> </property> </bean> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="classpath:messages"/> <property name="fileEncodings" value="utf-8"/> <property name="cacheSeconds" value="120"/> </bean></beans> atomikos所需包及相關設定檔下載路徑:http://download.csdn.net/detail/liaohaojian/9810401,其中檔案jta.properties檔案放到classpath根目錄下。