Spring事务(手写简单实现)

事务基本特性

  •  原子性(Atomicity)

  原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

  •  一致性(Consistency)

 一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

  拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

  •  隔离性(Isolation)

  隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

  即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

  关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍到。

  •  持久性(Durability)

       持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

       例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。

事务控制分类

编程式事务控制

         自己手动控制事务,就叫做编程式事务控制。

    Jdbc代码:

         Conn.setAutoCommite(false);  // 设置手动控制事务

    Hibernate代码:

         Session.beginTransaction();    // 开启一个事务

声明式事务控制

       Spring提供了对事务的管理, 这个就叫声明式事务管理。

       Spring提供了对事务控制的实现。用户如果想用Spring的声明式事务管理,只需要在配置文件中配置即可; 不想使用时直接移除配置。这个实现了对事务控制的最大程度的解耦。

      Spring声明式事务管理,核心实现就是基于Aop。

      Jdbc技术:DataSourceTransactionManager

      Hibernate技术:HibernateTransactionManager

手动实现事务

     1、在spring.xml加上相关配置

<!--1.设置扫包范围
	目的:封装的TransactionUtils加上@Component后,可以被扫到,并加载到Spring容器中-->
<context:component-scan base-package="lun"></context:component-scan>

<!-- 2. 数据源对象: 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?serverTimezone=UTC"></property>
    <property name="user" value="root"></property>
	<property name="password" value="root"></property>
</bean>

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

<!-- 4.配置事务
	 将Spring事务管理器加载到Spring容器中-->
<bean id="dataSourceTransactionManager"
				 class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"></property>
</bean>

     2、首先编写一个事务管理工具类,实现事务开启begin、事务提交commit、事务回滚rollback方法

@Component
public class TransactionUtils {
    // 全局接受事务状态
    private TransactionStatus transactionStatus;
    //将Spring事务管理器注入进来
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;

    //开启事务
    public TransactionStatus begin(){
        transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
        return transactionStatus;
    }
    //提交事务
    public void commit(){
        dataSourceTransactionManager.commit(transactionStatus);
    }
    //回滚事务
    public void rollback(){
        dataSourceTransactionManager.rollback(transactionStatus);
    }
}

编程事务实现

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    @Autowired
    private TransactionUtils transactionUtils;
    public Integer add(){
        int addNumber  = 0;
        TransactionStatus transactionStatus = null;
        try {
            //开启事务
            transactionStatus = transactionUtils.begin();
            addNumber += userDao.add();
            //制造异常
            //int i = 1 / 0;
            addNumber += userDao.add();
            //提交事务
            if(transactionStatus != null)
                transactionUtils.commit();
        }catch (Exception e){
            if(transactionStatus != null){
                //发生异常,事务回滚
                transactionUtils.rollback();
                addNumber = 0;
            }
        }
        return addNumber;
    }
}

@Repository
public class UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    public Integer add(){
        String sql = "INSERT INTO t_users(NAME, AGE) VALUES(?,?);";
        int updateResult = jdbcTemplate.update(sql, "12", 12);
        System.out.println("updateResult:" + updateResult);
        return 1;
    }
}

public class Test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = (UserService) applicationContext.getBean("userService");
        Integer add = userService.add();
        System.out.println(add);
    }
}

声明事务实现

1、首先在spring.xml文件中加上开启事务注解配置,这样建立在AOP上的声明事务才能有效

<!-- 开启事物注解 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

2、编写事务注解 

// 事务注解 设置传播行为
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface TransactionalDemo {
}

3、编写AOP,在相应方法上拦截,进行事务控制

@Component
@Aspect
public class AopTransaction {
    @Autowired
    private TransactionUtils transactionUtils;
    //异常通知
    @AfterThrowing("execution(* lun.Service.UserService.*())")
    public void afterThrowing() {
        System.out.println("回滚事务");
        transactionUtils.rollback();
    }
    // 环绕通知 在方法之前和之后处理事情
    @Around("execution(* lun.Service.UserService.*())")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        //1.获取该方法上是有加上注解
        TransactionalDemo transactionalDemo = getMethodTransacAnno(pjp);
        //2.如果加有注解,开启事务
        TransactionStatus transactionStatus = begin(transactionalDemo);
        //3.调用目标代理对象方法
        pjp.proceed();
        //4.如果有注解,提交事务
        commit(transactionStatus);
    }
    
    //获得方法是否存在事务注解
    private TransactionalDemo getMethodTransacAnno(ProceedingJoinPoint pjp) throws NoSuchMethodException {
        //1.获取代理对象的方法
        String methodName = pjp.getSignature().getName();
        Class<?> targetClass = pjp.getTarget().getClass();
        Class[] parameterTypes = ((MethodSignature) pjp.getSignature()).getParameterTypes();
        Method objMethod = targetClass.getMethod(methodName,parameterTypes);
        //2.获得方法上的注解
        TransactionalDemo transactionalDemo = objMethod.getDeclaredAnnotation(TransactionalDemo.class);
        return transactionalDemo;
    }
    //开启事务
    private TransactionStatus begin(TransactionalDemo transactionalDemo){
        if(transactionalDemo != null){
            System.out.println("开启事务");
            return transactionUtils.begin();
        }
        return null;
    }
    //提交事务
    private void commit(TransactionStatus transactionStatus){
        if(transactionStatus != null){
            System.out.println("提交事务");
            transactionUtils.commit();
        }
    }
}

4、在service的方法上加上注解

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    //加入事务控制
    @TransactionalDemo
    public Integer add(){
        int addNumber  = 0;
        addNumber += userDao.add();
        //制造异常
        //int i = 1 / 0;
        addNumber += userDao.add();
        return addNumber;
    }
}

Spring事物传播行为

  • PROPAGATION_REQUIRED—如果当前有事务,就用当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。默认为PROPAGATION_REQUIRED
  • PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。//如果外层方法没有事务,就会以非事务进行执行。
  • PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
  • PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。 
  • PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。如果当前有事务,就是以非事务进行执行

  • PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

猜你喜欢

转载自blog.csdn.net/u014034683/article/details/88833154