jotm 包括 jotm-core.jar、ow2-connector-1.5-spec.jar、jotm-client.jar、xapool.jar。
jotm-core.jar、ow2-connector-1.5-spec.jar、jotm-client.jar 主要是提供对transaction 的管理。
xapool.jar提供 xa datesource 以及 connection pool 。
其实个人觉得 学习jta 的切入点只有一个 ,为什么要使用 xa datesource ,而且要求是如此的强烈,以至于让我很想弄明白。
一般的解释就是:JTA(Java Transaction API) 为 J2EE 平台提供了分布式事务服务。要用 JTA 进行事务界定,应用程序要调用 javax.transaction.UserTransaction 接口中的方法。例如:
utx.begin();
// ...
DataSource ds = obtainXADataSource();
Connection conn = ds.getConnection();
pstmt = conn.prepareStatement("UPDATE MOVIES ...");
pstmt.setString(1, "Spinal Tap");
pstmt.executeUpdate();
// ...
utx.commit();
“用 JTA 界定事务,那么就需要有一个实现 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驱动程序。一个实现了这些接口的驱动程序将可以参与 JTA 事务。一个 XADataSource 对象就是一个 XAConnection 对象的工厂。 XAConnection s 是参与 JTA 事务的 JDBC 连接。”
要使用JTA事务,必须使用XADataSource来产生数据库连接,产生的连接为一个XA连接。
JTA方式的实现过程:
用XADataSource产生的XAConnection它扩展了一个getXAResource()方法,事务通过这个方法把它加入到事务容器中进行管理。
[---------------------来至baidu---------------------]
但我觉得还是不能理解,问题是还不能解释我原来提出的切入点[为什么要使用 xa datesource],能解释的只有一句话:用XADataSource产生的XAConnection它扩展了一个getXAResource()方法,事务通过这个方法把它加入到事务容器中进行管理,显然这不能让人满意!
所以我要解释的就是 jta 为什么只能使用xa datesource,要解释这一点,我们要先了解 普通的 jdbc transaction[hibernate transaction] 又是一个什么原理:在这里我结合 spring aop 讲解 jdbc transaction[hibernate transaction]
这是jdbc transaction[hibernate transaction] 使用 spring aop 的配置:
<!-- dataSource 其实已经被c3p0 包装过了 -->
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" dependency-check="none">
<property name="driverClass">
<value>${datasource.driverClassName}</value>
</property>
<property name="jdbcUrl">
<value>${datasource.url}</value>
</property>
<property name="user">
<value>${datasource.username}</value>
</property>
<property name="password">
<value>${datasource.password}</value>
</property>
<property name="acquireIncrement">
<value>${c3p0.acquireIncrement}</value>
</property>
<property name="initialPoolSize">
<value>${c3p0.initialPoolSize}</value>
</property>
<property name="minPoolSize">
<value>${c3p0.minPoolSize}</value>
</property>
<property name="maxPoolSize">
<value>${c3p0.maxPoolSize}</value>
</property>
<property name="maxIdleTime">
<value>${c3p0.maxIdleTime}</value>
</property>
<property name="idleConnectionTestPeriod">
<value>${c3p0.idleConnectionTestPeriod}</value>
</property>
<property name="maxStatements">
<value>${c3p0.maxStatements}</value>
</property>
<property name="numHelperThreads">
<value>${c3p0.numHelperThreads}</value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="mappingResources">
......内容太多 ,不在显示
</property>
</bean>
<!-- transactionManager-->
<bean id="myTransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<!-- 配置事务处理 -->
<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="myTransactionManager" />
</property>
<property name="transactionAttributes">
....拦截 dao 或 service 的配置
</property>
</bean>
我们将sessionFactory 传给了transactionManager、然后transactionManager 传给TransactionProxyFactoryBean
然后我们一般还会配置 dao ,例如 [把sessionFactory 传给 dao]
<bean id="permissionDAO"
class="sezelee.sample.bbsse.dao.hibernate.PermissionHibernateDAO">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
好,现在说 permissionDAO 的事务拦截的调用过程[关注的是transaction 的流向]:
假设代码 调用 permissionDAO 的某个方法之前事务拦截,我们就从TransactionProxyFactoryBean 中myTransactionManager中获取connection ,然后获取 transaction 事务。
说明 :myTransactionManager中已经有 sessionFactory ,我们就是从sessionFactory中获取connection ,然后由connection 获取transaction ,sessionFactory 获取connection 的时候,就将connection 放入 threadlocal[和线程绑定]。
下面正式执行我们的业务逻辑:比如permissionDAO 中的 save(); save()中必然要使用到数据库的connection 。我们从哪里获取 呢, permissionDAO中不是有传进sessionFactory 吗?和myTransactionManager 从sessionFactory获取connention 的道理一样, save()中用到的 connection也从 sessionFactory 获取,那么 此时从sessionFactory 获取的connection就是之前放入threadlocal的connection ,save() 执行完毕。
在提交[commit]或回滚[rollback] 的时候我们获取的还是之前放入threadlocal的connection ,为此整个事务的开始到结束 我们使用的都是 同一个 connection。
这就是 普通 jdbc transaction 结合 spring aop
那 jta 又是怎么个情况呢?
我们直接从 jta 使用spring aop 的配置入手。
<!-- jta 事务-->
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" />
<bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction" ref="jotm" />
</bean>
<!-- XAdataSource-->
<bean id="innerDataSource" class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
<property name="transactionManager" ref="jotm"/>
<property name="driverName">
<value>${datasource.driverClassName}</value>
</property>
<property name="url">
<value>${datasource.url}</value>
</property>
<property name="user">
<value>${datasource.username}</value>
</property>
<property name="password">
<value>${datasource.password}</value>
</property>
<property name="maxCon" value="50" />
<property name="minCon" value="5" />
<property name="preparedStmtCacheSize" value="5"/>
</bean>
<!-- 对 innerDataSource 进行pool 包装-->
<bean id="dataSource" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
<property name="dataSource" ref="innerDataSource"/>
<property name="user" value="root"/>
<property name="password" value=""/>
<property name="minSize" value="2"/>
<property name="maxSize" value="50"/>
<property name="deadLockMaxWait" value="1000"/>
<property name="deadLockRetryWait" value="600"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="mappingResources">
......
</property>
</bean>
<!-- 配置事务处理 -->
<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="jtaTransactionManager" />
</property>
<property name="transactionAttributes">
.....
</property>
</bean>
<!-- 配置事物处理 -->
<!-- about permission DAO -->
<bean id="permissionDAO"
class="sezelee.sample.bbsse.dao.hibernate.PermissionHibernateDAO">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
那么这段代码和 上面的jdbc transaction 有什么不同呢 ?
此时 transactionManager[jtaTransactionManager] 传入的不在是sessionFactory ,而是 jtom。
jtom 到底是什么 呢 ,不用着急我们 往下看, 仔细看 innerDataSource 有什么不同,多了一个jotm。
这是为什么呢?
我们还是从 permissionDAO 的事务拦截的调用过程 开始 [关注的是transaction 的流向]:
假设代码 调用 permissionDAO 的某个方法之前事务拦截,
比如说 update() 方法: 里面需要获取 两个 connection [来至不同的数据源]。
比如 第一个来至 datesource1 、 第二个来至 datesource2
还记得 innerDataSource 中 配置的jtom 吗?
通过 sessionFactory 我们获取 第一个 datesource1 的 connention 时 将connention 放入jtom。我们获取 第二个 datesource2 的 connention 时将connention 放入jtom
jtom 也同时传到了jtaTransactionManager ,update() 方法业务执行完毕。
在提交[commit]或回滚[rollback] 的时候 ,我们就从 jtaTransactionManager 中 的 jtom 获取datesource1 的 connention、datesource2 的 connention
然后加上这样的逻辑 ,只要其中有一个异常 ,就全部rollback。
try{ datesource1.connention.transaction.commit datesource2.connention.transaction.commit
}catch(Exception e){
datesource1.connention.transaction.rollback
datesource2.connention.transaction.rollback
}
所以我们 进行数据库操作的 connention 都是放入jtom或从jtom获取[其实jtom 的connection 还是 绑定到 threadlocal] 。
我们 就简单的将 jtom 理解为 一个 map , 获取connection 时将 connection放入这个map。然后 我们 将map 传给transactionManager ,当事务要提交/回滚的时候我们从transactionManager 获取这个map
spring 给我们提供了这样一个transactionManager [jtatransactionManager]。
以上就是对[用XADataSource产生的XAConnection它扩展了一个getXAResource()方法,事务通过这个方法把它加入到事务容器中进行管理] 这句话的解释。
到此我们 回到 刚开始的切入点:为什么要使用 xa datesource。
xa datesource 提供了 在获取 connecntion时 将connecntion放入 jtom 的支持。
而 datesource 是没有提供这种 支持的。
好了 !全文结束 ,以上是我对 jta 的个人理解 ,有不对的地方,请大家指点!
jotm-core.jar、ow2-connector-1.5-spec.jar、jotm-client.jar 主要是提供对transaction 的管理。
xapool.jar提供 xa datesource 以及 connection pool 。
其实个人觉得 学习jta 的切入点只有一个 ,为什么要使用 xa datesource ,而且要求是如此的强烈,以至于让我很想弄明白。
一般的解释就是:JTA(Java Transaction API) 为 J2EE 平台提供了分布式事务服务。要用 JTA 进行事务界定,应用程序要调用 javax.transaction.UserTransaction 接口中的方法。例如:
utx.begin();
// ...
DataSource ds = obtainXADataSource();
Connection conn = ds.getConnection();
pstmt = conn.prepareStatement("UPDATE MOVIES ...");
pstmt.setString(1, "Spinal Tap");
pstmt.executeUpdate();
// ...
utx.commit();
“用 JTA 界定事务,那么就需要有一个实现 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驱动程序。一个实现了这些接口的驱动程序将可以参与 JTA 事务。一个 XADataSource 对象就是一个 XAConnection 对象的工厂。 XAConnection s 是参与 JTA 事务的 JDBC 连接。”
要使用JTA事务,必须使用XADataSource来产生数据库连接,产生的连接为一个XA连接。
JTA方式的实现过程:
用XADataSource产生的XAConnection它扩展了一个getXAResource()方法,事务通过这个方法把它加入到事务容器中进行管理。
[---------------------来至baidu---------------------]
但我觉得还是不能理解,问题是还不能解释我原来提出的切入点[为什么要使用 xa datesource],能解释的只有一句话:用XADataSource产生的XAConnection它扩展了一个getXAResource()方法,事务通过这个方法把它加入到事务容器中进行管理,显然这不能让人满意!
所以我要解释的就是 jta 为什么只能使用xa datesource,要解释这一点,我们要先了解 普通的 jdbc transaction[hibernate transaction] 又是一个什么原理:在这里我结合 spring aop 讲解 jdbc transaction[hibernate transaction]
这是jdbc transaction[hibernate transaction] 使用 spring aop 的配置:
<!-- dataSource 其实已经被c3p0 包装过了 -->
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" dependency-check="none">
<property name="driverClass">
<value>${datasource.driverClassName}</value>
</property>
<property name="jdbcUrl">
<value>${datasource.url}</value>
</property>
<property name="user">
<value>${datasource.username}</value>
</property>
<property name="password">
<value>${datasource.password}</value>
</property>
<property name="acquireIncrement">
<value>${c3p0.acquireIncrement}</value>
</property>
<property name="initialPoolSize">
<value>${c3p0.initialPoolSize}</value>
</property>
<property name="minPoolSize">
<value>${c3p0.minPoolSize}</value>
</property>
<property name="maxPoolSize">
<value>${c3p0.maxPoolSize}</value>
</property>
<property name="maxIdleTime">
<value>${c3p0.maxIdleTime}</value>
</property>
<property name="idleConnectionTestPeriod">
<value>${c3p0.idleConnectionTestPeriod}</value>
</property>
<property name="maxStatements">
<value>${c3p0.maxStatements}</value>
</property>
<property name="numHelperThreads">
<value>${c3p0.numHelperThreads}</value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="mappingResources">
......内容太多 ,不在显示
</property>
</bean>
<!-- transactionManager-->
<bean id="myTransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<!-- 配置事务处理 -->
<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="myTransactionManager" />
</property>
<property name="transactionAttributes">
....拦截 dao 或 service 的配置
</property>
</bean>
我们将sessionFactory 传给了transactionManager、然后transactionManager 传给TransactionProxyFactoryBean
然后我们一般还会配置 dao ,例如 [把sessionFactory 传给 dao]
<bean id="permissionDAO"
class="sezelee.sample.bbsse.dao.hibernate.PermissionHibernateDAO">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
好,现在说 permissionDAO 的事务拦截的调用过程[关注的是transaction 的流向]:
假设代码 调用 permissionDAO 的某个方法之前事务拦截,我们就从TransactionProxyFactoryBean 中myTransactionManager中获取connection ,然后获取 transaction 事务。
说明 :myTransactionManager中已经有 sessionFactory ,我们就是从sessionFactory中获取connection ,然后由connection 获取transaction ,sessionFactory 获取connection 的时候,就将connection 放入 threadlocal[和线程绑定]。
下面正式执行我们的业务逻辑:比如permissionDAO 中的 save(); save()中必然要使用到数据库的connection 。我们从哪里获取 呢, permissionDAO中不是有传进sessionFactory 吗?和myTransactionManager 从sessionFactory获取connention 的道理一样, save()中用到的 connection也从 sessionFactory 获取,那么 此时从sessionFactory 获取的connection就是之前放入threadlocal的connection ,save() 执行完毕。
在提交[commit]或回滚[rollback] 的时候我们获取的还是之前放入threadlocal的connection ,为此整个事务的开始到结束 我们使用的都是 同一个 connection。
这就是 普通 jdbc transaction 结合 spring aop
那 jta 又是怎么个情况呢?
我们直接从 jta 使用spring aop 的配置入手。
<!-- jta 事务-->
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" />
<bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction" ref="jotm" />
</bean>
<!-- XAdataSource-->
<bean id="innerDataSource" class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
<property name="transactionManager" ref="jotm"/>
<property name="driverName">
<value>${datasource.driverClassName}</value>
</property>
<property name="url">
<value>${datasource.url}</value>
</property>
<property name="user">
<value>${datasource.username}</value>
</property>
<property name="password">
<value>${datasource.password}</value>
</property>
<property name="maxCon" value="50" />
<property name="minCon" value="5" />
<property name="preparedStmtCacheSize" value="5"/>
</bean>
<!-- 对 innerDataSource 进行pool 包装-->
<bean id="dataSource" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
<property name="dataSource" ref="innerDataSource"/>
<property name="user" value="root"/>
<property name="password" value=""/>
<property name="minSize" value="2"/>
<property name="maxSize" value="50"/>
<property name="deadLockMaxWait" value="1000"/>
<property name="deadLockRetryWait" value="600"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="mappingResources">
......
</property>
</bean>
<!-- 配置事务处理 -->
<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="jtaTransactionManager" />
</property>
<property name="transactionAttributes">
.....
</property>
</bean>
<!-- 配置事物处理 -->
<!-- about permission DAO -->
<bean id="permissionDAO"
class="sezelee.sample.bbsse.dao.hibernate.PermissionHibernateDAO">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
那么这段代码和 上面的jdbc transaction 有什么不同呢 ?
此时 transactionManager[jtaTransactionManager] 传入的不在是sessionFactory ,而是 jtom。
jtom 到底是什么 呢 ,不用着急我们 往下看, 仔细看 innerDataSource 有什么不同,多了一个jotm。
这是为什么呢?
我们还是从 permissionDAO 的事务拦截的调用过程 开始 [关注的是transaction 的流向]:
假设代码 调用 permissionDAO 的某个方法之前事务拦截,
比如说 update() 方法: 里面需要获取 两个 connection [来至不同的数据源]。
比如 第一个来至 datesource1 、 第二个来至 datesource2
还记得 innerDataSource 中 配置的jtom 吗?
通过 sessionFactory 我们获取 第一个 datesource1 的 connention 时 将connention 放入jtom。我们获取 第二个 datesource2 的 connention 时将connention 放入jtom
jtom 也同时传到了jtaTransactionManager ,update() 方法业务执行完毕。
在提交[commit]或回滚[rollback] 的时候 ,我们就从 jtaTransactionManager 中 的 jtom 获取datesource1 的 connention、datesource2 的 connention
然后加上这样的逻辑 ,只要其中有一个异常 ,就全部rollback。
try{ datesource1.connention.transaction.commit datesource2.connention.transaction.commit
}catch(Exception e){
datesource1.connention.transaction.rollback
datesource2.connention.transaction.rollback
}
所以我们 进行数据库操作的 connention 都是放入jtom或从jtom获取[其实jtom 的connection 还是 绑定到 threadlocal] 。
我们 就简单的将 jtom 理解为 一个 map , 获取connection 时将 connection放入这个map。然后 我们 将map 传给transactionManager ,当事务要提交/回滚的时候我们从transactionManager 获取这个map
spring 给我们提供了这样一个transactionManager [jtatransactionManager]。
以上就是对[用XADataSource产生的XAConnection它扩展了一个getXAResource()方法,事务通过这个方法把它加入到事务容器中进行管理] 这句话的解释。
到此我们 回到 刚开始的切入点:为什么要使用 xa datesource。
xa datesource 提供了 在获取 connecntion时 将connecntion放入 jtom 的支持。
而 datesource 是没有提供这种 支持的。
好了 !全文结束 ,以上是我对 jta 的个人理解 ,有不对的地方,请大家指点!