Spring事务

1 事务简介

1.1 什么是事务

事务是数据库管理系统中的一个重要概念,它是由一组操作组成的逻辑单元,这些操作要么全部成功执行,要么全部回滚到初始状态,以确保数据的一致性和完整性。

1.2 事务的特性(ACID)

  • 原子性(Atomicity):事务中的所有操作要么全部成功执行,要么全部失败回滚。如果任何操作失败,整个事务将被回滚到起始状态,不会对数据库造成任何改变。
  • 一致性(Consistency):事务的执行使数据库从一个一致状态转变为另一个一致状态。在事务开始之前和结束之后,数据库必须满足预先定义的一致性规则。
  • 隔离性(Isolation):每个事务的操作应该与其他事务的操作相互隔离,以防止互相干扰。事务应该以一种看起来它们是并发执行的方式运行,而不会相互干扰。
  • 持久性(Durability):一旦事务提交,其所做的更改应该永久保存在数据库中,即使系统发生故障或重新启动。

1.3 事务的隔离级别

事务的隔离级别是指多个并发事务之间的相互影响程度。

隔离级别定义了一个事务在读取或修改数据时,能否看到其他事务对同一数据所做的更改,以及能否被其他事务看到自己所做的未提交更改。

关系型数据库中定义了四个标准的隔离级别,每个级别提供了不同的数据一致性和并发性能之间的权衡:

  • 读未提交(Read Uncommitted):最低级别的隔离级别,允许一个事务读取另一个事务尚未提交的数据。这种级别可能导致脏读(Dirty Read)
    • 脏读(Dirty Read):事务可以看到其他事务“尚未提交”的修改。如果另一个事务回滚,那么当前事务读到的数据就是脏数据。
  • 读已提交(Read Committed):在这个级别下,一个事务只能读取到已经提交的数据。这样可以避免脏读,但可能会导致不可重复读(Non-Repeatable Read)
    • 不可重复读(Non-Repeatable Read):在一个事务内,多次读同一数据,在这个事务还没有结束时,如果另一个事务恰好修改了这个数据,那么,在第一个事务中,两次读取的数据就可能不一致。
  • 可重复读(Repeatable Read):在这个级别下,一个事务在执行期间多次读取同一数据,将会看到一致的结果。其他事务对该数据的修改将被阻塞,直到当前事务结束。这样可以避免脏读和不可重复读,但可能会导致幻读(Phantom Read)
    • 幻读(Phantom Read):在一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在的记录时,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了。
  • 串行化(Serializable):最高级别的隔离级别,要求事务串行执行,完全隔离了并发事务之间的影响。这种级别可以避免脏读、不可重复读和幻读,但对并发性能有较大的影响,因为事务需要顺序执行。
隔离级别脏读不可重复读幻读
READ-UNCOMMITTED
READ-COMMITTED×
REPEATABLE-READ××
SERIALIZABLE×××

2 spring的事务支持

Spring框架提供了全面的事务管理支持,使得在应用中使用事务变得更加简单和灵活。Spring的事务管理支持主要通过以下几个关键组件来实现:

  • 事务管理器(Transaction Manager):Spring通过事务管理器来统一管理事务。事务管理器负责处理事务的开始、提交、回滚等操作,并协调底层的事务资源。
  • 事务定义(Transaction Definition):事务定义描述了事务的隔离级别传播行为超时设置等属性。Spring提供了多种方式来定义事务,包括编程式事务声明式事务
  • 事务切面(Transaction Aspect):Spring使用切面(Aspect) 来实现声明式事务。通过AOP的方式,将事务逻辑织入到业务逻辑中,使得事务的管理与业务逻辑解耦。
  • 事务注解(Transaction Annotation):Spring支持使用注解的方式来声明事务。通过在方法或类上添加@Transactional注解,可以指定事务的属性,如隔离级别、传播行为等。

2.1 事务注解(Transaction Annotation)

事务注解(Transaction Annotation)是Spring框架中用于声明式事务管理的一种方式。通过在方法或类上添加@Transactional注解,可以指定方法或类的事务属性,从而实现对方法或类的事务管理。

使用事务注解可以简化事务管理的配置,使得开发者可以通过注解的方式来定义事务的行为,而无需显式编写事务管理的代码。

2.1.1 注解的属性

  • isolation(隔离级别):指定事务的隔离级别,默认为数据库的默认隔离级别。
    • READ-UNCOMMITTED(读未提交)
    • READ-COMMITTED(读已提交)
    • REPEATABLE-READ(可重复读)
    • SERIALIZABLE(串行化)
  • propagation(传播行为):指定事务的传播行为,即在方法调用链中如何传播事务,默认为REQUIRED。
    • REQUIRED:如果当前存在事务,则加入该事务;否则创建一个新事务。这是默认的传播行为。
    • SUPPORTS:如果当前存在事务,则加入该事务;否则以非事务方式执行。
    • MANDATORY:必须在一个已有的事务中执行;否则抛出异常。
    • REQUIRES_NEW:创建一个新的事务,并在它自己的事务内执行。如果当前存在事务,则挂起该事务。
    • NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则挂起该事务。
    • NEVER:以非事务方式执行操作,如果当前存在事务,则抛出异常。
    • NESTED:如果当前存在事务,则在嵌套事务内执行;否则创建一个新事务。嵌套事务是独立于外部事务的,它有自己的提交和回滚操作。如果外部事务回滚,则嵌套事务也会回滚。但是,如果嵌套事务回滚,则只会回滚嵌套事务本身,而不会影响到外部事务。
  • readOnly(只读):指定事务是否为只读事务,默认为false。如果设置为true,表示事务只读,不会对数据库进行修改操作,可以提高性能。
  • timeout(超时时间):指定事务的超时时间,单位为秒。如果事务执行时间超过指定的超时时间,事务将被强制回滚,默认为-1,表示没有超时限制。
  • rollbackFor(回滚异常):指定需要回滚事务的异常类型数组。当方法抛出指定类型的异常时,事务将回滚。
  • noRollbackFor(不回滚异常):指定不需要回滚事务的异常类型数组。当方法抛出指定类型的异常时,事务将不会回滚。

2.1.2 事务注解的使用

首先应在全局配置文件,如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: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
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
       https://www.springframework.org/schema/tx/spring-tx.xsd">

<!--        配置数据源-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
                <property name="url" value="jdbc:mysql:///mybatis"></property>
                <property name="username" value="root"></property>
                <property name="password" value="123456"></property>
                <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        </bean>
        <!--配置JdbcTemplate-->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">

                <property name="dataSource" ref="dataSource"></property>
        </bean>

        <context:component-scan base-package="com.yy"></context:component-scan>
<!--        配置事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <property name="dataSource" ref="dataSource"></property>
        </bean>
<!--        开启注解事务-->
        <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>

配置完成后可在方法或类上利用事务注解来进行声明式事务管理

public class BankService {
    //@Autowired
    private BankDao bankDao;

    public BankDao getBankDao() {
        return bankDao;
    }

    public void setBankDao(BankDao bankDao) {
        this.bankDao = bankDao;
    }
	//利用事务注解来进行事务管理
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ,timeout = 1,readOnly = false,rollbackFor = Exception.class)
    public void countMoney(){
        bankDao.addMoney();
        System.out.println("------");
        bankDao.reduceMoney();
    }
}

注意:一般情况下,事务注解(Transaction Annotation)会被应用在Service层。
这是因为Service层通常是应用程序的业务逻辑层,包含了多个DAO层的方法调用,需要确保整个Service方法的执行是一个原子操作,确保这些操作要么全部成功,要么全部回滚。这样可以避免数据不一致的问题,提高系统的稳定性和可靠性。

2.2 事务切面(Transaction Aspect)

事务切面(Transaction Aspect)是Spring框架中用于实现声明式事务的关键组件之一。

它通过AOP(Aspect-Oriented Programming)的方式将事务逻辑织入到业务逻辑中,实现了事务的管理与业务逻辑的解耦。

2.2.1 事务切面的组成部分

  • 切点(Pointcut):切点定义了哪些方法需要被事务增强处理。它可以通过表达式、注解或者自定义规则来指定目标方法。
  • 通知(Advice):通知定义了在切点处执行的具体逻辑。在事务切面中,通常使用的是Around通知,即在目标方法执行前后添加事务管理的逻辑。
  • 事务管理器(Transaction Manager):事务管理器负责处理事务的开始、提交、回滚等操作。在事务切面中,需要配置一个事务管理器,用于协调底层的事务资源。
  • 事务属性(Transaction Attributes):事务属性定义了事务的隔离级别、传播行为、超时设置等属性。在事务切面中,可以通过注解或者XML配置的方式来指定事务属性。

2.2.2 优点

  • 通过配置事务切面,Spring会自动将切面织入到目标方法中,实现对目标方法的事务管理。当目标方法被调用时,事务切面会拦截方法的执行,并根据事务属性进行事务的开启、提交或回滚等操作。
  • 使用事务切面可以大大简化事务管理的代码,提高开发效率。同时,由于事务逻辑与业务逻辑解耦,使得系统的可维护性和可测试性都得到了提升。

2.2.3 事务切面的使用

首先应在全局配置文件,如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: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
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
       https://www.springframework.org/schema/tx/spring-tx.xsd">

<!--        配置数据源-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
                <property name="url" value="jdbc:mysql:///mybatis"></property>
                <property name="username" value="root"></property>
                <property name="password" value="123456"></property>
                <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        </bean>
        <!--配置JdbcTemplate-->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">

                <property name="dataSource" ref="dataSource"></property>
        </bean>

        <context:component-scan base-package="com.yy"></context:component-scan>
<!--        配置事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <property name="dataSource" ref="dataSource"></property>
        </bean>
<!--        配置通知-->
        <tx:advice id="txadvice">
<!--                配置事务参数-->
                <tx:attributes>
                        <tx:method name="countMoney" propagation="REQUIRED"/>
<!--                        <tx:method name="save*" propagation="REQUIRED"/>-->
<!--                        <tx:method name="del*" propagation="REQUIRED"/>-->
                </tx:attributes>
        </tx:advice>

<!--        配置切入点和切面-->
        <aop:config>
<!--                切入点-->
                <aop:pointcut id="p" expression="execution(* com.yy.service.BankService.countMoney(..))" />
<!--                切面-->
                <aop:advisor advice-ref="txadvice" pointcut-ref="p"></aop:advisor>
        </aop:config>

        <bean id="bankDaoImpl" class="com.yy.dao.impl.BankDaoImpl">
                <property name="jdbcTemplate" ref="jdbcTemplate"></property>
        </bean>

        <bean id="bankService" class="com.yy.service.BankService">
                <property name="bankDao" ref="bankDaoImpl"></property>
        </bean>
</beans>

此时,只需在service层使用对应方法即可

public class BankService {
    //@Autowired
    private BankDao bankDao;

    public BankDao getBankDao() {
        return bankDao;
    }

    public void setBankDao(BankDao bankDao) {
        this.bankDao = bankDao;
    }
	//由于在全局配置文件中使用了事务切面,这里就无需使用事务注解来进行事务管理了
    //@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ,timeout = 1,readOnly = false,rollbackFor = Exception.class)
    public void countMoney(){
        bankDao.addMoney();
        System.out.println("------");
        bankDao.reduceMoney();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring事务的原理是通过AOP(面向切面编程)和代理模式来实现的。Spring使用了动态代理技术,将事务管理逻辑织入到目标方法中,从而实现对事务的控制。 具体来说,Spring事务的原理包括以下几个关键点: 1. 事务管理器(Transaction Manager):Spring通过事务管理器来管理事务的提交、回滚和连接的关闭等操作。事务管理器可以是JDBC事务管理器、Hibernate事务管理器或者JTA事务管理器等。 2. 事务定义(Transaction Definition):事务定义包括事务的隔离级别、传播行为、超时时间等属性。通过事务定义,我们可以指定事务的一些行为特性。 3. 事务切面(Transaction Aspect):Spring使用AOP来实现事务的切面,将事务管理逻辑织入到目标方法中。在方法执行前后,事务切面会根据事务定义来决定是否开启、提交或回滚事务。 4. 事务通知(Transaction Advice):事务通知是事务切面的具体实现,它定义了在目标方法执行前后需要执行的逻辑。在事务通知中,可以通过事务管理器来控制事务的提交、回滚等操作。 5. 事务代理(Transaction Proxy):Spring使用动态代理技术来生成事务代理对象。事务代理对象包装了目标对象,并在目标方法执行前后调用事务通知。 通过以上几个关键点的组合,Spring实现了对事务的管理和控制。当我们在业务方法上添加@Transactional注解时,Spring会根据注解的配置来生成事务代理对象,并在方法执行前后执行事务通知,从而实现对事务的管理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值