通过SpringAOP事务模拟转账

模拟转账操作之半xml半注解版(自定义事务管理)

1、pom.xml依赖

<dependencies>
    <!--Spring容器-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    <!--Spring aop-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
    <!--Spring 操作JDBC-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    <!--Mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>
    <!--Mybatis与Spring框架整合-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.1</version>
    </dependency>
    <!--Druid数据源-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.20</version>
    </dependency>
    <!--mysql数据库-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
        <scope>runtime</scope>
    </dependency>
    <!--junit单元测试-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    <!--lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

2、pojo实体类

package cn.bwm.pojo;

import lombok.Data;

/**
 * 账户实体类
 * @author bwm
 */
@Data
public class Account {
    private Integer id;
    private String name;
    private Double money;
}

3、Dao层接口

package cn.bwm.dao;

import cn.bwm.pojo.Account;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

/**
 * 账户dao层接口
 * @author bwm
 */
//@Repository
public interface AccountDao {

    /**
     * 通过name查询账户
     *
     * @param name 账户名称
     * @return 返回相应的账户实体类
     */
    @Select("select * from account where name=#{name}")
    Account findByName(@Param("name") String name);

    /**
     * 更新账户
     *
     * @param account 返回更新后的账户信息
     */
    @Update("update account set name=#{name}, money=#{money} where id=#{id}")
    void updateAccount(Account account);
}

4、数据源jdbc.properties

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis01?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=root

5、Spring核心配置文件applicationContext.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--加载数据源-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!--配置DruidDateSource连接池-->
    <bean id="druidDateSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--配置SqlSessionFactoryBean-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--关联数据源-->
        <property name="dataSource" ref="druidDateSource"/>
        <!--给pojo起别名-->
        <property name="typeAliasesPackage" value="cn.bwm.pojo"/>
    </bean>

    <!--配置MapperScannerConfigurer,扫描mybatis生成的dao层接口-->
    <bean  class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="cn.bwm.dao"/>
    </bean>

    <!--通知spring识别IOC相关注解-->
    <context:component-scan base-package="cn.bwm"/>

    <!--通知spring识别AOP相关注解-->
    <aop:aspectj-autoproxy/>

</beans>

6、自定义转账事务管理类

package cn.bwm.util;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * 自动以事务管理类
 * @author bwm
 */
@Component
@Aspect
public class TransationManager {
    /*
        注解说明:
        @Component 将当前类交给Spring管理
        @Aspect 切面增强
        @PostConstruct 声明当前方法是初始化方法
        @Around("execution(* cn.bwm.service..*.*(..))") 环绕增强
        execution(修饰符 返回值 包名.类名/接口名.方法名(参数列表))
    */

    /**
     * 获取连接池
     */
    @Autowired
    @Qualifier("druidDateSource")
    private DataSource dataSource;

    /**
     * 声明Connection连接对象
     */
    private static Connection connection = null;

    /**
     * 声明业务层和数据层使用同一个连接对象
     * 创建Connection连接对象
     */
    @PostConstruct
    public void init(){
        TransactionSynchronizationManager.initSynchronization();
        connection = DataSourceUtils.getConnection(dataSource);
    }

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

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

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

    /**
     * 关闭资源
     */
    public void close(){
        System.out.println("5 关闭资源......");
        try {
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 环绕增强
     */
    @Around("execution(* cn.bwm.service..*.*(..))")
    public Object aroundTransation(ProceedingJoinPoint joinPoint) {
        Object result = null;
        try {
            //开启事务
            this.begin();
            //执行业务相关操作
            Object[] args = joinPoint.getArgs();
            result = joinPoint.proceed(args);
            //提交事务
            this.commit();
        } catch (Exception e) {
            e.printStackTrace();
            //回滚事务
            this.rollback();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            this.close();
        }
        return result;
    }
}

7、Service层接口

package cn.bwm.service;

import cn.bwm.pojo.Account;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

/**
 * 账户业务层接口
 * @author bwm
 */
public interface AccountService {

    /**
     * 通过name查询账户
     *
     * @param name 账户名称
     * @return 返回相应的账户实体类
     */
    Account findByName(String name);

    /**
     * 更新账户
     *
     * @param account 返回更新后的账户信息
     */
    void updateAccount(Account account);

    /**
     * 转账
     *
     * @param out   转出账户
     * @param in    转入账户
     * @param money 转账金额
     */
    void transfer(String out,String in,Double money);
}

8、service层接口实现类

package cn.bwm.service.impl;

import cn.bwm.dao.AccountDao;
import cn.bwm.pojo.Account;
import cn.bwm.service.AccountService;
import cn.bwm.util.TransationManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

/**
 * 账户业务层接口实现类
 * @author bwm
 */
@Service("accountService")
public class AccountServiceImpl implements AccountService {

    /**
     * 引入dao层
     */
    @Autowired
    @Qualifier("accountDao")
    private AccountDao accountDao;

    /**
     * 引入自定义的事务管理器
     */
    @Autowired
    private TransationManager transationManager;

    @Override
    public Account findByName(String name) {
        return accountDao.findByName(name);
    }

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


    @Override
    public void transfer(String out, String in, Double money) {
        System.out.println("2 转账业务操作开始...");
        //转出账户信息
        Account outAccount = accountDao.findByName(out);
        System.out.println("转账前"+out+"的账户金额为:"+outAccount.getMoney());
        //转入账户信息
        Account inAccount = accountDao.findByName(in);
        System.out.println("转账前"+in+"的账户金额为:"+inAccount.getMoney());
        //转账 入账操作
        outAccount.setMoney(outAccount.getMoney()-money);
        inAccount.setMoney(inAccount.getMoney()+money);
        //制造异常
        //int i = 1 / 0 ;
        //更新双方账户信息
        accountDao.updateAccount(outAccount);
        System.out.println("转账后"+out+"的账户金额为:"+outAccount.getMoney());
        accountDao.updateAccount(inAccount);
        System.out.println("转账后"+in+"的账户金额为:"+inAccount.getMoney());
    }
}

9、测试类

package cn.bwm.service;

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.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.junit.Assert.*;

/**
 * 转账业务测试类
 * @author bwm
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AccountServiceTest {

    @Autowired
    @Qualifier("accountService")
    private AccountService accountService;

    @Test
    public void transfer() {
        accountService.transfer("王五","李四",50D);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值