事务必须服从ACID原则:
ACID是原子性(atomicity)、一致性(consistency)、隔离性 (isolation)持久性(durability)
原子性:表示一个事务必须视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。
一致性:表示当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态。
例子:假如有一个产品表和一个产品明细表,是父子关系,当我们添加产品表的时候,一定要添加产品明细表的资料,如果我们只是添加了产品表没有添加产品明细,这样就会是数据不一致,混乱,这里我们就要用到事务了。
隔离性:表示在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见。
持久性:一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。
事务在Java中的最基本操作:
Ø connection.setAutoCommit(false);//打开事务。
Ø connection.commit();//提交事务。
Ø connection.rollback();//回滚事务。
事务隔离级别:
1) 为了应对多线程并发读取数据时出现的问题,事务有了“隔离级别”特性,多线程并发读取数据一般会引发如下三个问题:
Ø 脏读(dirtyreads)
Ø 不可重复读(non-repeatablereads)
Ø 幻读(phantomread)
下面进行简要介绍:
Ø 脏读:一个事务读取了另一个未提交的并行事务写的数据。
Ø 不可重复读:一个事务重新读取前面读取过的数据, 发现该数据已经被另一个已提交的事务修改过。
Ø 幻读:一个事务重新执行一个查询,返回一套符合查询条件的行, 发现这些行因为其他最近提交的事务而发生了改变。
2) 为了处理上面的读数据问题,java事务提供了4种隔离级别,如下:
Ø 读未提交(Read uncommitted)
Ø 读已提交(Readcommitted)
Ø 可重复读(Repeatableread)
Ø 可串行化(Serializable)
3) 4种隔离级别与上面3个问题的对应关系如下:
注意上面的“可能”二字。
4) 隔离级别的设定:
connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
在代码中的应用:
事务传播行为:
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
例子:
1.@Transactional(propagation= Propagation.NOT_SUPPORTED):以非事务方式运行,如果当前存在事务,则把当前事务挂起。
如果在该模式下,外面事务调用当前service,则当前service中增删除改都是无事务的,即直接commit的。若当前service抛出异常,则使得外面事务回滚。
2.@Transactional(propagation= Propagation.REQUIRES_NEW)创建一个新的事务,如果当前存在事务,则把当前事务挂起。
如果在该模式下,外面事务调用当前service,则当前service中增删除改都处于新事务的。若当前service抛出异常,则使得外面事务回滚。
事务超时:
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。
事务只读属性:
只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。默认为读写事务。
spring事务回滚规则:
指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。可以明确的配置在抛出那些异常时回滚事务,包括checked异常。也可以明确定义那些异常抛出时不回滚事务。还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。
@Transactional注解:
@Transactional属性
属性 类型 描述
value String 可选的限定描述符,指定使用的事务管理器
propagation enum: Propagation 可选的事务传播行为设置
isolation enum: Isolation 可选的事务隔离级别设置
readOnly boolean 读写或只读事务,默认读写
timeout int (in seconds granularity) 事务超时时间设置
rollbackFor Class对象数组,必须继承自Throwable 导致事务回滚的异常类数组
rollbackForClassName 类名数组,必须继承自Throwable 导致事务回滚的异常类名字数组
noRollbackFor Class对象数组,必须继承自Throwable 不会导致事务回滚的异常类数组
noRollbackForClassName 类名数组,必须继承自Throwable 不会导致事务回滚的异常类名字数组
三种Java事务差异
1、JDBC事务控制的局限性在一个数据库连接内,但是其使用简单。
2、JTA事务的功能强大,事务可以跨越多个数据库或多个DAO,使用也比较复杂。
3、容器事务,主要指的是J2EE应用服务器提供的事务管理,局限于EJB应用使用。
隔离级别