SpringMVC声明式事务

事务并发、传播性、隔离级别(重难点)

不喜欢

导读:本节重点在于多线程并发环境下的事务处理、和数据库在并发环境下的表锁和行锁。

案例:在新增图书的时候,肯定需要先新增作者。

1、SpringMVC声明式事务

事务分两种:编程式事务、声明式事务

Connection conn

conn.setAutoCommit(false)

conn.commit() conn.rollback()

1.1 导入依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>

1.2 配置事务

<!--配置声明式事务-->
<!--采用数据源事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
<!--允许事务以注解的方式进行配置-->
<tx:annotation-driven transaction-manager="transactionManager"/>

1.3 使用测试

@Transactional//此注解表示,此方法的事务交给Spring管理
public void save(TbBook book){
    //新增作者新增,并且需要返回主键
    int authorId = authorService.save(book.getAuthor());
    if (1==1){
        throw new NullPointerException("故意的");
    }

    book.setAuthorId(authorId);
    //完成新增图书的操作
    bookMapper.save(book);

}

2、事务的传播

导读:我们知道,mvc模型中一般将事务放在service层控制,那么问题是:service层方法A调用service层方法B,方法A和方法B是否在同一个事务中? 
案例1:方法A和方法B上都有事务注解,方法A调用方法B,此时方法B中出现异常,是否会导致方法A回滚?
答案:会回滚

分析:方法A和方法B在同一个事务中,证明方法A的事务会传递给方法B,这就是Spring声明式事务的传播性。

案例2:方法A调用方法B,方法B出现异常,不要影响到方法A的成功事务执行。

2.1 举例

当事务A中包含了事务B,如果事务B出现了回滚,那么事务A也会回滚,此时事务A和事务B成为一个事务整体。

如何实现事务B的回滚不影响事务A呢? NESTED

方法B:在方法B的声明式事务中声明事务的传播特性为NESTED

@Transactional(rollbackFor = Exception.class, propagation = Propagation.NESTED)
public void addOrderInfo(List<TOrderinfo> orderinfos) throws Exception {

    if(orderinfos.isEmpty() || orderinfos==null) {
       throw new NullPointerException();
    }
    orderinfoMapper.insertOrderInfos(orderinfos);
}

2.2 Spring中的事务传播性(声明式事务)

涉及到事务的作用域。 session和事务间的关系。具体的事务传播特性的属性值或事务的传播行为有如下几种:

注意 PROPAGATION_REQUIRED和PROPAGATTION_NESTED

1)PROPAGATION_REQUIRED:支持当前事务,没有事务就新建一个。(默认)
    比如:方法A调用方法B,方法A有事务,方法B会延用方法A的事务,而不会重新创建。如果方法A没有事务,方法B有事务,方法B会新建事务。
2)PROPAGATION_SUPPORTS:支持当前事务,如果没有事务,不新建事务。
    比如:方法A调用方法B,方法A有事务,方法B会延用方法A的事务,而不会重新创建。如果方法A不支持事务,方法B有事务,方法B不会新建事务。
3)PROPAGATION_MANDATORY:支持当前事务,没有事务会抛异常
    比如:方法A调用方法B,方法A有事务,则方法B也有事务。如果方法A没有事务,方法B需要事务就会抛出异常。
4)PROPAGATION_REQUIRES_NEW:使用新建事务,如果当前存在事务,把当前事务挂起
    比如:方法A调用方法B,不管方法A是否支持事务,方法B都会新建事务(挂起方法A的事务)。
5)PROPAGATION_NOT_SUPPORTED:不支持事务操作,有事务则挂起
    比如:方法A调用方法B,不论方法A是否有事务,方法B都不支持事务。
6)PROPAGATION_NEVER:不支持事务,有事务则挂起 
    比如:方法A调用方法B,不论方法A是否有事务,方法B都不支持事务。
7)PROPAGATTION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作
    同 PROPAGATION_REQUIRED 操作

注意:

内层事务的异常可能会影响到外层事务。即使内层开启的新事务。原因:内层方法出现异常,会导致被挂起的异常无法正常执行完成。

事务传播:

1、默认情况下,spring方法中事务的传播特性为:如果方法的上一级方法存在事务,则方法会沿用上一级方法的事务。

PROPAGATION_REQUIRES_NEW 开启新的session

3、事务隔离级别

导读:事务的四大特性中的隔离性的实现会带来一定的性能消耗~ 要实现事务的隔离性,就需要避免线程同步操作同一条数据。事务的隔离级别问题分类如下:
1、脏读(事务a读取了事务b没有提交的数据)
2、不可重复读(事务a读取了数据后,事务b对此数据进行了修改,事务a再次读取发现不一致)
3、幻读(事务a读取一个范围的数据后,事务b又修改了一条数据进来,导致事务a再次读取时发现不一样,多出一行数据,好像出现幻觉一样)。

隔离级别是事务四大特性之一的隔离性的级别。隔离也分不同级别的隔离:

读未提交(read uncommitted):没有隔离

读已提交(read committed)

可重复度(repeatable read):默认

串行化(serializable)

事务隔离级别的实现方式是加锁,隔离级别越高,锁影响的范围越大。效率越低。

3.1、脏读(最低隔离级别)

修改数据库的事务隔离级别:

set session transaction isolation level read uncommitted; 
//session表示当前会话(请求),transaction就表示事务,isolation表示隔离,level表示级别

事务隔离级别的分类:

read uncommitted、read committed、repeatable read(默认)、serializable(串行)

脏读演示

解决脏读:配置事务隔离级别为read committed。

脏读现象:一个事务读取了另一个事务没有提交的内容~~

1、开启两个客户端,都开启事务

2、一个客户端用来读数据,一个客户端用来写数据(但是不提交事务,之后做事务回滚)。

3、写操作进行事务回滚

避免脏读

数据库默认是避免脏读的~

select @@tx_isolation;

##设置数据的事务的隔离级别
##read uncommitted能读取其他事务没有提交的内容,最低的隔离级别
set session transaction isolation level repeatable read;

start transaction;
select * from tb_account where account_id=1 for update;
update tb_account set account_money=200 where account_id=1;

commit;

insert into tb_account(account_money,account_user_id) values(100,2);

rollback;

select @@tx_isolation;

select * from tb_account;

start transaction;

3.2 锁

数据库引擎常见分2种:myisam和innodb。

数据库引擎:是一种数据操作的机制。

目前数据库默认存储引擎:InnoDB。

区别:

InnoDB:支持事务、行锁 MySql8.0

MyIsam:不支持事务、表锁

InnoDB

行锁(共享锁(读锁)和排它锁(写锁)):

SELECT ... LOCK IN SHARE MODE  //共享锁、乐观锁、读锁

特点:对读操作共享,写操作排队
SELECT ... FOR UPDATE; //排他锁

MyIsam

lock table tb_user read

unlock tables;
posted @ 2021-08-30 22:45  W-D-G  阅读(264)  评论(0编辑  收藏  举报