七个事务传播属性
PROPAGATION_REQUIRED – 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS – 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY – 支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW – 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED – 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER – 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED–如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
事务: 事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit。 如果没有事务, 即使报错数据也会添加成功
是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠
事务特性:
原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。 [1]
两个方法之间的事务传递
//默认注入容器 id userService
@Service
public class UserService {
// @Autowired与Resource区别是什么?
// Autowired 默认是以类型进行查找 Resource默认是名称进行查找
@Resource(name = "userDao02")
private UserDao userDao;
@Autowired
private LogService logService;
@Transactional(propagation= Propagation.REQUIRED)
public void add03() {
logService.addLog();
System.out.println(" userService02 add003...");
userDao.add("enjoy", 20);
int i = 1 / 0;
}
@Service
public class LogService {
@Autowired
private LogDao logDao;
//@Transactional(propagation=Propagation.NEVER)
public void addLog(){
logDao.addLog(); //如果有一条数据
int i =10/0;
logDao.addLog();
}
五种隔离级别
隔离级别是指若干个并发的事务之间的隔离程度。
ISOLATION_DEFAULT–这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应;
ISOLATION_READ_UNCOMMITTED–这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
ISOLATION_READ_COMMITTED–保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
ISOLATION_REPEATABLE_READ–这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
ISOLATION_SERIALIZABLE–这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。
ISOLATION_READ_UNCOMMITTED 未提交读:
脏读:读取未提交的数据
set SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
测试:
启动两个session
一个session中
start TRANSACTION
update account set balance = balance -50 where id = 1 (假设balance 初始值是1000, 此时的执行sql 语句并没有提交)
另外一个session中查询
select * from account (此时查出来的balance 的结果是950, 查出的结果放到java 的代码的变量里面 int a =950)
回到第一个session中 回滚事务
ROLLBACK(事务没有提交, 但是回滚了, 回滚之后的数据库的值是1000)
在第二个session种
再次执行update 语句 此时balance 在java 中记录的是950
update account set balance = balance -50 where id = 1–> 期望的结果是 900
但是查寻出来的结果是1000-50=950, 因为callback 之后 数据库的值变成1000 了
导致最后的结果和意料中的结果并不一致。
ISOLATION_READ_COMMITTED:读已提交。
不会读取未提交的数据 防止脏读, 会读取已提交的事务
测试
show variables like ‘%tx_isolation%’;
set SESSION TRANSACTION ISOLATION LEVEL read committed;
一个session中
start TRANSACTION
update account set balance = balance -50 where id = 1
另外一个session中查询 (数据并没改变)
select * from account
回到第一个session中 回滚事务
commit
在第二个session种
select * from account (数据已经改变)
又叫不可重复读:在同一个事务里面读取同一行的数据产生了2 个不一样的结果
update account set balance = balance -50 where id = 1 commit 950
select * from account where id= 1//第一次 是950
再执行update account set balance = balance -50 where id = 1 commit 900
select * from account where id= 1//第一次 是900
幻像读:是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
ISOLATION_REPEATABLE_READ 可重复读
在同一个事务里面多次读取的数据是一摸一样的, 是可重复读
测试
show variables like ‘%tx_isolation%’;
set SESSION TRANSACTION ISOLATION LEVEL repeatable read;
一个session中
start TRANSACTION
update account set balance = balance -50 where id = 1
另外一个session中查询 (数据并没改变)
select * from account
回到第一个session中 回滚事务
commit
在第二个session种
select * from account (数据并未改变)
ISOLATION_SERIALIZABLE(可串行化)尽量避免用 导致整个表都会锁住