手写spring编程事务

微信公众号:用心程序员

编程事务和声明事务的区别

编程式事务:编码方式实现事务管理。需要你在代码中直接加入处理事务的逻辑,可能需要在代码中显式调用beginTransaction()、commit()、rollback()等事务管理相关的方法,如在执行a方法时候需要事务处理,你需要在a方法开始时候开启事务,处理完后。在方法结束时候,关闭事务。

声明式事务:声明式的事务的做法是在a方法外围添加注解或者直接在配置文件中定义,a方法需要事务处理,在spring中会通过配置文件在a方法前后拦截,并添加事务。声明式事务属于无侵入式,不会影响业务逻辑的实现。

实现过程

建立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>5.1.37</version>
        </dependency>
    </dependencies>

####第二步 编写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"
	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">
	<context:component-scan base-package="ljx"></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.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
		<property name="user" value="root"></property>
		<property name="password" value=""></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>

</beans>


####第三步 编写dao层


@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void add(String name, int age){
        String sql  = "insert into tb_user(name, age) values (?,?)";
        int udateResult = jdbcTemplate.update(sql,name,age);
        System.out.println("updateResult:" + udateResult);
    }
}

####第四步 编写事务工具类TransactionUtils


//编程事务(需要手动begin 手动回滚  手都提交)
@Component
public class TransactionUtils {

	// 获取事务源
	@Autowired
	private DataSourceTransactionManager dataSourceTransactionManager;

	// 开启事务
	public TransactionStatus begin() {
		TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
		return transaction;
	}

	// 提交事务
	public void commit(TransactionStatus transaction) {
		dataSourceTransactionManager.commit(transaction);
	}

	// 回滚事务
	public void rollback(TransactionStatus transaction) {
		dataSourceTransactionManager.rollback(transaction);
	}

}

####第五步 编写service层


@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Autowired
    private TransactionUtils transactionUtils;
    @Override
    public void add() {
        TransactionStatus transactionStatus = null;
        try {
            //开启事务
            transactionStatus = transactionUtils.begin();
            userDao.add("张三",13);
            int i = 1/0;
            System.out.println("############################");
            userDao.add("李四", 14);
            //提交事务
            if (transactionStatus != null){
                transactionUtils.commit(transactionStatus);
            }
        }catch (Exception e){
            e.getMessage();
            //回滚事务
            if (transactionStatus != null)
                transactionUtils.rollback(transactionStatus);
        }
    }
}

####第六步 测试


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


使用Aop整合编程事务

####第一步 编写切面类AopTransaction


@Component
@Aspect
public class AopTransaction {
    @Autowired
    private TransactionUtils transactionUtils;
    // TransactionUtils 不要实现为单例子: 如果为单例子的话可能会发生线程安全问题
    // // 异常通知
    @AfterThrowing("execution(* ljx.service.UserService.add(..))")
    public void afterThrowing() {
        System.out.println("回滚事务");
        // 获取当前事务 直接回滚
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }// 环绕通知 在方法之前和之后处理事情
    @Around("execution(* ljx.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);
    }
}

####第二步 重构service层

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Autowired
    private TransactionUtils transactionUtils;
​
    @Override
    public void add(){
        userDao.add("张三",13);
        int i = 1/0;
        System.out.println("############################");
        userDao.add("李四", 14);
    }
}

####第三步 测试

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

项目源码:https://github.com/ljx95/springDemo01

我的公众号

手写spring编程事务