作为一个Java开发人员,对事务一定不能不懂,在面试的时候,基本都会问询到事务的使用。
Ⅰ、事务必须遵循4个原则,即常说的 ACID
A,Automicity,原子性,即事务要么被全部执行,要么被全部不执行。如果事务下的子事务全部提交成功,则所有数据库操作被提交,否则,应进行事务回滚。
C,Consistency,一致性,即状态转换必须是由一种正确的状态转换到另外一种正确的状态。
I,Isolation,隔离性,即相互间必须不能被影响。
D,Durabillity,持久性,即事务提交后将被永久保存,即便出现其他故障,事务处理结果也应得到保存。
Ⅱ、事务的隔离级别
串行化,Serializable,一个事务在执行过程中完全看不到其他事务对数据库所做的更新。
可重复读,Repeatable Read,一个事务在执行过程中可以看到其他事务已经提交的记录,但是不能看到其他事务对已有记录的更新。
读已提交数据,Read Commited,一个事务在执行过程中可以看到其他事务已经提交的记录,而且能看到其他事务对已有记录的更新。
读未提交数据,Read UnCommited,一个事务在执行过程中可以看到其他事务没有提交的记录,而且能看到其他事务没有提交的记录的更新。
隔离级别越高,越能保证数据的完整性和一致性,但对高并发性能影响也越大,故需要合理选择。
当然,上面的这些百度随便都是可以找到的,今天要说的是我在使用事务的过程中所发现的一个点,在自己开发过程中,发现使用了声明式的事务之后,如果代码块没有进行捕捉异常,当程序发生异常的时候事务会回滚,但是有时候我们需要捕捉一些可预测的异常来进行一些业务上面的处理,这个时候发现事务没有起作用,然后研究了一下声明式事务的起作用的过程,发现是当程序抛出RuntimeExcetion的时候才会被spring aop中的事务回滚,如果程序异常被捕捉了,声明式事务就不会起作用了。
如下面的代码:
/**
* 事务测试
*/
@Transactional
public void transaction(User user){
try{
System.out.println("程序开始!");
userDao.inser(user);
//模仿抛出一个除0异常
int f = 1;
int g = f/0;
System.out.println("程序结束!");
}catch (Exception e){
System.out.println("程序异常!");
}
}
因为程序中捕捉了异常,所以代码的异常不会往外抛出,事务没有捕捉到runtimeExcetion,所以这段代码是不会回滚的。
那么难道就只能任异常抛出不可以自己捕捉处理了吗?不是的,针对这个我们可以手动回滚,如下面:
/**
* 事务测试
*/
@Transactional
public void transaction(User user){
try{
System.out.println("程序开始!");
userDao.insert(user);
//模仿抛出一个除0异常
int f = 1;
int g = f/0;
System.out.println("程序结束!");
}catch (Exception e){
System.out.println("程序异常!");
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
在程序中,我们使用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();获取当前程序的事务,进行手动回滚,这样子,即实现了自己处理异常,又可以回滚事务了。
最后,再转一个满大街的事务的传播特性,虽然这个使用上面不会很多,但是却是很多公司面试的时候都经常会询问到的技术点
PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。
它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为(如Spring的DataSourceTransactionManager)