springboot事物

一、事物的基本要素(ACID)

1.原子性:事物开始后的所有操作要么全部做完,要么全不做,不可分割

2.一致性:事物开始前后结束后,数据库的完整约束不被破坏

3.隔离性:统一时间只允许一个事物请求数据,不同事物之间无干扰

4.持久性:事物完成后,事物对数据库的所有更新将保存到数据库,不能回滚

二、事物并发问题

1.脏度:事物A读了事物B更新的数据,然后B回滚了,则A读到了B的脏数据

2.不可重读度:事物A多次读取同一数据,事物B在A读的过程中对数据做了更改并提交,导致A多次读取的数据结果不一致

3.幻度:管理员A将数据库中所有的学生的成绩都改为合格,系统管理员在A修改的过程中插入一条不及格的成绩数据,当A改结束后,发现还有一天没改,过来,就像发生幻觉一样,这种模式下,数据库性能最差

解决不可重复读只要锁住满足的条件即可,解决欢度需要锁住整张表

三、mysql的隔离级别(默认为repeatable-read)

1.读未提交(read-uncommied)

2.不可重复读(read-commied)

3.可重复读(repeatable-read)

4.串行化(serializable)

四、springboot设置事物的隔离级别

使用方式

使用注解实现申明式事物

在application.java上加入开启事物声明@EnableTransactionManagement,默认是开启的,可不添加

在方法/实现类/接口上添加@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED)

特点

1.如果在接口、实现类或方法上都指定了@Transactional 注解,则优先级顺序为方法>实现类>接口

2.建议在实现方法或类注解@Transactional,而不要在接口上使用,JDK的代理机制基于接口没有问题,但CGLIB基于继承的代理,注解不能被继承,spring IOC底层两种代理都有

3.默认只回滚RuntimeException,检查异常则不回滚,需要@Transactional(rollbackFor=Exception.class)表示任何异常都回滚

参数解释

propagation:事物传播行为配置,可参考org.springframework.transaction.annotation.Propagation,默认REQUIRED

 REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 

 SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。 

 MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。 

 REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。 

 NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 

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

 NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。 

isolation:隔离级别,默认DEFAULT,选项有(DEFAULT,READ_UNCOMMITTED,READ_COMMITTED,REPEATABLE_READ,SERIALIZABLE)

DEFAULT 使用后端数据库默认的隔离级别(Mysql默认为REPEATABLE_READ )。

READ_UNCOMMITTED 允许读取尚未提交的更改。可能导致脏读、幻读或不可重复读。

COMMITTED 允许从已经提交的并发事务读取。可防止脏读,但幻读和不可重复读仍可能会发生

REPEATABLE_READ 对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读,但幻读仍可能发生。 

ISOLATION_SERIALIZABLE

四、例子 

     //如果发生Exception异常则回滚
   @Transactional(rollbackFor=Exception.class) @Override public ArticleInfo insertArtice(ArticleInfo article) { Date date = new Date(); Article tmpArticle = article.getArticle(); Content tmpContent = article.getContent(); tmpArticle.setCreateTime(date);
     //保存一条数据到数据库A tmpArticle
= articleRep.save(tmpArticle); tmpContent.setArticleId(tmpArticle.getId()); tmpContent.setCreateTime(date);
     //保存一条数据到数据库B tmpContent
= contentRep.save(tmpContent); article.setArticle(tmpArticle); article.setContent(tmpContent); return article; }

 

 

posted @ 2020-07-14 10:35  zincredible  阅读(363)  评论(0编辑  收藏  举报