事务详解

来源:互联网 发布:智能社node抽奖 编辑:程序博客网 时间:2024/06/06 23:16

一、事务的ACID属性

事务使用ACID特性来衡量事务的质量。

1、原子性

   事务必须是原子的,在事务结束的时候,事务中的所有任务必须全部成功完成,否则全部失败,事务回滚到事务开始之间的状态。

2、一致性

   事务必须保证和数据库的一致性,即数据库中的所有数据和现实保持一致。如果事务失败数据必须返回到事务执行之前的状态,反之修改数据和现实的同步。

3、隔离性

   隔离性是事务与事务之间的屏障,每个事务必须与其他事务的执行结果隔离开,直到该事务执行完毕,它保证了事务的访问的任何数据不会受其他事务执行结果的影响。

4、持久性

   如果事务成功执行,无论系统发生任何情况,事务的持久性都必须保证事务的执行结果是永久的。

二、事务的隔离级别

ANSI/ISO SQL标准定义了4中事务隔离级别:

1、未提交(read uncommitted

   一个事务读取另外一个尚未提交的事务的数据。

2、已提交(read committed

   一个事务读取另外已经提交的事务的数据。

3、重复读(repeatable read

  一个事务在两个不同时间点读取的数据是一致的。

4、串行读(serializable read

  不同的事务是按顺序执行,不会相互影响。

 

对于不同的事务,采用不同的隔离级别分别有不同的结果,不同的隔离级别有不同的现象,主要有下面3种现象:

(1) 脏读(dirty read

   一个事务可以读取另一个尚未提交事务的修改数据。

   ‘读未提交’这种事务隔离级别则可能会出现脏读的情况。

(2) 非重复读(nonrepeatable read

   在同一个事务中,同一个查询在T1时间读取某一行,在T2时间重新读取这一行时候,这一行的数据已经发生修改,可能被更新了(update),也可能被删除了(delete)。

(3) 幻像读(phantom read

   在同一事务中,同一查询多次进行时候,由于其他插入操作(insert)的事务提交,导致每次返回不同的结果集。

 

不同的隔离级别有不同的现象,并有不同的锁定/并发机制,隔离级别越高,数据库的并发性就越差,4种事务隔离级别分别表现的现象如下:

(1)  读未提交(read uncommitted

      允许出现脏读、不可重复读、幻象读。

(2) 读已提交(read committed

     不会出现脏读,允许出现不可重复读、幻象读。

(3) 重复读(repeatable read

     不会出现脏读、不可重复读,允许出现幻象读。

(4) 串行读(serializable read

    不会出现脏读、不可重复读、幻象读。

 

常用数据库的事务隔离级别

(1) MySQL

     默认的隔离级别是:repeatable read

(2) ORACLE

     默认的隔离级别是:read committed

三、MYSQL中的事务

 在MySQL中默认事务隔离级别是可重复读(Repeatable read).可通过SQL语句查询:
查看InnoDB系统级别的事务隔离级别:

mysql> SELECT @@global.tx_isolation;+-----------------------+| @@global.tx_isolation |+-----------------------+| REPEATABLE-READ       |+-----------------------+

查看InnoDB全局级别的事务隔离级别

查看InnoDB会话级别的事务隔离级别:mysql> SELECT @@tx_isolation;+-----------------+| @@tx_isolation  |+-----------------+| REPEATABLE-READ |+-----------------+

MYSQL中事务隔离级别的值有:

READ   COMMITTED
READ   UNCOMMITTED
REPEATABLE   READ
SERIALIZABLE


1、修改事务隔离级别是read uncommitted

事务T1在执行的过程中会去读取事务T2中未提交的数据,从而出现脏读。

2、修改事务隔离级别是read committed

出现不可重复读问题。

3、修改事务隔离级别是read repeatable

不会出现不可重复读的问题,但会出现幻读。

4、修改事务隔离级别是read serializable

如果事务的隔离级别是read serializable,意味着事务是排队执行的,事务之间不会相互影响,这种情况下不会出现脏读、不可重复读和幻读的情况,但数据库的并发性能非常差,所以一般数据库都不会使用这种隔离级别。

四、Spring的事务管理方式

1)编程式事务

在代码中实现事务的控制,比较少用。

2)声明式事务

         通过配置AOP的方式来实现事务的控制,比较简洁。

定义事务管理器

<beanid="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

       <propertyname="dataSource"ref="dataSource"></property>

</bean>

 

定义通知

<tx:adviceid="txAdvice"transaction-manager="txManager">

       <tx:attributes>

           <tx:methodname="get*"/>

           <tx:methodname="query*"/>

           <tx:methodname="search*"/>

           <tx:methodname="save*"propagation="REQUIRED"/>

           <tx:methodname="update*"propagation="REQUIRED"/>

           <tx:methodname="delete*"propagation="REQUIRED"/>

           <tx:methodname="test*"propagation="REQUIRED"rollback-for="java.lang.Exception"/>

           <tx:methodname="*"read-only="true"/>

       </tx:attributes>

</tx:advice>

<!--

     propagation传播属性的值

     REQUIRED默认值,业务方法需要在一个事务中运行。如果方法运行时,已经在一个事务中,那么加入到该事务,否则自己创建一个新的事务。一般spring默认都是这种事务,像保存,删除,修改等都是这种事务。

     SUPPORTS:如果方法在某个事务范围内被调用,则方法成为该事务的一部分。如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行。

     MANDATORY:该属性指定业务方法必须在一个事务中运行,业务方法不能发起自己的事务。如果业务方法在没有事务的环境下调用,容器会抛出例外。

     REQUIRES_NEW:属性不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先事务才会恢复执行。

     NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会执行。

     NEVER:指定业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任何事务,才能正常执行。

     NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中,如果没有活动事务,则按Required属性执行,它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响,它只对DataSourceTransactionManager事务管理器起效。

-->

<!--

      isolation隔离属性的值

      DEFAULT:默认值,使用数据库默认的隔离级别

      READ_COMMITTEDOracle中默认的事务隔离级别,允许读取其他并发事务已经提交的更新(防止脏读)

      READ_UNCOMMITTED:允许读取其他并发事务还未提交的更新,会导致事务之间的3个缺陷发生,这是速度最快的一个隔离级别,但同时它的隔离级别也是最低

      REPEATABLE_READMySQL5默认的事务隔离级别,除非事务自身修改了数据,否则规定事务多次重复读取,数据必须相同(防此脏读,不可重复读)

      SERIALIZABLE这是最高的隔离级别,它可以防此脏读,不可重复读和幻读等问题,但因其侵占式的数据记录完全锁定,导致它影响事务的性能,成为隔离级别中最展慢的一个。

-->

 <!--

     timeout超时属性,默认值-1,以秒为单位

-->

<!--

     read-only只读属性,默认值false,为true的话,事务只能读数据,而不能进行了插入、修改、删除操作。而且默认将数据库的隔离级别提高一级到可重复读。

可重复读:从这一点设置的时间点开始(时间点a)到这个事务结束的过程中,其他事务所提交的数据,该事务将看不见!(查询中不会出现别人在时间点a之后提交的数据)

-->

<!--

     rollback-for service中触发回滚的异常。

     spring默认只在发生未被捕获的RuntimeException时才回滚

     如果配置rollback-for="java.lang.Exception",那么service中抛出异常java.lang.Exception时,事务就会回滚。

-->

配置切入点

<aop:config>

       <aop:pointcutid="servicePointcut"expression="execution(* com.service..*.*(..))"/>

       <aop:advisoradvice-ref="txAdvice"pointcut-ref="servicePointcut"/>

</aop:config>

<!--

      execution(* com.service..*.*(..))的解读

        第一个*号表示任务返回类型

      com.service.* 表示包com.service下的任意类

      com.service..* 表示包com.service及其子包下的任意类

      com.service.*.* 表示包com.service下的任意类的任意方法

      com.service..*.* 表示包com.service及其子包下的任意类的任意方法

      (..) 匹配0个参数或者多个参数的,任意类型

      (x,..) 第一个参数的类型必须是X

      (x,,,s,..) 匹配至少4个参数,第一个参数必须是x类型,第二个和第三个参数可以任意,第四个必须是s类型。

 -->

 

原创粉丝点击