Spring核心系列之Spring中的事务

栏目: Java · 发布时间: 6年前

内容简介:Spring核心系列之Spring中的事务

Hello,大家好,前面两篇文章给大家分享了Spring AOP,今天就趁热打铁,给大家分享一下,Spring中的事务,事务这个事,其实在国内一些小公司,一般都会忽略的,尤其是很多网站,设计不到钱的系统,不会在乎这个东西,事务不回滚造成的结果无非就是脏数据,脏改等后果。因为作者以前待过的一个房产网站,根本就不在乎这个事务,有问题就有问题了,反正用户也没充钱在网站上。呵呵。今天还是和大家分享一下这个Spring的事务,因为这个东西算是Spring 内部使用AOP最好的一个体现,体现了AOP思想,OK,文章结构:

  1. Spring boot 中的事务
  2. Spring事务中的事务属性

1. Spring boot 中的事务

看到Spring boot,很多人肯定感觉是被忽悠了,为什么说讲Spring事务,这又来Spring boot搞事情。用过Spring boot的小伙伴其实都知道,这两个没什么大的区别,笔者这里使用Spring boot来演示,完全是为什么了简便。因为搭一个Spring传统的ssm三件套工程可能要花费5分钟,而搭建一个Spring boot的"ssm"工程,就是鼠标点一点的事。而且开启事务也是一个注解的事。所以,老铁们,对不住了,这一篇用Spring boot和大家演示Spring的事务,这里我给一个传送门,是传统项目的事务,大家可以参考下:

废话说下,直接上Spring boot代码:

@SpringBootApplication
@EnableTransactionManagement  
public class TestTxApplication {

	public static void main(String[] args) {
		SpringApplication.run(TestTxApplication.class, args);
	}
}

@EnableTransactionManagement 表示开启事务!

@Component
public class PersonService {
    @Autowired
    private PersonMapper personMapper;

    @Transactional
    public void testTx(){
        //该操作会成功
        personMapper.update();
        //该操作会报异常
        personMapper.update2();
    }
}

这是一个Service,内部的personMapper是一个dao接口,持久化用的mybatis

@Mapper
public interface PersonMapper {
    //更改某条记录
    @Update("update user_info set user_name='123'  where user_id='1' ")
    Long update();
    //user_info2这个表不存在。会报异常
    @Update("update user_info2 set user_name='123'  where user_id='1' ")
    Long update2();
}

演示的效果应该是:

  1. 当调用PersonService的testTx()时,由于开启了事务,所以update2报异常时,应该会回滚。update1的操作不会被写入数据库。
  2. 去掉testTx()上面的@Transactional注解,再做试验,发现虽然报异常,但数据还是update了。

具体我就不演示了 。大家可以看到,在Spring boot中开启事务就是一个注解的事 。具体的内部使用什么trancationManagement根本不用管,Spring boot内部会根据pom中引入的持久层框架自动注入。真是开发神器!

然后我说下底层原理: Spring事务其实就是Spring AOP,底层创建动态代理对象,在代码的开头结尾封装了开启事务和事务回滚操作 。用过JDBC原生代码的更应该清楚了,都是显示在代理里commit和rollback的。然后一大堆try catch..

2. Spring事务中的事务属性

上面的代码虽然简单,也能应对大部分的场景,但还是有一些问题的,比如,有些异常开发者知道,并且想人为的控制,"抛出某类异常,不要回滚".这样的问题。这就引出了, 事务属性 这个概念, 事务属性通常由事务的传播行为,事务的隔离级别,事务的超时值和事务只读标志组成 。 这些属性都是在使用@Transactional可以指定的,我给一张表格:

Spring核心系列之Spring中的事务

然后把这些属性讲一讲:

2.1 isolation

事务的隔离界别:使用@Transactional的Isolation属性可以指定事务的隔离级别。但事务的隔离级别是由底层的数据库实现的,并不是由Spring来实现。

  1. ISOLATION_DEFAULT ,这是默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应.
  2. ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
  3. ISOLATION_READ_COMMITTED 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
  4. ISOLATION_REPEATABLE_READ 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读。
  5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。

一般的数据库默认提供的是READ_COMMITTED隔离级别,如sqlserver2000;Mysql默认提供的是REPEATABLE_READ;

好了,结论给大家说完了,然后解释一下上面提到的 脏读,不可重复读和幻象读的概念。

脏读:

  1. Mary的原工资为1000,财务人员将Mary的工资改为了8000,但未提交事务
  2. 与此同时,Mary正在读取自己的工资.Mary发现自己的工资变为了8000,欢天喜地! (脏读)
  3. 而财务发现操作有误,而回滚了事务,Mary的工资又变为了1000.

不可重复读: 在一个事务中前后两次读取的结果并不致,导致了不可重复读。

  1. 在事务1中,Mary 读取了自己的工资为1000,操作并没有完成 .
  2. 在事务2中,这时财务人员修改了Mary的工资为2000,并提交了事务.
  3. 在事务1中,Mary 再次读取自己的工资时,工资变为了2000.

幻想读:

  1. 目前工资为1000的员工有10人。
  2. 事务1,读取所有工资为1000的员工。共读取10条记录 .
  3. 这时另一个事务向employee表插入了一条员工记录,工资也为1000
  4. 事务1再次读取所有工资为1000的员工,共读取到了11条记录,这就产生了幻像读。

好了,事务的隔离级别就讲完了,一般还是采用数据库默认的,像 mysql 的REPEATABLE_READ,能够避免脏读和不可重复读。

2.2 propagation

  1. REQUIRED:表示业务方法需要在一个事务中处理,如果业务方法执行时已经在一个事务中,则加入该事务,否则重新开启一个事务。这也是默认的事务传播行为;
  2. NOT_SUPPORTED:声明业务方法不需要事务,如果业务方法执行时已经在一个事务中,则事务被挂起,等方法执行完毕后,事务恢复进行;

其他的传播行为省略,基本不用,一般的传播行为也是使用默认的:REQUIRED

2.3 rollbackFor rollbackForClassName noRollbackFor norollbackForClassName

Transactional的异常控制,默认是Check Exception不回滚,unCheck Exception回滚,rollbackFor 和noRollbackFor 配置也许不会含盖所有异常,对于遗漏的按照Check Exception 不回滚,unCheck Exception回滚.

使用@Transactional注解的noRollbackFor和rollbackFor属性可以改变默认的行为:

  • 如:@Transactional(rollbackFor=Exception.class)可以使checked异常发生时,数据库操作也rollback,@Transactional(noRollbackFor=RuntimeException.class)可以使unchecked异常发生时也提交数据库操作。

也可以使用noRollbackForClassName、rollbackForClassName属性来指定一个异常类名的String数组来改变默认的行为。

好了,事务属性大致就这么多了,其他一些就是比较简单的了,看名字就知道啥意思,伸手就用的东西,然后再提一下,@Transactional只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能..

老实说,一般事务属性配置的比较少,一般都是直接@Transactional加上就完事了。很少配置一些属性。尤其是那个事务传播行为,在日常的业务里,很少有食物嵌套的情况,所以我就是点了一点,没有展开。一般使用默认就可以了。

结语

好了,Spring的事务使用层面给大家算是分享完了,在Spring boot里想使用事务简单的有点可怕。所以我就采用Spring boot了。其实传统的SSM项目也很简单,无非就是在xml文件里配置下tranclationManagement..然后Spring 事务的底层是Spring AOP,把jdbc的事务代码嵌入了进去。 Over,Have a good day!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Don't Make Me Think

Don't Make Me Think

Steve Krug / New Riders Press / 18 August, 2005 / $35.00

Five years and more than 100,000 copies after it was first published, it's hard to imagine anyone working in Web design who hasn't read Steve Krug's "instant classic" on Web usability, but people are ......一起来看看 《Don't Make Me Think》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

SHA 加密
SHA 加密

SHA 加密工具