【Spring】通过动态代理改进银行转账事务控制

前情

银行转账的案例中,通过给业务层实现类中每个方法中通过事务控制方法添加事务控制,保证每个方法在执行时只有一个数据库连接,通过事务保证整个方法要成功全部成功,要失败都失败。

问题

业务层实现类添加事务控制后,每个方法变得很重复,可不可以让事务控制从业务层中抽离

解决

代码结构:此处省略标记为蓝色类的代码
在这里插入图片描述
beanFactory

package com.itheima.factory;


import com.itheima.service.IAccountService;
import com.itheima.utils.TransactionManager;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 用于创建service的代理对象的bean工厂
 */
public class BeanFactory {

    private IAccountService accountService;

    private TransactionManager txManager;
    public final void setTxManager(TransactionManager txManager) {
        this.txManager = txManager;
    }
    /**
     * 获取Service代理对象
     * @return
     */
    public IAccountService getAccountService()
    {
        return (IAccountService)Proxy.newProxyInstance(accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() {
            /**
             * 添加事务的支持
             * @param proxy
             * @param method
             * @param args
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object rtValue=null;
                try {
                    //1.开启事务
                    txManager.beginTransaction();
                    //2.执行操作
                    rtValue=method.invoke(accountService,args);
                    //3.提交事务
                    txManager.CommitTransaction();
                    //4.返回结果
                    return rtValue;
                } catch (Exception e) {
                    //5.回滚操作
                    txManager.rollbackTransaction();
                    //e.printStackTrace();
                    throw new RuntimeException(e); //这样写后,产生异常程序不再执行
                } finally {
                    //6.释放连接
                    txManager.releaseTransaction();
                }
            }
        });
    }

    public void setAccountService(IAccountService accountService)
    {
        this.accountService = accountService;
    }
}

业务层实现类

package com.itheima.service.impl;

import com.itheima.dao.IAccountDao;
import com.itheima.domain.Account;
import com.itheima.service.IAccountService;


import java.util.List;

/**
 * 账户的业务成层实现类
 * 事务控制应该都是在业务层
 */
public class AccountServiceImpl implements IAccountService {

    private IAccountDao accountDao;
    public void setAccountDao(IAccountDao accountDao) {
        this.accountDao = accountDao;
    }

   /* private TransactionManager txManager;
    public void setTxManager(TransactionManager txManager) {
        this.txManager = txManager;
    }*/

    @Override
    public List<Account> findAllAccount() {
        return accountDao.findAllAccount();
    }

    @Override
    public Account findAccountById(Integer accountId) {
        return accountDao.findAccountById(accountId);
    }

    @Override
    public void saveAccount(Account account) {
      accountDao.findAllAccount();

    }

    @Override
    public void updateAccount(Account account) {
       accountDao.findAllAccount();
    }

    @Override
    public void deleteAccount(Integer accountId) {
         accountDao.findAllAccount();
    }

    @Override
    public void transfer(String sourceName, String targetName, Float money){
            //1.根据名称查询转出账户
            Account source=accountDao.findAccountByName(sourceName); //获取一个数据库连接
            //2.根据名称查询转入账户
            Account target=accountDao.findAccountByName(targetName); //获取一个数据库连接
            //3.转出账户减钱
            source.setMoney(source.getMoney()-money);
            //4.转入账户加钱
            target.setMoney(target.getMoney()+money);
            //5.更新转出账户
            accountDao.updateAccount(source); //获取一个数据库连接
            //6.更新转入账户
            accountDao.updateAccount(target); //获取一个数据库连接

    }

}

bean.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置代理的service-->
    <bean id="proxyAccountService" factory-bean="beanFactory" factory-method="getAccountService"></bean>
    <!--配置beanfactory-->
    <bean id="beanFactory" class="com.itheima.factory.BeanFactory">
        <!--注入service-->
        <property name="accountService" ref="accountService"></property>
        <property name="txManager" ref="txManager"></property>
    </bean>
    <!--配置Service-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <!--注入dao-->
        <property name="accountDao" ref="accountDao"></property>
        <!--&lt;!&ndash;注入事务管理器&ndash;&gt;
        <property name="txManager" ref="txManager"></property>-->
    </bean>
    <!--配置dao对象-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <!--注入QueryRunner-->
        <property name="runner" ref="runner"></property>
        <!--注入ConnectionUtils-->
        <property name="connectionUtils" ref="connectionUtils"></property>
    </bean>
    <!--配置QueryBean-->
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner">
        <!--&lt;!&ndash;配置数据源&ndash;&gt;
        <constructor-arg name="ds" ref="dataSource"></constructor-arg>-->
    </bean>

    <!--配置数据源-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--连接数据库的四大必备信息-->
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/eesy"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <!--配置Connection的工具类 ConnectionUtils-->
    <bean id="connectionUtils" class="com.itheima.utils.ConnectionUtils">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--配置事务管理器-->
    <bean id="txManager" class="com.itheima.utils.TransactionManager">
        <!--注入ConnectionUtils-->
        <property name="connectionUtils" ref="connectionUtils"></property>
    </bean>

</beans>

测试类:

package com.itheima.test;

import com.itheima.domain.Account;
import com.itheima.service.IAccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

/**
 * 使用Junited单元测试,测试我们的配置
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class AccountServiceTest {

    @Autowired
    @Qualifier("proxyAccountService")
    private IAccountService as;
    @Test
    public void testTransfer(){

        as.transfer("aaa","bbb",100f);

    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值