Java事务处理全解析(七)—— 像Spring一样使用Transactional注解(Annotation)

转载 2013年12月02日 16:44:34

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


首先定义Transactional注解:

package davenkin.step6_annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional
{
}
使用注解标记事务的基本原理为:依然使用上一篇中讲到的动态代理的方式,只是在InvocationHandler的invoke方法中,首先判断被代理的方法是否标记有Transactional注解,如果没有则直接调用method.invoke(proxied, objects),否则,先准备事务,在调用method.invoke(proxied, objects),然后根据该方法是否执行成功调用commit或rollback。定义TransactionEnabledAnnotationProxyManager如下:

package davenkin.step6_annotation;

import davenkin.step3_connection_holder.TransactionManager;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class TransactionEnabledAnnotationProxyManager
{
    private TransactionManager transactionManager;

    public TransactionEnabledAnnotationProxyManager(TransactionManager transactionManager)
    {

        this.transactionManager = transactionManager;
    }

    public Object proxyFor(Object object)
    {
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), new AnnotationTransactionInvocationHandler(object, transactionManager));
    }
}

class AnnotationTransactionInvocationHandler implements InvocationHandler
{
    private Object proxied;
    private TransactionManager transactionManager;

    AnnotationTransactionInvocationHandler(Object object, TransactionManager transactionManager)
    {
        this.proxied = object;
        this.transactionManager = transactionManager;
    }

    public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable
    {
        Method originalMethod = proxied.getClass().getMethod(method.getName(), method.getParameterTypes());
        if (!originalMethod.isAnnotationPresent(Transactional.class))
        {
            return method.invoke(proxied, objects);
        }

        transactionManager.start();
        Object result = null;
        try
        {
            result = method.invoke(proxied, objects);
            transactionManager.commit();
        } catch (Exception e)
        {
            transactionManager.rollback();
        } finally
        {
            transactionManager.close();
        }
        return result;
    }
}

可以看到,在AnnotationTransactionInvocationHandler的invoke方法中,我们首先获得原service的transfer方法,然后根据originalMethod.isAnnotationPresent(Transactional.class)判断该方法是否标记有Transactional注解,如果没有,则任何额外功能都不加,直接调用原来service的transfer方法;否则,将其加入到事务处理中。



在service层中,我们只需将需要加入事务处理的方法用Transactional注解标记就行了:

package davenkin.step6_annotation;

import davenkin.BankService;
import davenkin.step3_connection_holder.ConnectionHolderBankDao;
import davenkin.step3_connection_holder.ConnectionHolderInsuranceDao;

import javax.sql.DataSource;

public class AnnotationBankService implements BankService
{
    private ConnectionHolderBankDao connectionHolderBankDao;
    private ConnectionHolderInsuranceDao connectionHolderInsuranceDao;

    public AnnotationBankService(DataSource dataSource)
    {
        connectionHolderBankDao = new ConnectionHolderBankDao(dataSource);
        connectionHolderInsuranceDao = new ConnectionHolderInsuranceDao(dataSource);
    }

    @Transactional
    public void transfer(final int fromId, final int toId, final int amount)
    {
        try
        {
            connectionHolderBankDao.withdraw(fromId, amount);
            connectionHolderInsuranceDao.deposit(toId, amount);
        } catch (Exception e)
        {
            throw new RuntimeException();
        }
    }
}

然后执行测试:

@Test
    public void transferFailure() throws SQLException
    {
        TransactionEnabledAnnotationProxyManager transactionEnabledAnnotationProxyManager = new TransactionEnabledAnnotationProxyManager(new TransactionManager(dataSource));
        BankService bankService = new AnnotationBankService(dataSource);
        BankService proxyBankService = (BankService) transactionEnabledAnnotationProxyManager.proxyFor(bankService);

        int toNonExistId = 3333;
        proxyBankService.transfer(1111, toNonExistId, 200);

        assertEquals(1000, getBankAmount(1111));
        assertEquals(1000, getInsuranceAmount(2222));
    }

测试运行成功,如果将AnnotationBankService中transfer方法的Transactional注解删除,那么以上测试将抛出RuntimeException异常,该异常为transfer方法中我们人为抛出的,也即由于此时没有事务来捕捉异常,程序便直接抛出该异常而终止运行。在下一篇(本系列最后一篇)文章中,我们将讲到分布式事务的一个入门例子。

Java事务处理全解析(七)—— 像Spring一样使用Transactional注解(Annotation)

在本系列的上一篇文章中,我们讲到了使用动态代理的方式完成事务处理,这种方式将service层的所有public方法都加入到事务中,这显然不是我们需要的,需要代理的只是那些需要操作数据库的方法。在本篇中...
  • qq_33824312
  • qq_33824312
  • 2017年05月07日 09:57
  • 232

Java事务处理全解析(七)—— 像Spring一样使用Transactional注解(Annotation)

在本系列的上一篇文章中,我们讲到了使用动态代理的方式完成事务处理,这种方式将service层的所有public方法都加入到事务中,这显然不是我们需要的,需要代理的只是那些需要操作数据库的方法。在本篇中...
  • SunshineLPL
  • SunshineLPL
  • 2017年05月02日 13:49
  • 150

Java事务处理全解析(七)—— 像Spring一样使用Transactional注解(Annotation)

在本系列的上一篇文章中,我们讲到了使用动态代理的方式完成事务处理,这种方式将service层的所有public方法都加入到事务中,这显然不是我们需要的,需要代理的只是那些需要操作数据库的方法。在本篇中...
  • huilangeliuxin
  • huilangeliuxin
  • 2015年02月03日 11:10
  • 7829

Java事务处理全解析(七)—— 像Spring一样使用Transactional注解(Annotation)

在本系列的上一篇文章中,我们讲到了使用动态代理的方式完成事务处理,这种方式将service层的所有public方法都加入到事务中,这显然不是我们需要的,需要代理的只是那些需要操作数据库的方法。在本篇中...
  • wushiwude
  • wushiwude
  • 2017年06月23日 17:35
  • 271

使用Spring中的 @Transactional注解控制事务

使用Spring中的 @Transactional注解控制事务
  • u013803262
  • u013803262
  • 2016年11月13日 17:05
  • 2443

@Transactional注解工作原理

一、配置好Bean实例 首先配置好DataSource和DataSourceTransactionManager这两个类的Bean实例 二、添加注解 在测试类上添加@Transactio...
  • DSLZTX
  • DSLZTX
  • 2015年06月25日 14:25
  • 9998

Spring提取@Transactional事务注解的源码解析

声明:本编文章是自己在查看Spring提取@Transactional注解的源码过程中随手记下的笔记,只做了大概流程的记录,未做详细分析,如有错误还请谅解。1、事务切面匹配处理类AopUtils#ca...
  • dalinsi
  • dalinsi
  • 2016年11月18日 12:35
  • 3945

Spring对注解(Annotation)处理源码分析2——解析和注入注解配置的资源

Spring对注解(Annotation)处理源码分析2——解析和注入注解配置的资源 标签: springwebservicebeannullstringejb 2011-04...
  • XRYMIBZ
  • XRYMIBZ
  • 2017年05月22日 16:42
  • 774

spring的@Transactional事务处理详解

参考地址:http://www.cnblogs.com/xusir/p/3650522.html 概述 事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一...
  • uestc_lxp
  • uestc_lxp
  • 2016年01月04日 16:20
  • 3975

spring中自定义注解(annotation)与AOP中获取注解

spring中自定义注解(annotation)与AOP中获取注解 标签: annotation aop sprin 2015-04-15 16:51 25410人阅读 评论(1) 举...
  • gaoqiao1988
  • gaoqiao1988
  • 2016年12月12日 17:06
  • 2766
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java事务处理全解析(七)—— 像Spring一样使用Transactional注解(Annotation)
举报原因:
原因补充:

(最多只允许输入30个字)