淘先锋技术网

首页 1 2 3 4 5 6 7

你未必出类拔萃,但一定与众不同

手写简易Spring事务框架

前言

该篇需要一些框架基础

在spring中数据库事务时通过PlatformTransactionManager进行管理的,单凭他自身是无法支持事务的,而能够支持事务的是org.springframework.transaction.support.TransactionTemplate模板 他是Spring所提供的事务管理器的模板 以下是一段重要源码

public class TransactionTemplate extends DefaultTransactionDefinition implements TransactionOperations, InitializingBean {
    protected final Log logger = LogFactory.getLog(this.getClass());
    private PlatformTransactionManager transactionManager;

    public TransactionTemplate() {
    }

    ...................

    public <T> T execute(TransactionCallback<T> action) throws TransactionException {
    	//使用自定义的事务管理器
        if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
            return ((CallbackPreferringPlatformTransactionManager)this.transactionManager).execute(this, action);
        } else {
        	//系统默认的构造器
        	//获取事务的状态
            TransactionStatus status = this.transactionManager.getTransaction(this);

            Object result;
            try {
            	//回调接口方法
                result = action.doInTransaction(status);
            } catch (RuntimeException var5) {
            	//回滚异常方法
                this.rollbackOnException(status, var5);
                //抛出异常
                throw var5;
            } catch (Error var6) {
            	//回滚异常方法
                this.rollbackOnException(status, var6);
                throw var6;
            } catch (Exception var7) {
                this.rollbackOnException(status, var7);
                //抛出无法捕获的异常
                throw new UndeclaredThrowableException(var7, "TransactionCallback threw undeclared checked exception");
            }
			//提交事务
            this.transactionManager.commit(status);
            //返回结果
            return result;
        }
    }

PlatformTransactionManager

public interface PlatformTransactionManager {
	//获取事务的状态
    TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException;

	//提交事务
    void commit(TransactionStatus var1) throws TransactionException;

	//回滚事务
    void rollback(TransactionStatus var1) throws TransactionException;
}

接下来就进入正题手写Spring事务框架 这里使用编程式事务

(当前这个方式已经不是主流了,甚至几乎不被推荐,但是因为代码流程更为清晰,方便阅读)

内容

创建maven项目

导入依赖

<dependencies>
        <!-- 引入Spring-AOP等相关Jar -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>3.0.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>3.0.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>3.0.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>3.0.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.5.3</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.1_2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
        </dependency>
    </dependencies>

UserDao

@Repository
public class UserDao {
   @Autowired
   private JdbcTemplate jdbcTemplate;

   public void add(String name, String password) {
      String sql = "INSERT INTO user_list(user_name, user_password) VALUES(?,?);";
      int updateResult = jdbcTemplate.update(sql, name, password);
      System.out.println("updateResult:" + updateResult);
   }

}

UserService

public interface UserService {
    /**
     * 添加数据
     */
    public void add();
}

UserServiceImpl

TransactionStatus表示一个事物的状态。接口提供了控制事务执行和查询事务状态的方法。比如当前调用栈中之前已经存在了一个事物,那么就是通过该接口来判断的,TransactionStatus接口可以让事务管理器控制事务的执行,比如检查事务是否为一个新事务,或者是否只读,TransactionStatus还可以初始化回滚操作。

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private TransactionUtils transactionUtils;
    /**
     * spring事务
     */
    @Override
    public void add() {
        TransactionStatus transactionStatus = null;
        try {
            //开启事务
            transactionStatus = transactionUtils.begin();
            System.out.println("-------");
            userDao.add("java","123456");
//            int i = 1/0;
            System.out.println("-------");
            //提交事务
            transactionUtils.commit(transactionStatus);
        }catch (Exception e){
            e.printStackTrace();
            //回滚事务
            if(transactionStatus == null){
                transactionUtils.rollback(transactionStatus);
            }
        }
    }
}

Spring.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:p="http://www.springframework.org/schema/p"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
	<context:component-scan base-package="com.bluedot"></context:component-scan>
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!-- 开启事物注解 -->

	<!-- 1. 数据源对象: C3P0连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/bank?useSSL=false&amp;serverTimezone=GMT"></property>
		<property name="user" value="root"></property>
		<property name="password" value="520560"></property>
	</bean>

	<!-- 2. JdbcTemplate工具类实例 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<!-- 3.配置事务 -->
	<bean id="dataSourceTransactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<tx:annotation-driven transaction-manager="dataSourceTransactionManager" />
</beans>

TransactionUtils

使用DataSourceTransactionManager去定义数据库事务管理器

并且开启这个事物 这样spring就知道将数据库事务委托给事务管理器信息管理

数据库的资源的产生和释放如果没有委托给数据库管理器,那么就由JdbcTemplate管理,而这时委托给了事务管理器,所以JdbcTemplate的数据库资源和事务交由事务管理器处理

@Component
public class TransactionUtils {
    /**
     * 获取事务源
     */
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;

    /**
     * 开启事务
     */
    public TransactionStatus begin(){
        System.out.println("事务开始");
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
        return transactionStatus;

    }

    /**
     * 提交事务
     */
    public void commit(TransactionStatus transactionStatus){
        System.out.println("开始提交事务");
        dataSourceTransactionManager.commit(transactionStatus);
    }

    /**
     * 事务回滚
     */
    public void rollback(TransactionStatus transactionStatus){
        System.out.println("事务回滚!!!");
        dataSourceTransactionManager.rollback(transactionStatus);
    }


}

测试类Test

public class Test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = (UserService) classPathXmlApplicationContext.getBean("userServiceImpl");
        userService.add();
    }
}

未出现异常时 成功提交

事务开始
-------
updateResult:1
-------
开始提交事务

整合aop实现Spring事务框架

AopTransaction

@Component
@Aspect
public class AopTransaction {

    @Autowired
    private TransactionUtils transactionUtils;


    /**
     * 异常通知  出现异常 进行事务回滚
     */
    @AfterThrowing("execution(* com.bluedot.service.UserService.add(..))")
    public void afterThrow(){
        System.out.println("异常通知 回滚事务");
        //获取当前事务直接回滚
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }

    /**
     * 环绕通知 提交事务
     * @param proceedingJoinPoint
     * @throws Throwable
     */
    @Around("execution(* com.bluedot.service.UserService.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        System.out.println("环绕通知 开启事务");
        TransactionStatus transactionStatus = transactionUtils.begin();
        /**
         * 调用方法之前执行
         * 代理调用方法 如果调用方法抛出了异常不会执行后面代码
         */
        proceedingJoinPoint.proceed();
        System.out.println("环绕通知 提交事务");
        transactionUtils.commit(transactionStatus);


    }
}

修改UserServiceImpl

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private TransactionUtils transactionUtils;
    /**
     * spring事务
     */
    @Override
    public void add() {
//        TransactionStatus transactionStatus = null;
//        try {
//            transactionStatus = transactionUtils.begin();
//            System.out.println("-------");
//            userDao.add("java","123456");
            int i = 1/0;
//            System.out.println("-------");
//            transactionUtils.commit(transactionStatus);
//        }catch (Exception e){
//            e.printStackTrace();
//            //回滚事务
//            if(transactionStatus == null){
//                transactionUtils.rollback(transactionStatus);
//            }
//        }
            System.out.println("-------");
            userDao.add("Spring","123456");
            int i = 1/0;
            System.out.println("-------");
    }
}

出现异常时 事务成功回滚

环绕通知 开启事务
事务开始
-------
updateResult:1
异常通知 回滚事务
Exception in thread "main" org.springframework.transaction.NoTransactionException: No transaction aspect-managed TransactionStatus in scope