SpringBoot(十八)事务

目录

spring事务

一、Spring事务介绍

1.事务隔离级别

2.事务传播行为

3.声明式事务属性

4.事务回滚规则

5.@Transactional使用注意事项

二、编码实现


spring事务

一、Spring事务介绍

Spring事务不仅可以通过使用事务注解@Transactional,同时支持编程式使用事务,但是这种模式不常用。这里详细介绍Spring事务。

1.事务隔离级别

使用事务其实只用到了一个注解@Transactional,这就是Spring的注解式事务。事务隔离级别是指若干个事务并发时的隔离程度,Spring声明事务可以通过isolation属性来设置Spring的事务隔离级别。其中提供了以下5种事务隔离级别。 @Transactional(isolation=IsolationDEFAULT):默认的事务隔离级别,即使用数据库的事务隔离级别。

数据库一共有如下四种隔离级别:

1、Read uncommitted 读未提交 在该级别下,一个事务对一行数据修改的过程中,不允许另一个事务对该行数据进行修改,但允许另一个事务对该行数据读。 因此本级别下,不会出现更新丢失,但会出现脏读、不可重复读。

2、Read committed 读已提交 在该级别下,未提交的写事务不允许其他事务访问该行,因此不会出现脏读;但是读取数据的事务允许其他事务的访问该行数据,因此会出现不可重复读的情况。

3、Repeatable read 可重复读 在该级别下,读事务禁止写事务,但允许读事务,因此不会出现同一事务两次读到不同的数据的情况(不可重复读),且写事务禁止其他一切事务。

4、Serializable 序列化 该级别要求所有事务都必须串行执行,因此能避免一切因并发引起的问题,但效率很低。

从上到下隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,安全性低。隔离级别越低,安全性越高。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为ReadCommitted。它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

2.事务传播行为

事务传播行为是指如果多个事务同时存在,Spring 就会处理这些事务的行为。事务传播行为分为如下几种。

可以看出1、2、3为一组,都表现对当前事务的支持,不同的在于当前不存在事务的处理方式;4、5、6为一组,都表现对当前事务的不支持,不同的在于当前有事务的处理方式。然后7单独一组。

举个小栗子,比如有一个service中有方法A,调用了方法B,方法B的传播行为是PROPAGATION_REQUIRED,那么如果方法A的传播行为也是PROPAGATION_REQUIRED,方法A运行的时候,开启了一个事务,方法A中执行到方法B的时候,察觉到当前已经有事务了,方法B就不会再创建新的事务,直接包含在方法A的事务当中。

1、PROPAGATIONREQUIRED:如果当前存在事务,就加入该事务;如果当前没有事务,就创建一个新的事务,这是Spring默认的事务传播行为。 2、PROPAGATION REOUIRES NEW:创建一个新的事务,如果当前存在事务,就把当前事务 挂起。新建事务和被挂起的事务没有任何关系,是两个独立的事务。外层事务回滚失败时, 不能回滚内层事务执行结果,内外层事务不能相互干扰。 3、PROPAGATION SUPPORTS:如果当前存在事务,就加入该事务;如果当前没有事务,就以非事务的方式继续运行。 4、PROPAGATION NOT SUPPORTED:以非事务方式运行,如果当前存在事务,就把当前事务挂起。 5、PROPAGATION NEVER:以非事务方式运行,如果当前存在事务,就抛出异常。 6、PROPAGATION MANDATORY:如果当前存在事务,就加入该事务;如果当前没有事务,就抛出异常。 7、PROPAGATIONNESTED:如果当前存在事务,就创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,该取值就等价于 PROPAGATIONREQUIRED

3.声明式事务属性

Spring 事务不只拥有事务隔离级别和事务传播行为,另外还包含很多属性供开发者使用,分别说明如下。

ovalue:存放String类型的值,主要用来指定不同的事务管理器,满足在同一个系统中存在不同的事务管理器。比如在Spring容器中声明了多种事务管理器,然后开发者可以根据设置指定需要使用的事务管理器。通常一个系统需要访问多个数据库的场景下,就会设置多个事务管理器,然后进行不同的选择。

transactionManager:与value类似,也是用来选择事务管理器。 propagation:事务传播行为,默认值是PropagationREQUIRED。 isolation:事务的隔离级别,默认值是IsolationDEFAULT timeout:事务的超时时间,默认值是-1,如果超过了设置的时间还没有执行完成,就会自动回滚当前事务。 readOnly:当前事务是不是只读事务,默认值是false。通常可以设置读取数据的事务的属性值为true。 rollbackFor:可以设置触发事务的指定异常,允许指定多个类型的异常。 noRollbackFor:与rollbackFor相反,可以设置不触发事务的指定异常,允许指定多个类型的异常。

4.事务回滚规则

Spring的事务回滚通常是根据当前事务抛出异常的时候,Spring事务管理器捕捉到未经处理的异常,然后根据规则来决定当前事务是否回滚。如果捕获的异常正好是设置notRollbackFor属性的异常,那么将不会被捕获。在默认配置下,Spring只有捕获运行时异常(RuntimeException)的子类时才会进行回滚。

5.@Transactional使用注意事项

在使用@Transactional注解的时候,需要注意一些情况:

@Transactional需要在类的上方使用,而不是在接口的上方使用,如果在接口上使用,事务就会失效。 @Transactional只能在public修饰的方法上,如果使用在private或protected修饰的方法上,事务就会无效。 @Transactional 尽量不在类的上方使用,因为这样会对类内的全部方法使用事务,如果对查询方法使用事务,就可能会影响效率。

二、编码实现

mapper接口

@Mapper //该注解就可以不用在配置类中扫描mapper接口包了
public interface UserMapper{
​
    void insertUser1();
​
    void insertUser2();
​
}

mapper映射文件

<mapper namespace="com.yka.mapper.UserMapper">
    <insert id="insertUser1">
        insert into t_user(name)value ('杨凯奥1')
    </insert>
​
    <insert id="insertUser2">
        insert into t_user(name)value ('杨凯奥2')
    </insert>
</mapper>

service层

public interface UserService {
    void insertUser1();
​
    void insertUser2();
}
@Service
public class UserServiceImpl implements UserService {
​
    @Autowired
    private UserMapper userManager;
​
    @Override
    public void insertUser1() {
        userManager.insertUser1();
    }
​
    @Override
    public void insertUser2() {
        userManager.insertUser2();
    }
​
​
}

controller

@Controller
public class TransactionalController {
​
    @Autowired
    private UserService userService;
​
    @RequestMapping("/Transactional")
    @Transactional//添加事务注解
    public void test(){
        userService.insertUser1();
        System.out.println(1/0);//除0异常
        userService.insertUser2();
    }
​
}

运行后有除0异常,所以回滚了,两条sql语句都没有添加到数据库中

如果不添加事务sql1可以添加成功,sql2不能添加成功

猜你喜欢

转载自blog.csdn.net/m0_65992672/article/details/130451288