前情

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

问题

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

解决

代码结构:此处省略标记为蓝色类的代码

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*/@Overridepublic 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;}*/@Overridepublic List<Account> findAllAccount() {return accountDao.findAllAccount();}@Overridepublic Account findAccountById(Integer accountId) {return accountDao.findAccountById(accountId);}@Overridepublic void saveAccount(Account account) {accountDao.findAllAccount();}@Overridepublic void updateAccount(Account account) {accountDao.findAllAccount();}@Overridepublic void deleteAccount(Integer accountId) {accountDao.findAllAccount();}@Overridepublic 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/beanshttps://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;@Testpublic void testTransfer(){as.transfer("aaa","bbb",100f);}}

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

  1. spring的动态代理,碰到了一个类型转换的问题:java.lang.ClassCastException: com.sun.proxy.$Proxy16 cannot be cast to com.

    spring的动态代理,碰到了一个类型转换的问题: java.lang.ClassCastException: com.sun.proxy.$Proxy16 cannot be cast to com ...

  2. Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题

    Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题 参考文章: (1)Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代 ...

  3. Spring的动态代理原理

    Spring动态代理原理 Spring动态代理有两种:CGLIB动态代理和JDK动态代理. JDK动态代理可以代理接口,不能代理没有实现接口的类:而CGLIB通过字节码技术可以动态生成被代理类的子类, ...

  4. 【Spring】spring基于注解的声明式事务控制

    结构 domin package com.itheima.domain;import java.io.Serializable;public class Account implements Seri ...

  5. 【spring】spring基于xml的声明式事务控制

    结构 domain package com.itheima.domain;import java.io.Serializable;public class Account implements Ser ...

  6. spring基于注解的声明式事务控制

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...

  7. spring基于XML的声明式事务控制-配置步骤

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...

  8. Spring CGLlB动态代理

    JDK 动态代理使用起来非常简单,但是有一定的局限性,这是因为 JDK 动态代理必须要实现一个或多个接口,如果不希望实现接口,则可以使用 CGLIB 代理. CGLIB(Code Generation ...

  9. Spring JDK动态代理

    JDK 动态代理是通过 JDK 中的 java.lang.reflect.Proxy 类实现的.下面通过具体的案例演示 JDK 动态代理的使用. 1. 创建项目 在 MyEclipse 中创建一个名称 ...

最新文章

  1. git 初次push
  2. from selenium.webdriver.support.ui import Select
  3. .net操纵xml文件类(c#)
  4. 从代理机制到Spring AOP,这篇给你安排的明明白白的
  5. 十个模块_专栏 | ABAQUS Part模块的十个小技巧
  6. phtml php,PHTML Encoder
  7. c#正则表达式应用实例
  8. shop++源码反编译----随笔
  9. OSPF综合实验(有点难哦!)
  10. 操作系统面试常问问题
  11. Arduino的软件:Arduino IDE和Mind+图形化编程
  12. 地图编辑器开发(四)
  13. 全国计算机二级c语言上机考试软件,考前刷题专用
  14. CreateProcess并隐藏窗口
  15. python-一些文件相关的操作
  16. 腾讯云认证证书——云计算行业的敲门砖
  17. uniapp 模块权限配置 权限管理 权限设置
  18. Java面试基础(二)
  19. 吸粉神器——维盟智慧wifi,微信粉丝生产基地!
  20. 17位时间戳转换为Unix时间戳及转换工具,代码实现转换 WebKit/Chrome Timestamp Converter

热门文章

  1. 是否存在分布式的【大泥球】?
  2. 计算机如何表示色彩?
  3. 斯坦福CS224n、CMU NLP公开课 播放地址
  4. Springboot 多文件上传
  5. kali安装vscode和无法启动解决方法
  6. 聊一聊Spring中的线程安全性
  7. 黎曼曲面Riemann Surface
  8. 关键任务应用程序依赖于故障保护存储器
  9. 深度学习点云语义分割:CVPR2019论文阅读
  10. Android自定义View基本步骤