原创文章,如需转载,请注明出处。
1.认识事务
对于一个软件系统,事务是为了保证系统状态的完整性,事务本身有四个属性ACID,即原子性(Atomic),一致性(Consistency),隔离性(Isolation)和持久性(Durability)。
2.事务的隔离级别
事务的隔离性各个事务之间相互影响的程度,当两个或更多事务同时访问同一数据资源的时候, 不同的隔离级别决定了各个事务对该数据资源访问的不同行为。隔离级别与系统并发性成反比,与数据一致性成正比。通常,隔离级别按照从弱到强分别为“Read Uncommitted”,“Read Committed”,“Repeatable Read”和“Serializable”,见图1。并非所有的数据库都支持这四种隔离级别,比如Oracle只支持Read Committed和Serializable。
图1:Isolation( 隔离级别)
隔离级别的不同,也会影响脏读(Dirty Read)、不可重复读取(Non-Repeatable Read)和幻读(Phantom Read) 等问题的出现。
脏读(Dirty Read)。 如果一个事务中对数据进行了更新,但事务还没有提交,另一个事务可以“看到”该事务没有提交的更新结果,这样造成的问题就是,如果第一个事务回滚,那么,第二个事务在此之前所“看到”的数据就是一笔脏数据。见图2。
图2:脏读(Dirty Read)
不可重复读取(Non-Repeatable Read)。不可重复读取是指同一个事务在整个事务过程中对同一笔数据进行读取,每次读取结果都不同。如果事务1在事务2的更新操作之前读取一次数据,在事务2的更新操作之后再读取同一笔数据一次,两次结果是不同的,所以,Read Uncommitted也无法避免不可重复读取的问题。 见图3。
图3:不可重复读取(Non-Repeatable Read)
幻读(Phantom Read)。幻读是指同样一笔查询在整个事务过程中多次执行后,查询所得的结果集是不一样的。幻读针对的是多笔记录。在Read Uncommitted隔离级别下, 不管事务2的插入操作是否提交,事务1在插入操作之前和之后执行相同的查询,取得的结果集是不同的,所以,Read Uncommitted同样无法避免幻读的问题。见图4。
图4:幻读(Phantom Read)
3.事务的传播行为(propagation)
事务的传播行为见图5。
图5:事务的传播行为(propagation)
Required和Required_New的区别,见图6。FooService的业务方法的传播行为为Required,表示如果当前存在事务的话,则加入当前事务,因为FoobarService在调用FooService的业务方法的时候已经启动了一个事务,所以,FooSerivce的业务方法会直接加入FoobarService启动的“事务1”中; BarService的业务方法的传播行为Required New, 表示无论当前是否存在事务,都需要为其重新启动一个事务,所以,它使用自己启动的“事务2”。
图6:Required和Required_New的区别
Propagatio_Supports和Propagatio_Not_Supported的区别,见图7。A.service()会首先更新数据库,然后调用B.service()进行查询,那么,B.service()如果是PROPAGATION_SUPPORTS, 就可以读取A.service()之前所做的最新更新结果,而如果使用PROPAGATION_NOT_SUPPORTED,则B.service()将无法读取最新的更新结果,因为A.service()的事务在这个时候还没有提交(除非隔离级别是read uncommitted)。
图7:Propagation_Supports和Propagation_Not_Supported的区别