Spring AOP(简单的转账实现)

转账功能

新建数据库

在这里插入图片描述

导包

<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.2.13.RELEASE</version>
    <scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->
<dependency>
    <groupId>commons-dbutils</groupId>
    <artifactId>commons-dbutils</artifactId>
    <version>1.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.23</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>

配置文件

在这里插入图片描述

配置数据源

在这里插入图片描述

编写代码

数据库连接工具类:ConnectionUtils.java

 package utils;
 @Component
public class ConnectionUtils {
private ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
@Autowired
private ComboPooledDataSource dataSource;
/**
 * 获得当前线程绑定的连接
 *
 * @return
 */
public Connection getThreadConnection() {
    try {
        // 看线程是否绑了连接
        Connection conn = tl.get();
        if (conn == null) {
            // 从数据源获取一个连接
            conn = dataSource.getConnection();
            // 和线程局部变量  绑定
            tl.set(conn);
        }
        // 返回线程连接
        return tl.get();
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
}

/**
 * 把连接和当前线程进行解绑
 */
public void remove() {
    tl.remove();
}
}

Account模块实体类:Account.java

package entity;
 
  public class Account {

private Integer id;
private String accountNum;
private Integer money;
public Integer getId(){ return id;}

public void setId(Integer id){ this.id = id;}

public String getAccountNum(){ return accountNum;}

public void setAccountNum(String accountNum){ this.accountNum = accountNum;}

public Integer getMoney(){
    return money;
}

public void setMoney(Integer money){
    this.money = money;
    }
}

Account模块Dao层:AccountDao.java

package dao;

public interface AccountDao {
void updateAccount(AccountDao accountDao);
Account findAccouontByNum(String accountNum);
}

Account模块Dao层实现类:AccountDaoImpl.java

 @Repository("accountDao")
 public class AccountDaoImpl implements AccountDao {
  @Autowired
  private QueryRunner runner;
@Autowired
private ConnectionUtils connectionUtils;
public void updateAccount(AccountDao account) {
    try{
        runner.update(ConnectionUtils.getThreadConnection(),
                "update account set accountNum=?,money=? where id=?",
                account.getAccountNum(), account.getMoney(), account.getId());
    }
    catch (SQLException e) {
        throw new RuntimeException(e);
    }
}
public Account findAccouontByNum(String accountNum) {

    List<Account> accounts = null;
    try {
        accounts = runner.query(ConnectionUtils.getThreadConnection(),
                "select * from account where accountNum = ? ",
                new BeanListHandler<Account>(Account.class),
                accountNum);
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
    if (accounts == null || accounts.size() == 0) {
        // 如果没有结果就返回null
        return null;
    } else if (accounts.size() > 1) {
        // 如果结果集超过一个就抛异常
        throw new RuntimeException("结果集不唯一,数据有问题");
    } else {
        // 如果有唯一的一个结果就返回
        return accounts.get(0);
    }
}

Account模块Service层:AccountService.java

package services;

public interface AccountService {
void transfer(String sourceAccount,String targetAccount, Integer money);

Account模块测试类:AccountTest.java

SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AccountTest {

@Autowired
private AccountService accountService;

@Test
public void testTransfer() {
    accountService.transfer("622200001", "622200002", 100);
  }
}

运行结果
在这里插入图片描述

数据库中修改前:
在这里插入图片描述
修改后:
在这里插入图片描述

可以看到转账成功。

加异常

//增加异常
 int a=1/0;

在这里插入图片描述
数据库数据异常如图
在这里插入图片描述
可以看到转账异常

引入代理模式

代码:
事务管理器:TransactionManager.java
package transaction;

 import org.springframework.beans.factory.annotation.Autowired;
 import utils.ConnectionUtils;

import java.sql.SQLException;

public class TransactionManager {
// 数据库连接工具类
@Autowired
private ConnectionUtils connectionUtils;

/**
 * 开启事务
 */
public void beginTransaction() {
    try {
        System.out.println("开启事务");
        connectionUtils.getThreadConnection().setAutoCommit(false);
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

/**
 * 提交事务
 */
public void commit() {
    try {
        System.out.println("提交事务");
        connectionUtils.getThreadConnection().commit();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

/**
 * 取消(回滚)事务
 */
public void rollback() {
    try {
        System.out.println("回滚事务");
        connectionUtils.getThreadConnection().rollback();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

/**
 * 释放连接
 */
public void release() {
    try {
        System.out.println("释放连接");
        connectionUtils.getThreadConnection().close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    connectionUtils.removeConnentiion();
}
}

事务代理工具类:TransactionProxyUtils

package utils;

@Component
public class TransactionProxyUtils {
//被代理的业务类接口
@Autowired
private AccountService accountService;
//提供事务管理的工具类
@Autowired
private TransactionManager transactionManager;

/**
 * 获取AccountService代理对象
 *
 * @return
 */
public AccountService getAccountService() {
    return (AccountService) Proxy.newProxyInstance(
            accountService.getClass().getClassLoader(),
            accountService.getClass().getInterfaces(),
            new InvocationHandler() {
                /**
                 * 添加事务的支持
                 *
                 * @param proxy     被代理的对象实例本身
                 * @param method    被代理对象正在执行的方法对象
                 * @param args      正在访问的方法参数对象
                 * @return
                 * @throws Throwable
                 */
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                    //
                    Object rtValue = null;
                    try {
                        // 执行操作前开启事务
                        transactionManager.beginTransaction();
                        // 执行操作
                        rtValue = method.invoke(accountService, args);
                        // 执行操作后提交事务
                        transactionManager.commit();
                        // 返回结果
                        return rtValue;
                    } catch (Exception e) {
                        // 捕捉到异常执行回滚操作
                        transactionManager.rollback();
                        throw new RuntimeException(e);
                    } finally {
                        // 最终释放连接
                        transactionManager.release();
                    }
                }
            });

 }
}

核心配置文件:applicationContext.xml

1、事务管理bean

      <context:component-scan base-package="transaction"/>

2、配置代理

 <!-- 配置代理的service-->
 <bean id="transactionProxyAccountService" factory-bean=
     "TransactionProxyUtils" factory-method="getAccountService"></bean>

Account模块:测试类

  @Qualifier("transactionProxyAccountService")

将数据库的金额改回1000元。

数据库中的数据修改后:
在这里插入图片描述

引入AOP(XML)

导入aspectjweaver包

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.3</version>
</dependency>

配置aop文件

  <!-- aop相关的节点配置 -->
    <aop:config>
<!-- 切入点  表示哪些类的哪些方法在执行的时候会应用Spring配置的通知进行增强 -->
<aop:pointcut expression="execution ( * services.*.*(..))" id="pc"/>
<!-- 配置切面类的节点  作用主要就是整合通知和切入点 -->
<aop:aspect ref="transactionManager">
    <aop:before method="beginTransaction" pointcut-ref="pc"/>
    <aop:after-returning method="commit" pointcut-ref="pc"/>
    <aop:after method="release" pointcut-ref="pc"/>
    <aop:after-throwing method="rollback" pointcut-ref="pc"/>
  </aop:aspect>
</aop:config>

改测试代码
在这里插入图片描述
数据库结果
在这里插入图片描述
加异常:
在这里插入图片描述
数据库中的数据没改变
在这里插入图片描述

XML该注解

代码
删除XML中的AOPXML配置并注解代理模式

  <!-- 注解  开启代理模式 -->
  <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

注释事务管理器类:TransactionManager.java

 package transaction;

  @Component
  @Aspect
public class TransactionManager {
// 数据库连接工具类
@Autowired
private ConnectionUtils connectionUtils;

@Pointcut("execution(* services.*.*(..))")
private void transactionPointcut() {
}

/**
 * 开启事务
 */
@Before("transactionPointcut()")
public void beginTransaction() {
    try {
        System.out.println("开启事务");
        connectionUtils.getThreadConnection().setAutoCommit(false);
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

/**
 * 提交事务
 */
@AfterReturning("transactionPointcut()")
public void commit() {
    try {
        System.out.println("提交事务");
        connectionUtils.getThreadConnection().commit();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

/**
 * 回滚事务
 */
@AfterThrowing("transactionPointcut()")
public void rollback() {
    try {
        System.out.println("回滚事务");
        connectionUtils.getThreadConnection().rollback();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

/**
 * 释放连接
 */
@After("transactionPointcut()")
public void release() {
    try {
        System.out.println("释放连接");
        connectionUtils.getThreadConnection().close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    connectionUtils.removeConnection();
 }
}

数据库修改后
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ai清

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值