java事务笔记【2】

一. 前言:

上一篇文章中, 我们讲了使用动态代理完成事务处理, 这种方式将service层的所有public方法都加入事务中, 这显然不是我们需要的,我们需要代理的只是那些需要更改数据库的方法, 在本篇文章中, 我们将使用Java注解来标记需要处理事务的方法.


二. 实例:

1. 代码结构图:



2. 自定义注解:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Target (ElementType.METHOD)  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. public @interface  Transactional{  
  4. }  


3. 代理类:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 动态代理 
  3.  */  
  4. public class TransactionProxy {  
  5.   
  6.     public static Object proxyFor(Object object) {  
  7.         return Proxy.newProxyInstance(  
  8.                                         object.getClass().getClassLoader(),   
  9.                                         object.getClass().getInterfaces(),   
  10.                                         new TransactionInvocationHandler(object)  
  11.                                      );  
  12.     }  
  13. }  
  14.   
  15. class TransactionInvocationHandler implements InvocationHandler {  
  16.     private Object proxy;  
  17.   
  18.     TransactionInvocationHandler(Object object) {  
  19.         this.proxy = object;  
  20.     }  
  21.   
  22.     public Object invoke(Object obj, Method method, Object[] objects) throws Throwable {  
  23.         Method originalMethod = proxy.getClass().getMethod(method.getName(), method.getParameterTypes());  
  24.         // 判断方法上是否有Transactional注解  
  25.         if (!originalMethod.isAnnotationPresent(Transactional.class)) {  
  26.             // 没有注解, 直接调用方法不用控制事务  
  27.             return method.invoke(proxy, objects);  
  28.         }  
  29.   
  30.         TransactionManager.beginTransaction();  
  31.         Object result = null;  
  32.         try {  
  33.             result = method.invoke(proxy, objects);  
  34.             TransactionManager.commit();  
  35.         } catch (Exception e) {  
  36.             TransactionManager.rollback();  
  37.         } finally {  
  38.             TransactionManager.close();  
  39.         }  
  40.         return result;  
  41.     }  
  42. }  

在TransactionInvocationHandle的invoke方法中, 首先判断被代理的方法是否标记有Transactional注解, 

如果没有则直接调用method.invoke(proxy, objects), 否则, 进入事务处理代码.


4. 业务代码类:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 业务逻辑层 
  3.  */  
  4. public class AccountServiceImpl implements AccountService {  
  5.       
  6.     @Override  
  7.     @Transactional  
  8.     public void transfer(Account outAccount, Account inAccount, int money) throws SQLException {  
  9.         // 查询两个账户  
  10.         AccountDAO accountDAO = new AccountDAO();  
  11.         outAccount = accountDAO.findAccountById(outAccount.getId());  
  12.         inAccount = accountDAO.findAccountById(inAccount.getId());  
  13.   
  14.         // 转账 - 修改原账户金额   
  15.         outAccount.setMoney(outAccount.getMoney() - money);  
  16.         inAccount.setMoney(inAccount.getMoney() + money);  
  17.           
  18.         // 更新账户金额  
  19.         accountDAO.update(outAccount);  
  20.         accountDAO.update(inAccount);  
  21.     }  
  22. }  
在方法上标注使用注解.


参考文章:http://www.davenkin.me/post/2013-02-24/40048572306

源码下载: http://download.csdn.net/detail/zdp072/7908913

一. 前言:

在写这篇博客之前,我们需要弄清楚两个概念:本地事务和分布式事务。

本地事务:只处理单一数据源,比如单个数据库。

分布式事务:处理多种异构的数据源, 比如某个业务操作中同时包含JDBC和JMS或者某个操作需要访问多个不同的数据库。


Java通过JTA完成分布式事务, JTA本身只是一种规范, 本篇博客将使用JOTM作为实现, 后续还会使用Atomikos实现。


二. 业务背景:

假定我们有这样一个需求:当我们新建一个用户的时候需要往一个DB中插入一条用户记录,还需要往另一个DB中记录日志

因为是不同的DB操作,所以这里就涉及到分布式事务的处理。


三. 代码实现:

1. 代码结构图:


2. 建表语句:

[sql]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. create database log;  
  2. DROP TABLE IF EXISTS `log`;  
  3. CREATE TABLE `log` (  
  4.   `id` varchar(20) NOT NULL,  
  5.   `content` varchar(100) default NULL,  
  6.   PRIMARY KEY  (`id`)  
  7. );  
  8.   
  9. create database user;  
  10. DROP TABLE IF EXISTS `user`;  
  11. CREATE TABLE `user` (  
  12.   `id` varchar(20) NOT NULL,  
  13.   `namevarchar(40) default NULL,  
  14.   PRIMARY KEY  (`id`)  
  15. );  

3. 配置文件ApplicationContext.xml
[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.  xmlns:aop="http://www.springframework.org/schema/aop"  
  5.  xmlns:tx="http://www.springframework.org/schema/tx"  
  6.  xsi:schemaLocation="http://www.springframework.org/schema/beans   
  7.                      http://www.springframework.org/schema/beans/spring-beans.xsd   
  8.                      http://www.springframework.org/schema/tx   
  9.                      http://www.springframework.org/schema/tx/spring-tx.xsd   
  10.                      http://www.springframework.org/schema/aop   
  11.                      http://www.springframework.org/schema/aop/spring-aop.xsd">  
  12.       
  13.     <!-- 引用Spring内部所提供的对JOTM支持的工厂类 -->  
  14.     <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" />  
  15.       
  16.     <!-- 配置JTA事务管理器, 并在管理器中使用上面所配置的JOTM -->  
  17.     <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">  
  18.         <property name="userTransaction" ref="jotm" />  
  19.     </bean>  
  20.       
  21.     <!-- 配置多个数据源 -->  
  22.     <bean id="db1" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">  
  23.         <property name="dataSource">  
  24.             <bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">  
  25.                 <property name="transactionManager" ref="jotm" />  
  26.                 <property name="driverName" value="com.mysql.jdbc.Driver" />  
  27.                 <property name="url" value="jdbc:MySQL://localhost:3306/user" />  
  28.             </bean>  
  29.         </property>  
  30.         <property name="user" value="root" />  
  31.         <property name="password" value="root" />  
  32.     </bean>  
  33.   
  34.     <bean id="db2" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">  
  35.         <property name="dataSource">  
  36.             <bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">  
  37.                 <property name="transactionManager" ref="jotm" />  
  38.                 <property name="driverName" value="com.mysql.jdbc.Driver" />  
  39.                 <property name="url" value="jdbc:MySQL://localhost:3306/log" />  
  40.             </bean>  
  41.         </property>  
  42.         <property name="user" value="root" />  
  43.         <property name="password" value="root" />  
  44.     </bean>  
  45.       
  46.     <!-- 根据不同的数据源配置两个jdbcTemplate -->  
  47.     <bean id="jdbcTemplate1" class="org.springframework.jdbc.core.JdbcTemplate">  
  48.         <property name="dataSource" ref="db1" />  
  49.     </bean>  
  50.   
  51.     <bean id="jdbcTemplate2" class="org.springframework.jdbc.core.JdbcTemplate">  
  52.         <property name="dataSource" ref="db2" />  
  53.     </bean>  
  54.   
  55.     <bean id="userDao" class="com.zdp.dao.UserDao">  
  56.         <property name="jdbcTemplate" ref="jdbcTemplate1" />  
  57.     </bean>  
  58.   
  59.     <bean id="logDao" class="com.zdp.dao.LogDao">  
  60.         <property name="jdbcTemplate" ref="jdbcTemplate2" />  
  61.     </bean>  
  62.   
  63.     <bean id="userService" class="com.zdp.service.UserService">  
  64.         <property name="userDao" ref="userDao" />  
  65.         <property name="logDao" ref="logDao" />  
  66.     </bean>  
  67.       
  68.     <!-- JTA事务传播特性 -->  
  69.     <tx:advice id="txAdviceJTA" transaction-manager="txManager">  
  70.         <tx:attributes>  
  71.             <tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" rollback-for="Exception"/>  
  72.             <tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED" rollback-for="Exception"/>  
  73.             <tx:method name="create*" isolation="DEFAULT" propagation="REQUIRED" rollback-for="Exception"/>  
  74.             <tx:method name="insert*" isolation="DEFAULT" propagation="REQUIRED" rollback-for="Exception"/>  
  75.             <tx:method name="del*" isolation="DEFAULT" propagation="REQUIRED" rollback-for="Exception"/>  
  76.             <tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" rollback-for="Exception"/>  
  77.             <tx:method name="*" read-only="true"/>   
  78.         </tx:attributes>  
  79.     </tx:advice>  
  80.       
  81.     <aop:config>  
  82.         <aop:advisor pointcut="execution(* com.zdp.service..*(..))"   advice-ref="txAdviceJTA" />  
  83.     </aop:config>  
  84. </beans>    

4. service业务类:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class UserService {  
  2.     private UserDao userDao;  
  3.     private LogDao logDao;  
  4.   
  5.     public void saveUser(String id, String name) {  
  6.         userDao.insertUser(id, name);  
  7.         // int i = 1 / 0;  // 制造异常  
  8.         logDao.insertLog(id, id + "_" + name);  
  9.     }  
  10.   
  11.     public UserDao getUserDao() {  
  12.         return userDao;  
  13.     }  
  14.   
  15.     public void setUserDao(UserDao userDao) {  
  16.         this.userDao = userDao;  
  17.     }  
  18.   
  19.     public LogDao getLogDao() {  
  20.         return logDao;  
  21.     }  
  22.   
  23.     public void setLogDao(LogDao logDao) {  
  24.         this.logDao = logDao;  
  25.     }  
  26. }  

5. Dao类:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class UserDao extends JdbcDaoSupport {  
  2.     public void insertUser(String id, String name) {  
  3.         JdbcTemplate template = getJdbcTemplate();  
  4.         template.execute("insert into user values('" + id + "','" + name + "')");  
  5.     }  
  6. }  

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class LogDao extends JdbcDaoSupport {  
  2.     public void insertLog(String id, String content) {  
  3.         JdbcTemplate template = getJdbcTemplate();  
  4.         template.execute("insert into log values('" + id + "','" + content + "')");  
  5.     }  
  6. }  

6. 测试类:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class UserTest {  
  2.     @Test  
  3.     public void testSave() {  
  4.         ApplicationContext cxt = new ClassPathXmlApplicationContext("ApplicationContext.xml");  
  5.         UserService us = (UserService) cxt.getBean("userService");  
  6.         us.saveUser("1""zhangsan");  
  7.     }  
  8. }  


源码下载: http://download.csdn.net/detail/zdp072/7950383

一. 前言:

上一篇博客中,我们使用jotm实现了分布式事务, 本篇将使用atomikos实现。

基本的代码都是一样的,就是配置略有不同。


二. 代码实现:

1. 代码结构图:


2. 配置文件:ApplicationContext.xml

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.  xmlns:aop="http://www.springframework.org/schema/aop"  
  5.  xmlns:tx="http://www.springframework.org/schema/tx"  
  6.  xsi:schemaLocation="http://www.springframework.org/schema/beans   
  7.                      http://www.springframework.org/schema/beans/spring-beans.xsd   
  8.                      http://www.springframework.org/schema/tx   
  9.                      http://www.springframework.org/schema/tx/spring-tx.xsd   
  10.                      http://www.springframework.org/schema/aop   
  11.                      http://www.springframework.org/schema/aop/spring-aop.xsd">  
  12.       
  13.     <!-- 数据库1 -->  
  14.     <bean id="db1" class="com.atomikos.jdbc.SimpleDataSourceBean" init-method="init" destroy-method="close">     
  15.         <property name="uniqueResourceName">     
  16.             <value>mysql/main</value>     
  17.         </property>     
  18.         <property name="xaDataSourceClassName">     
  19.             <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>     
  20.         </property>     
  21.         <property name="xaDataSourceProperties">     
  22.             <value>URL=jdbc:mysql://localhost:3306/user?useUnicode=true&characterEncoding=utf-8;user=root;password=root</value>     
  23.         </property>     
  24.         <property name="exclusiveConnectionMode">     
  25.             <value>true</value>     
  26.         </property>     
  27.         <property name="connectionPoolSize">     
  28.             <value>3</value>     
  29.         </property>     
  30.         <property name="validatingQuery">     
  31.             <value>SELECT 1</value>     
  32.         </property>     
  33.     </bean>         
  34.       
  35.     <!-- 数据库2 -->  
  36.     <bean id="db2" class="com.atomikos.jdbc.SimpleDataSourceBean" init-method="init" destroy-method="close">     
  37.         <property name="uniqueResourceName">     
  38.             <value>mysql/secondary</value>     
  39.         </property>     
  40.         <property name="xaDataSourceClassName">        
  41.             <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>     
  42.         </property>  
  43.         <property name="xaDataSourceProperties">     
  44.             <value>URL=jdbc:mysql://localhost:3306/log?useUnicode=true&characterEncoding=utf-8;user=root;password=root</value>     
  45.         </property>  
  46.         <property name="exclusiveConnectionMode">     
  47.             <value>true</value>     
  48.         </property>  
  49.         <property name="connectionPoolSize">     
  50.             <value>3</value>     
  51.         </property>  
  52.         <property name="validatingQuery">  
  53.             <value>SELECT 1</value>     
  54.         </property>     
  55.     </bean>       
  56.       
  57.     <bean id="userTransactionManager" init-method="init" destroy-method="close"  
  58.         class="com.atomikos.icatch.jta.UserTransactionManager">     
  59.         <property name="forceShutdown" value="true" />     
  60.     </bean>  
  61.       
  62.     <bean id="userTransactionImp" class="com.atomikos.icatch.jta.UserTransactionImp">     
  63.         <property name="transactionTimeout" value="300"/>      
  64.     </bean>  
  65.       
  66.     <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">     
  67.         <property name="transactionManager" ref="userTransactionManager" />  
  68.         <property name="userTransaction" ref="userTransactionImp" />  
  69.         <property name="allowCustomIsolationLevels" value="true"/>   
  70.     </bean>  
  71.       
  72.     <!-- 配置事务传播特性 -->  
  73.     <tx:advice id="txAdvice" transaction-manager="jtaTransactionManager">  
  74.         <tx:attributes>  
  75.            <tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>  
  76.            <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/>  
  77.            <tx:method name="create*" propagation="REQUIRED" rollback-for="Exception"/>  
  78.            <tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception"/>  
  79.            <tx:method name="del*" propagation="REQUIRED" rollback-for="Exception"/>  
  80.            <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>  
  81.            <tx:method name="*" read-only="true"/>  
  82.        </tx:attributes>  
  83.     </tx:advice>  
  84.       
  85.     <!-- 事务管理 -->  
  86.     <aop:config proxy-target-class="true">  
  87.         <aop:advisor pointcut="execution(* com.zdp.service..*.*(..))" advice-ref="txAdvice"/>  
  88.     </aop:config>  
  89.       
  90.     <bean id="userDao" class="com.zdp.dao.UserDao">  
  91.         <property name="dataSource" ref="db1" />  
  92.     </bean>  
  93.       
  94.     <bean id="logDao" class="com.zdp.dao.LogDao">  
  95.         <property name="dataSource" ref="db2" />  
  96.     </bean>  
  97.       
  98.     <bean id="userService" class="com.zdp.service.UserService">  
  99.         <property name="userDao" ref="userDao" />  
  100.         <property name="logDao" ref="logDao" />              
  101.     </bean>  
  102. </beans>    
其他的代码请参见上一篇博客。

源码下载: http://download.csdn.net/detail/zdp072/7950391

转载于:https://my.oschina.net/liting/blog/420061

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值