数据库事务(五):利用动态代理实现事务处理

上一篇我们利用template模式实现事务处理,把实际对业务逻辑交给子类去实现,这样对话在service层中,我们只需要声明一个transactionTemplate即可完成事务处理。
本文通过另一种方法在service层隐藏事务对开启、提交或回滚,那就是动态代理(dynamic proxy)。

java动态代理原理:被代理对象proxied实现接口interface,同时声明一个代理对象proxy,也实现interface接口,且代理对象proxy会拦截被代理对象proxied的所有方法,并在proxied方法的前后加入事务处理的通用方法。

首先定义一个实际的业务类,对需要启动事务处理的方法添加@Transactional注解,比如transfer方法:

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

    public BankServiceImpl(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();  
        }  
    }  
} 

接下来需创建代理类对BankService进行拦截,绑定代理类proxy与被代理类proxied需要实现InvocationHandler接口:

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

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

    public Object invoke(Object o, Method method, Object[] params) throws Throwable  
    {   
        //判断是否被@Transactional注解
        Method originalMethod = proxied.getClass().getMethod(method.getName(), method.getParameterTypes());  
        if (!originalMethod.isAnnotationPresent(Transactional.class))  
        {  
            return method.invoke(proxied, params);  
        } 

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

invoke方法将被代理proxy调用,且判断拦截方法是否由@Transactional,以及事务的开启提交回滚等操作,并且通过反射执行实际的业务处理方法:result = method.invoke(proxied, params) 。

然后在客户代码中,我们需要先创建代理对象(这在Spring中通常是通过配置实现的),代理类的创建可以使用Proxy类的静态方法newProxyInstance。

    @Test  
    public void transferTest() throws SQLException  
    {   
        BankService bankService = new BankServiceImpl(dataSource);  
        BankService proxyBankService = (BankService)Proxy.newProxyInstance(bankService.getClass().getClassLoader(),bankService.getClass().getInterfaces(),new ProxyHandler(bankService,dataSource));  

        int toNonExistId = 3333;  
        proxyBankService.transfer(1111, toNonExistId, 200);  
        assertEquals(1000, getBankAmount(1111));  
        assertEquals(1000, getInsuranceAmount(2222));  
    } 

以上即为java动态代理实现事务处理,可知在实际的业务代码中我们无需关注事务处理的逻辑,只需要对需要事务处理的业务方法加上@Transactional即可轻松搞定。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值