1、概念java
分佈式事務
分佈式事務是指事務的參與者、支持事務的服務器、資源服務器以及事務管理器分別位於不一樣的分佈式系統的不一樣節點之上。簡言之,同時操做多個數據庫保持事務的統一,達到跨庫事務的效果。node
JTA
JTA,即Java Transaction API,JTA容許應用程序執行分佈式事務處理———在兩個或多個網絡計算機資源上訪問而且更新數據。JDBC驅動程序的JTA支持極大地加強了數據訪問能力。mysql
JTA和JTSspring
Java事務API(JTA:Java Transaction API)和它的同胞Java事務服務(JTS:Java Transaction Service),爲J2EE平臺提供了分佈式事務服務(distributed transaction)。
一個分佈式事務(distributed transaction)包括一個事務管理器(transaction manager)和一個或多個資源管理器(resource manager)。
一個資源管理器(resource manager)是任意類型的持久化數據存儲。
事務管理器(transaction manager)承擔着全部事務參與單元者的相互通信的責任。sql
JTA與JDBC數據庫
JTA事務比JDBC事務更強大。一個JTA事務能夠有多個參與者,而一個JDBC事務則被限定在一個單一的數據庫鏈接。下列任一個Java平臺的組件均可以參與到一個JTA事務中:JDBC鏈接、JDO PersistenceManager 對象、JMS 隊列、JMS 主題、企業JavaBeans(EJB)、一個用J2EE Connector Architecture 規範編譯的資源分配器。apache
JOTM
JOTM (Java Open Transaction Manager)是一個開源獨立的事務管理器,支持分佈式事務,Spring3.X已經再也不支持JOTM。api
Atomikos
Atomikos TransactionsEssentials是一個爲Java平臺提供增值服務的而且開源類事務管理器,支持分佈式事務,本文所採用的技術。服務器
Atomikos是目前在分佈式事務管理中作得至關不錯的開源軟件。有10年以上的經驗,Atomikos保障您的關鍵事務和防止昂貴的數據丟失在發生系統故障或事故中.Atomikos支持XA(全局事務)和NON-XA(非全局事務),NON-XA效率高於XA。本文主要是講XA事件,由於要在不一樣的數據庫中操做多張表。網絡
接下來講一下Spring.x+Hibernate中集成Atomikos構建JTA的分佈式事務
2、Spring.x+Hibernate+Atomikos集成
Spring.x+Hibernate怎麼集成此處省略不說,主要講解Spring.x+Atomikos的集成,操做步驟以下:
一、下載Atomikos,須要如下這些包
atomikos-util-1.0.jar
cglib-nodep-2.2.2.jar
transactions-3.7.0.jar
transactions-api-3.7.0.jar
transactions-jdbc-3.7.0.jar
transactions-jta-3.7.0.jar
二、配置
在applicationContext.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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <context:annotation-config /> <!-- 經過註解方式自動掃描需交給sping管理的Bean --> <context:component-scan base-package="com.ljq" /> <!-- spring atomikos配置 --> <!-- bpm數據源 --> <bean id="bpmDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close"> <!-- Set unique name for this DataSource --> <property name="uniqueResourceName"><value>bpm</value></property> <!-- Set XADatasource class name--> <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" /> <property name="xaProperties"> <props> <prop key="user">root</prop> <prop key="password">parami2013</prop> <prop key="url">jdbc:mysql://192.168.1.254:3306/parami_bpm</prop> </props> </property> <!-- set properties for datasource connection pool --> <property name="poolSize" value="3" /> <!-- 管理 Connection 被佔用的時間 --> <!-- 若是不設置這個值,Atomikos使用默認的300秒(即5分鐘),那麼在處理大批量數據讀取的時候,一旦超過5分鐘,就會拋出相似 Resultset is close 的錯誤 --> <property name="reapTimeout"><value>20000</value></property> </bean> <!-- center數據源 --> <bean id="centerDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close"> <property name="uniqueResourceName"><value>center</value></property> <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" /> <property name="xaProperties"> <props> <prop key="user">root</prop> <prop key="password">parami2013</prop> <prop key="url">jdbc:mysql://192.168.1.254:3306/parami_center</prop> </props> </property> <!-- 鏈接池裏面鏈接的個數 --> <property name="poolSize" value="3" /> <!-- 管理 Connection 被佔用的時間 --> <!-- 若是不設置這個值,Atomikos使用默認的300秒(即5分鐘),那麼在處理大批量數據讀取的時候,一旦超過5分鐘,就會拋出相似 Resultset is close 的錯誤 --> <property name="reapTimeout"><value>20000</value></property> </bean> <!-- 將hibernate數據源注入sessionFactory --> <bean id="bpmSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="bpmDataSource" /> <property name="packagesToScan"> <list> <value>com.ljq.pojo</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.show_sql">true</prop> <!-- 慎重(推薦禁止) 固定爲update --> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</prop> </props> </property> </bean> <!-- 將hibernate數據源注入sessionFactory --> <bean id="centerSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="centerDataSource" /> <property name="packagesToScan"> <list> <value>com.ljq.pojo</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.show_sql">true</prop> <!-- 慎重(推薦禁止) 固定爲update --> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</prop> </props> </property> </bean> <!-- atomikos事務管理器 --> <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close"> <property name="forceShutdown"> <value>true</value> </property> </bean> <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp"> <property name="transactionTimeout" value="300" /> </bean> <!-- spring 事務管理器 --> <bean id="springTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManager" ref="atomikosTransactionManager"/> <property name="userTransaction" ref="atomikosUserTransaction" /> <property name="allowCustomIsolationLevels" value="true"/> </bean> <!-- 使用annotation定義事務,對於要加入事物的類,只需對該類加 @Transactional --> <tx:annotation-driven transaction-manager="springTransactionManager" /> <!-- hibernate Dao層模板 --> <bean id="bpmHibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory" ref="bpmSessionFactory"></property> </bean> <bean id="centerHibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory" ref="centerSessionFactory"></property> </bean> </beans>
三、在src文件夾下面加入一個transactions.properties文件
# SAMPLE PROPERTIES FILE FOR THE TRANSACTION SERVICE # THIS FILE ILLUSTRATES THE DIFFERENT SETTINGS FOR THE TRANSACTION MANAGER # UNCOMMENT THE ASSIGNMENTS TO OVERRIDE DEFAULT VALUES; # Required: factory implementation class of the transaction core. # NOTE: there is no default for this, so it MUST be specified! # com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory # Set base name of file where messages are output # (also known as the 'console file'). # # com.atomikos.icatch.console_file_name = tm.out # Size limit (in bytes) for the console file; # negative means unlimited. # # com.atomikos.icatch.console_file_limit=-1 # For size-limited console files, this option # specifies a number of rotating files to # maintain. # # com.atomikos.icatch.console_file_count=1 # Set the number of log writes between checkpoints # # com.atomikos.icatch.checkpoint_interval=500 # Set output directory where console file and other files are to be put # make sure this directory exists! # # com.atomikos.icatch.output_dir = ./ # Set directory of log files; make sure this directory exists! # # com.atomikos.icatch.log_base_dir = ./ # Set base name of log file # this name will be used as the first part of # the system-generated log file name # # com.atomikos.icatch.log_base_name = tmlog # Set the max number of active local transactions # or -1 for unlimited. # # com.atomikos.icatch.max_actives = 50 # Set the default timeout (in milliseconds) for local transactions # # com.atomikos.icatch.default_jta_timeout = 10000 # Set the max timeout (in milliseconds) for local transactions # # com.atomikos.icatch.max_timeout = 300000 # The globally unique name of this transaction manager process # override this value with a globally unique name # # com.atomikos.icatch.tm_unique_name = tm # Do we want to use parallel subtransactions? JTA's default # is NO for J2EE compatibility # # com.atomikos.icatch.serial_jta_transactions=true # If you want to do explicit resource registration then # you need to set this value to false. # # com.atomikos.icatch.automatic_resource_registration=true # Set this to WARN, INFO or DEBUG to control the granularity # of output to the console file. # # com.atomikos.icatch.console_log_level=WARN # Do you want transaction logging to be enabled or not? # If set to false, then no logging overhead will be done # at the risk of losing data after restart or crash. # # com.atomikos.icatch.enable_logging=true # Should two-phase commit be done in (multi-)threaded mode or not? # Set this to false if you want commits to be ordered according # to the order in which resources are added to the transaction. # # NOTE: threads are reused on JDK 1.5 or higher. # For JDK 1.4, thread reuse is enabled as soon as the # concurrent backport is in the classpath - see # http://mirrors.ibiblio.org/pub/mirrors/maven2/backport-util-concurrent/backport-util-concurrent/ # # com.atomikos.icatch.threaded_2pc=false # Should shutdown of the VM trigger shutdown of the transaction core too? # # com.atomikos.icatch.force_shutdown_on_vm_exit=false
四、注入HibernateTemplate模板
a、爲bpm庫注入HibernateTemplate模板
public abstract class BpmDaoSupport<T> extends DaoSupport<T> { protected HibernateTemplate bpmHibernateTemplate; /** * HibernateTemplate注入 * * @param bpmHibernateTemplate */ @Resource public void setBpmHibernateTemplate(HibernateTemplate bpmHibernateTemplate) { this.bpmHibernateTemplate = bpmHibernateTemplate; setHibernateTemplate(bpmHibernateTemplate); } }
b、爲center庫注入HibernateTemplate模板
public abstract class CenterDaoSupport<T> extends DaoSupport<T> { protected HibernateTemplate centerHibernateTemplate; /** * HibernateTemplate注入 * * @param centerHibernateTemplate */ @Resource public void setCenterHibernateTemplate(HibernateTemplate centerHibernateTemplate) { this.centerHibernateTemplate = centerHibernateTemplate; setHibernateTemplate(centerHibernateTemplate); } }
五、編寫業務邏輯代碼
@Service(value="userServiceBean") @Transactional public class UserServiceBean implements UserService { @Resource(name="userDaoBean") private UserDao userDao; @Resource(name="userRoleDaoBean") private UserRoleDao userRoleDao; public List<User> queryUser() { return userDao.queryUser(); } public void save(User user, UserRole ur) { userDao.save(user); //a處 //此處報異常 System.out.println(1/0); //b處 ur.setUserId(user.getUid()); userRoleDao.save(ur); //c處 } }
在執行save()方法時會報java.lang.ArithmeticException: / by zero異常,b處的「1/0」有問題,由於除數不能爲0;
若是事務生效,save()方法會回滾掉,即a處、c處不作save操做,保持事務的原子性;
若是事務不起做用,那麼a處會執行成功,往數據庫添加一條記錄;b處拋出異常終止向下執行;c處這條代碼不執行,致使髒數據的出現。
Atomikos的集成到此就結束了,親!是否是很簡單。
注意mysql的驅動須要5.1.10版本以上,低版本會出現以下錯誤:java.lang.IllegalArgumentException: null source