复盘了一下上周写的代码,没注意的情况下在Controller中调用了Service的多个DML操作,这就是妥妥的数据不安全的操作。
我们在Service层配置的事务的隔离级别统一为DEFAULT,传播机制为REQUIRED,也就是说支持当前事务,如果当前没有事务,则开启新的事务。而由于Controller层并没有事务控制,在该层执行多个DML操作,如果其中有部分操作失败了,就会导致事务的原子性遭到了破坏。
多个增删改的操作应该置于一个事务中完成。
下面附上Spring事务管理的传播机制和隔离级别的说明:
传播属性 | 值 | 说明 |
---|---|---|
PROPAGATION_REQUIRED | 0 | 支持当前事务,如果当前没有事务,则新建一个事务,这是Spring的默认属性 |
PROPAGATION_SUPPORTS | 1 | 支持当前事务,如果当前没有事务,则以非事务方式运行 |
PROPAGATION_MANDATORY | 2 | 支持当前事务,如果当前没有事务,则抛出异常 |
PROPAGATION_REQUIRES_NEW | 3 | 新建事务,如果当前存在事务,则将当前事务挂起 |
PROPAGATION_NOT_SUPPORTED | 4 | 以非事务方式运行,如果当前存在事务,则将当前事务挂起 |
PROPAGATION_NEVER | 5 | 以非事务方式运行,如果当前存在事务,则抛出异常 |
PROPAGATION_NESTED | 6 | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则以类似PROPAGATION_REQUIRED的形式运行 |
隔离级别 | 值 | 说明 |
---|---|---|
ISOLATION_DEFAULT | -1 | 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别 |
ISOLATION_READ_UNCOMMITED | 1 | 最低级别的事务隔离,允许一个事务看到另一个事务未提交的数据。可以产生脏读、幻读、不可重复读的问题。 |
ISOLATION_READ_COMMITED | 2 | 保证事务的数据提交后才能被另一个事务读取到。 |
ISOLATION_REPEATABLE_READ | 3 | 可以防止脏读、不可重复读,但不能避免幻读。 |
ISOLATION_SERIALIZABLE | 4 | 最高级别,代价高昂。 |
关于脏读、幻读、不可重复读之类问题的概念:
- 脏读:一个事务读到另一个事务未提交的更新数据。
- 不可重复读:一个事务两次读同一行数据,可是这两次读到的数据不一样。
- 幻读:一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行。
- 丢失更新:撤消一个事务时,把其它事务已提交的更新的数据覆盖了。