`
空指针异常
  • 浏览: 21483 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类

spring事务管理配置:注解和XML

阅读更多
本文内容前面配置从spring3.2.8参考文档摘抄以及自己的理解,后面关于传播级别和隔离的知识点参考自http://www.blogjava.net/freeman1984/archive/2010/04/28/319595.html

一、XML配置(推荐使用XML配置,一次配置可以多处使用,
    注解需要每个方法写  @Transactinal)

<!-- from the file 'context.xml' -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xmlns:tx="http://www.springframework.org/schema/tx"
     xsi:schemaLocation="
     http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/tx
     http://www.springframework.org/schema/tx/spring-tx.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop.xsd">

  <!-- this is the service object that we want to make transactional -->
  <bean id="fooService" class="x.y.service.DefaultFooService"/>

  <!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
  <tx:advice id="txAdvice" transaction-manager="txManager">
  <!-- the transactional semantics... -->
  <tx:attributes>
    <!-- all methods starting with 'get' are read-only -->
    <tx:method name="get*" read-only="true"/>
    <!-- other methods use the default transaction settings (see below) -->
    <tx:method name="*"/>
  </tx:attributes>
  </tx:advice>

  <!-- ensure that the above transactional advice runs for any execution
    of an operation defined by the FooService interface -->
  <aop:config>
  <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
  </aop:config>

  <!-- don't forget the DataSource -->
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
  <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
  <property name="username" value="scott"/>
  <property name="password" value="tiger"/>
  </bean>

  <!-- similarly, don't forget the PlatformTransactionManager -->
  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
  </bean>

  <!-- other <bean/> definitions here -->
</beans>

注:根据spring参考文档,可以对不同的bean设置不同的事务级别

关注点:
1.通过<tx:advice>标签里的<tx:method>指定需要进行事务处理的类。
2.<tx:method>包含属性如下:
  name:方法名称。如“get*”代表以get开始的方法。
  propagation:事务传播级别
  isolation:隔离级别
  timeout:事务超时时间
  read-only:只读。如配置为true,主要是spring用来优化性能,
             或者防止某些方法进行写操    作;不配置为true也能正常工作。
  rollback-for:配置事务需要回滚的异常。
  如:<tx:method name="get*" rollbackfor="NoProductInStockException"/>
  no-rollback-for:配置事务不需要回滚的异常。
  如:<tx:method name="updateStock" no-rollbackfor="InstrumentNotFoundException"/>

二、注解
<!-- from the file 'context.xml' -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xmlns:tx="http://www.springframework.org/schema/tx"
     xsi:schemaLocation="
     http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/tx
     http://www.springframework.org/schema/tx/spring-tx.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop.xsd">

  <!-- this is the service object that we want to make transactional -->
  <bean id="fooService" class="x.y.service.DefaultFooService"/>

  <!-- enable the configuration of transactional behavior based on annotations -->
  <tx:annotation-driven transaction-manager="txManager"/>

  <!-- a PlatformTransactionManager is still required -->
  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <!-- (this dependency is defined somewhere else) -->
  <property name="dataSource" ref="dataSource"/>
  </bean>

  <!-- other <bean/> definitions here -->
</beans>


关注点:
1.在类或者方法上加上@Transactional,即可加入spring的事务管理,两者可以同时加,但方法上的事务优于类的事务。@Transactional的属性与基于XML配置的<tx:method>包含的属性差不多,如下两个属性新增:
rollbackForClassName:需要回滚的类名
noRollbackForClassName:不需要回滚的类名集
默认属性:
a.Propagation setting is PROPAGATION_REQUIRED.
b.Isolation level is ISOLATION_DEFAULT.
c.Transaction is read/write.
d.Transaction timeout defaults to the default timeout of the underlying transaction system, or to none if timeouts are not supported.
e.Any RuntimeException triggers rollback, and any checked Exception does not.

2.<tx:annotation-driven/>属性
  transaction-manager:事务管理器名字;如果事务管理器bean的
  名字默认为“transactionManager”,则此属性默认就会关联;
  如果名字不是“transactionManager”,则需要指定。
  mode:代理模式,默认“proxy”,直接使用spring aop方式处理;
  也可以选择“aspectj”,则用aspectj方式处理,具体参考文档。
(基于XML的配置不可以选择。)
  proxy-target-class:默认false,基于JDK动态代理,只适用于面向接口编程;
  当有些特殊情况不是面向接口编程时,可以使用CGLIB等基于继承的代理方式,
  值为true。基于XML方式的配置也可以指定此值,在<aop:config>有此属性。
  order:当有多个advise存在时,可以通过此属性指定执行顺序。
  基于XML方式的配置可以参考文档。

三、事务传播与隔离级别。(TransactionDefinition中定义)
    
/**
      * Support a current transaction; create a new one if none exists.
      */
     int PROPAGATION_REQUIRED = 0;

     /**
      * Support a current transaction; 
      * execute non-transactionally if none exists.
      */
     int PROPAGATION_SUPPORTS = 1;

     /**
      * Support a current transaction; 
      * throw an exception if no current transaction.
      */
     int PROPAGATION_MANDATORY = 2;

     /**
      * Create a new transaction, 
      * suspending the current transaction if one exists.
      */
     int PROPAGATION_REQUIRES_NEW = 3;

     /**
      * Do not support a current transaction; 
      * rather always execute non-transactionally.
      */
     int PROPAGATION_NOT_SUPPORTED = 4;

     /**
      * Do not support a current transaction; 
      * throw an exception if a current transaction
      */
     int PROPAGATION_NEVER = 5;

     /**
      * Execute within a nested transaction if a current transaction
      */
     int PROPAGATION_NESTED = 6;


     /**
      * Use the default isolation level of the underlying datastore.
      */
     int ISOLATION_DEFAULT = -1;

     /**
      * Indicates that dirty reads, non-repeatable reads and phantom reads
      * can occur.
      */
     int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;

     /**
      * Indicates that dirty reads are prevented; non-repeatable reads and
      * phantom reads can occur.
      */
      int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
 
     /**
      * Indicates that dirty reads and non-repeatable reads are prevented;
      * phantom reads can occur.
      */
     int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;

     /**
      * Indicates that dirty reads, non-repeatable reads and phantom reads
      * are prevented.
      */
     int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;



四、事务传播实例
  
ServiceA {
     /** 
      * 事务属性配置为 PROPAGATION_REQUIRED 
      */ 
     void methodA() { 
         ServiceB.methodB(); 
     } 
   } 
  
   ServiceB { 
     /** 
      * 事务属性配置为 PROPAGATION_REQUIRED 
      */ 
     void methodB() { 
     } 
   } 


   1: PROPAGATION_REQUIRED
   加入当前正要执行的事务不在另外一个事务里,那么就起一个新的事务 比如说,ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED, 那么由于执行  ServiceA.methodA的时候,ServiceA.methodA已经起了事务,这时调用ServiceB.methodB,ServiceB.methodB看到自己已经运行在ServiceA.methodA 的事务内部,就不再起新的事务。而假如ServiceA.methodA运行的时候发现自己没有在事  务中,他就会为自己分配一个事务。这样,在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都会被   回滚。即使ServiceB.methodB的事务已经被 提交,但是ServiceA.methodA在接下来fail要回滚,ServiceB.methodB也要回滚

   2: PROPAGATION_SUPPORTS
   如果当前在事务中,即以事务的形式运行,如果当前不再一个事务中,那么就以非事务的  形式运行

   3: PROPAGATION_MANDATORY
   必须在一个事务中运行。也就是说,他只能被一个父事务调用。否则,他就要抛出异常

    4: PROPAGATION_REQUIRES_NEW
    这个就比较绕口了。 比如我们设计ServiceA.methodA的事务级别PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_REQUIRES_NEW,那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的事务,等待ServiceB.methodB的事务完成以后, 他才继续执行。他PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为ServiceB.methodB是新起一个事务,那么就是存在两个不同的事务。如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。如果ServiceB.methodB失败回滚, 如果他抛出的异常被ServiceA.methodA捕获,ServiceA.methodA事务仍然可能提交。

    5: PROPAGATION_NOT_SUPPORTED
    当前不支持事务。比如ServiceA.methodA的事务级别是PROPAGATION_REQUIRED ,而ServiceB.methodB的事务级别是PROPAGATION_NOT_SUPPORTED,那么当执行ServiceB.methodB时,ServiceA.methodA的事务挂起,而他以非事务的状态运行完,再继续ServiceA.methodA的事务。

    6: PROPAGATION_NEVER
    不能在事务中运行。假设ServiceA.methodA的事务级别是PROPAGATION_REQUIRED, 而ServiceB.methodB的事务级别是PROPAGATION_NEVER , 那么ServiceB.methodB就要抛出异常了。

    7: PROPAGATION_NESTED
    理解Nested的关键是savepoint。他与PROPAGATION_REQUIRES_NEW的区别是PROPAGATION_REQUIRES_NEW另起一个事务,将会与他的父事务相互独立, 而Nested的事务和他的父事务是相依的,他的提交是要等和他的父事务一块提交的。也就是说,如果父事务最后回滚,他也要回滚的。 而Nested事务的好处是他有一个savepoint。
如下所示:
  
 ServiceA { 
    /** 
     * 事务属性配置为 PROPAGATION_REQUIRED 
     */ 
     void methodA() { 
        try { 
             //savepoint 
             ServiceB.methodB(); //PROPAGATION_NESTED 级别 
        } catch (SomeException) { 
             // 执行其他业务, 如 ServiceC.methodC(); 
        } 
      } 
     } 

     也就是说ServiceB.methodB失败回滚,那么ServiceA.methodA也会回滚到savepoint点上,ServiceA.methodA可以选择另外一个分支,比如ServiceC.methodC,继续执行,来尝试完成自己的事务。 但是这个事务并没有在EJB标准中定义。

五、Isolation Level(事务隔离等级)
    1、Serializable:最严格的级别,事务串行执行,资源消耗最大;
    2、REPEATABLE READ:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。
    3、READ COMMITTED:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。
    4、Read Uncommitted:保证了读取过程中不会读取到非法数据。隔离级别在于处理多事务的并发问题。
    我们知道并行可以提高数据库的吞吐量和效率,但是并不是所有的并发事务都可以并发运行,这需要查看数据库教材的可串行化条件判断了。

    我们首先说并发中可能发生的3中不讨人喜欢的事情
    1: Dirty reads--读脏数据。也就是说,比如事务A的未提交(还依然缓存)的数据被事务B读走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的。
    2: non-repeatable reads--数据不可重复读。比如事务A中两处读取数据-total-的值。在第一读的时候,total是100,然后事务B就把total的数据改成200,事务A再读一次,结果就发现,total竟然就变成200了,造成事务A数据混乱。
    3: phantom reads--幻象读数据,这个和non-repeatable reads相似,也是同一个事务中多次读不一致的问题。但是non-repeatable reads的不一致是因为他所要取的数据集被改变了(比如total的数据),但是phantom reads所要读的数据的不一致却不是他所要读的数据集改变,而是他的条件数据集改变。比如Select account.id where account.name="ppgogo*",第一次读去了6个符合条件的id,第二次读取的时候,由于事务b把一个帐号的名字由"dd"改成"ppgogo1",结果取出来了7个数据。

参考自:http://www.cnblogs.com/digdeep/p/4947694.html
一致性读,又称为快照读。使用的是MVCC机制读取undo中的已经提交的数据。所以它的读取是非阻塞的。

相关文档:http://dev.mysql.com/doc/refman/5.6/en/innodb-consistent-read.html

A consistent read means that InnoDB uses multi-versioning to present to a query a snapshot of the database at a point in time. The query sees the changes made by transactions that committed before that point of time, and no changes made by later or uncommitted transactions. The exception to this rule is that the query sees the changes made by earlier statements within the same transaction.

一致性读肯定是读取在某个时间点已经提交了的数据,有个特例:本事务中修改的数据,即使未提交的数据也可以在本事务的后面部分读取到。

1. RC 隔离 和 RR 隔离中一致性读的区别

根据隔离级别的不同,一致性读也是不一样的。不同点在于判断是否提交的“某个时间点”:

1)对于RR隔离:

If the transaction isolation level is REPEATABLE READ (the default level), all consistent reads within the same transaction read the snapshot established by the first such read in that transaction.

文档中说的是:the first such read in that transaction。实际上实验的结果表明,这里的 the first such read指的是:对同一个表或者不同表进行的第一次select语句建立了该事务中一致性读的snapshot. 其它update, delete, insert 语句和一致性读snapshot的建立没有关系。在snapshot建立之后提交的数据,一致性读就读不到,之前提交的数据就可以读到。

事务的起始点其实是以执行的第一条语句为起始点的,而不是以begin作为事务的起始点的。

实验1:
sesseion A

session B
mysql> set tx_isolation='repeatable-read';
Query OK, 0 rows affected (0.00 sec)


mysql> set tx_isolation='repeatable-read';
Query OK, 0 rows affected (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.01 sec)




mysql> select * from t1;
Empty set (0.00 sec)

mysql> insert into t1(c1,c2) values(1,1);
Query OK, 1 row affected (0.01 sec)
mysql> select * from t1;
+----+------+
| c1 | c2   |
+----+------+
|  1 |    1 |
+----+------+
1 row in set (0.00 sec)



上面的实验说明:RR隔离级别下的一致性读,不是以begin开始的时间点作为snapshot建立时间点,而是以第一条select语句的时间点作为snapshot建立的时间点。

实验2:
session A

session B
mysql> set tx_isolation='repeatable-read';

mysql> set tx_isolation='repeatable-read';


mysql> select * from t1;
Empty set (0.00 sec)
mysql> begin;
mysql> select * from t;




mysql> insert into t1(c1,c2) values(1,1);
Query OK, 1 row affected (0.01 sec)
mysql> select * from t1;
Empty set (0.00 sec) 


该使用说明:RR隔离级别下的一致性读,是以第一条select语句的执行点作为snapshot建立的时间点的,即使是不同表的select语句。这里因为session A在insert之前对 t 表执行了select,所以建立了snapshot,所以后面的select * from t1 不能读取到insert的插入的值。

实验3:
session A

session B
mysql> set tx_isolation='repeatable-read';

mysql> set tx_isolation='repeatable-read';
mysql> select * from t1;
Empty set (0.00 sec)
mysql> begin;

mysql> select * from t1;
Empty set (0.00 sec)

mysql> select * from t1;
Empty set (0.00 sec)


mysql> insert into t1(c1,c2) values(1,1);
mysql> select * from t1;
Empty set (0.01 sec)



该实验中:session A 的第一条语句,发生在session B的 insert语句提交之前,所以session A中的第二条select还是不能读取到数据。因为RR中的一致性读是以事务中第一个select语句执行的时间点作为snapshot建立的时间点的。而此时,session B的insert语句还没有执行,所以读取不到数据。

实验4:
session A

session B
mysql> set tx_isolation='repeatable-read';

mysql> set tx_isolation='repeatable-read';
mysql> select * from t1;
Empty set (0.00 sec)
mysql> select * from t1;
Empty set (0.00 sec)




mysql> insert into t1(c1,c2) values(1,1),(2,2);
mysql> select * from t1;
+----+------+
| c1 | c2   |
+----+------+
|  1 |    1 |
|  2 |    2 |
+----+------+
2 rows in set (0.01 sec)
mysql> select * from t1;
Empty set (0.00 sec)


mysql> update t1 set c2=100 where c1=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from t1;
+----+------+
| c1 | c2   |
+----+------+
|  1 |  100 |
+----+------+
1 row in set (0.00 sec)



该实验说明:本事务中进行修改的数据,即使没有提交,在本事务中的后面也可以读取到。update 语句因为进行的是“当前读”,所以它可以修改成功。

2)对于RC隔离就简单多了:

With READ COMMITTED isolation level, each consistent read within a transaction sets and reads its own fresh snapshot.

事务中每一次读取都是以当前的时间点作为判断是否提交的实际点,也即是 reads its own fresh snapshot.

RC是语句级多版本(事务的多条只读语句,创建不同的ReadView,代价更高),RR是事务级多版本(一个ReadView);

3. MySQL 中事务开始的时间

一般我们会认为 begin/start transaction 是事务开始的时间点,也就是一旦我们执行了 start transaction,就认为事务已经开始了,其实这是错误的。上面的实验也说明了这一点。事务开始的真正的时间点(LSN),是 start transaction 之后执行的第一条语句,不管是什么语句,不管成功与否。

但是如果你想要达到将 start transaction 作为事务开始的时间点,那么我们必须使用:

START TRANSACTION WITH consistent snapshot

它的含义是:执行 start transaction 同时建立本事务一致性读的 snapshot . 而不是等到执行第一条语句时,才开始事务,并且建立一致性读的 snapshot .

The WITH CONSISTENT SNAPSHOT modifier starts a consistent read for storage engines that are capable of it. This applies only to InnoDB. The effect is the same as issuing a START TRANSACTION followed by a SELECT from any InnoDB table. See Section 14.2.2.2, “Consistent Nonlocking Reads”. The WITH CONSISTENT SNAPSHOT modifier does not change the current transaction isolation level, so it provides a consistent snapshot only if the current isolation level is one that permits a consistent read. The only isolation level that permits a consistent read is REPEATABLE READ. For all other isolation levels, the WITH CONSISTENT SNAPSHOT clause is ignored. As of MySQL 5.7.2, a warning is generated when the WITH CONSISTENT SNAPSHOT clause is ignored.

http://dev.mysql.com/doc/refman/5.6/en/commit.html
效果等价于: start transaction 之后,马上执行一条 select 语句(此时会建立一致性读的snapshot)。

If the transaction isolation level is REPEATABLE READ (the default level), all consistent reads within the same transaction read the snapshot established by the first such read in that transaction. You can get a fresher snapshot for your queries by committing the current transaction and after that issuing new queries. (RR隔离级别中的一致性读的snapshot是第一条select语句执行时建立的,其实应该是第一条任何语句执行时建立的)

http://dev.mysql.com/doc/refman/5.6/en/innodb-consistent-read.html

我们在 mysqldump --single-transaction 中使用的就是该语句:

SET session TRANSACTION isolation LEVEL REPEATABLE read
START TRANSACTION /*!40100 WITH consistent snapshot */

所以事务开始时间点,分为两种情况:

1)START TRANSACTION 时,是第一条语句的执行时间点,就是事务开始的时间点,第一条select语句建立一致性读的snapshot;

2)START TRANSACTION  WITH consistent snapshot 时,则是立即建立本事务的一致性读snapshot,当然也开始事务了;

实验1:
session A

session B
mysql> set tx_isolation='repeatable-read';

mysql> set tx_isolation='repeatable-read';


mysql> select * from t1;
Empty set (0.01 sec)
mysql> start transaction;




mysql> insert into t1(c1,c2) values(1,1);
mysql> select * from t1;
+----+------+
| c1 | c2   |
+----+------+
|  1 |    1 |
+----+------+
1 row in set (0.00 sec)


实验2:
mysql> set tx_isolation='repeatable-read';

mysql> set tx_isolation='repeatable-read';


mysql> select * from t1;
Empty set (0.01 sec)
mysql> start transaction with consistent snapshot;




mysql> insert into t1(c1,c2) values(1,1);
mysql> select * from t1;
Empty set (0.00 sec)


上面两个实验很好的说明了 start transaction 和 start tansaction with consistent snapshot的区别。第一个实验说明,start transaction执行之后,事务并没有开始,所以insert发生在session A的事务开始之前,所以可以读到session B插入的值。第二个实验说明,start transaction with consistent snapshot已经开始了事务,所以insert语句发生在事务开始之后,所以读不到insert的数据。

3. Oracle中的一致性读

Oracle读一致性是指一个查询所获得的数据来自同一时间点。

Oracle读一致性分为语句级读一致性和事务级读一致性。

语句级读一致性:Oracle强制实现语句级读一致性。一个查询语句只读取语句开始之前提交的数据。

事务级读一致性:隔离级别为SERIALIZABLE和read only的事务才支持事务级读一致性。事务中的所有查询语句只读取 事务开始之前提交的数据。

Oracle只实现了RC和serializable,没有实现Read uncommitted 和 RR。其实Oracle的serializable级别才实现了可重复读。

4. 当前读(current read) 和 一致性读

一致性读是指普通的select语句,不带 for update, in share mode 等等子句。使用的是undo中的提交的数据,不需要使用锁(MDL除外)。而当前读,是指update, delete, select for update, select in share mode等等语句进行的读,它们读取的是数据库中的最新的数据,并且会锁住读取的行和gap(RR隔离时)。如果不能获得锁,则会一直等待,直到获得或者超时。RC隔离级别的当前读没有gap lock,RC的update语句进行的是“半一致性读”,和RR的update语句的当前读不一样。

5. 一致性读与 mysqldump --single-transaction

我们知道 mysqldump --single-transaction的原理是:设置事务为RR模式,然后利用事务的特性,来获得一致性的数据,但是:

--single-transaction
                      Creates a consistent snapshot by dumping all tables in a
                      single transaction. Works ONLY for tables stored in
                      storage engines which support multiversioning (currently
                      only InnoDB does); the dump is NOT guaranteed to be
                      consistent for other storage engines. While a
                      --single-transaction dump is in process, to ensure a
                      valid dump file (correct table contents and binary log
                      position), no other connection should use the following
                      statements: ALTER TABLE, DROP TABLE, RENAME TABLE,
                      TRUNCATE TABLE, as consistent snapshot is not isolated
                      from them. Option automatically turns off --lock-tables.

在mysqldump运行期间,不能执行 alter table, drop table, rename table, truncate table 等等的DDL语句,因为一致性读和这些语句时无法隔离的。

那么在mysqldump --single-transaction 执行期间,执行了上面那些DDL,会发生什么呢?

mysqldump --single-transaction 的执行过程是:设置RR,然后开始事务,对应了一个LSN,然后对所有选中的表,一个一个的执行下面的过程:

save point sp; --> select * from t1 --> rollback to sp;

save point sp; --> select * from t2 --> rollback to sp;

... ...

1> 那么如果对t2表的DDL发生在 save point sp 之前,那么当mysqldump处理到 t2 表时,mysqldump 会立马报错:表结构已经改变......

2> 如果对t2表的DDL发生在 save point sp 之后,rollback to sp 之前,那么要么DDL被阻塞,要么mysqldump被阻塞,具体谁被阻塞,看谁先执行了。

     被阻塞额原因是:DDL需要t2表的 MDL 的互斥锁,而select * from t1 需要MDL的共享锁,所以阻塞发生。

3> 如果对t2表的DDL发生在 rollback to sp 之后,那么因为对 t2 表的dump已经完成,不会发生错误或者阻塞。

那么为什么: 对t2表的DDL发生在 save point sp 之前,那么当mysqldump开始处理 t2 表时,mysqldump 立马报错呢?

其原因就是 一致性读的胳膊拗不过DDL的大腿:

Consistent read does not work over certain DDL statements:(一致性读的胳膊拗不过DDL的大腿)

    Consistent read does not work over DROP TABLE, because MySQL cannot use a table that has been dropped and InnoDB destroys the table.

    Consistent read does not work over ALTER TABLE, because that statement makes a temporary copy of the original table and deletes the original table when the temporary copy is built. When you reissue a consistent read within a transaction, rows in the new table are not visible because those rows did not exist when the transaction's snapshot was taken. In this case, the transaction returns an error as of MySQL 5.6.6: ER_TABLE_DEF_CHANGED, “Table definition has changed, please retry transaction”.

原因:ALTER TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE 这些DDL语句的执行,会导致无法使用undo构造出正确的一致性读,一致性读和它们是无法隔离的。
分享到:
评论
1 楼 骑自行车去旅行 2014-04-18  

相关推荐

    spring事务,xml方式和注解方式

    包含了spring事务的两种使用方式,xml和注解,有数据库

    Spring 整合mybatis(注解&xml版声明式事务).pdf

    Spring 整合mybatis(注解&xml版声明式事务).pdf

    Spring JDBC与事务管理

    3、了解Spring事务管理的3个核心接口; 4、了解Spring事务管理的两种方式; 5、掌握基于XML和Annotation的声明式事务管理的使用。 二.实验内容 (1)使用Spring JDBC实现书店的购书过程,即有如下一个BookShopDao接口...

    Spring中的事务操作、注解及XML配置详解

    主要给大家介绍了关于Spring中事务操作、注解及XML配置的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    spring注解事务实现demo

    声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。spring注解事务实现demo

    spring五种事务配置demo

    测试spring事务管理 搭建了ssh框架的web工程 本工程用到的数据库表很简单 user(id, name) 可自行创建 本例所有的事务放在service层进行管理,方法中间抛出运行时异常以测试是否回滚 Spring配置文件中关于事务...

    Spring框架--事务管理

    Spring提供了两种事务管理方式:编程式事务管理和声明式事务管理; 描述了声明式事务管理,XML,注解;事务配置详解。。。

    基于java的企业级应用开发:声明式事务管理.ppt

    5.2.2 基于Annotation方式的声明式事务 基于Annotation方式的声明式事务 1 在Spring容器中注册事务注解驱动; 2 在需要事务管理的类或方法上使用@Transactional注解。 &lt;tx:annotation-driven transaction-manager=...

    Spring事务优缺点及使用详解.docx

    事务简介 二、程序举例环境搭建 o1. 创建数据表 ...三、使用 Spring 的事务注解管理事务 o1. 声明事务管理器 o2. 开启注解驱动 o3. 完整Spring配置文件 o4. 业务层 public 方法加入事务属性 o5. 测试

    Spring+Hibernate事务管理

    Spring将事务管理分成了两类: * 编程式事务管理 * 手动编写代码进行事务管理.(很少使用) * 声明式事务管理: * 基于TransactionProxyFactoryBean的方式.(很少使用) * 需要为每个进行事务管理的类,配置一个...

    spring.doc

    5.1.8.4以XML配置的 形式 119 拓展: 120 5.1.8.5以注解方式配置 125 拓展: 127 5.1.9使用CGLIB以XML形式配置事务 130 5.2 Spring+Hibernate 131 5.2.1 HibernateTemplate模板 131 5.2.2 声明式事务 131 配置XML...

    spring hibernate,spring jdbc事务管理

    两个项目,一个项目是基于spring jdbc实现的分布式事务,一个是基于spring ...applicationContext4.xml使用注解管理事务,基于mysql和mssql 这两个项目下来,关于spring事务这一块基本上明了,绝对对得起这个分数

    整合Mybatis和Spring框架进行注解开发SSM框架的学习与应用-Java EE企业级应用开发学习记录(第十天)

    2. 注解开发: 我们将深入讨论如何使用注解来配置和管理Spring容器、控制器、服务层和数据访问层。注解开发可以显著简化配置,并提高代码的可读性。 3. 整合配置: 我们将演示如何将Spring、Spring MVC和MyBatis进行...

    Spring.html

    注意:使用注解的方式,最终通知和后置通知顺序换了,建议使用环绕通知 注解 配置 声明式事务管理 PlatFormTransactionManager:平台事务管理器:定义了commit/rollback Mybatis/jdbc:...

    spring_trans.zip

    最简单的dbutils+spring事务控制,注解+xml配置,入门必备.绝对可以运行.包含spring bean,aop,注解,事务等基础知识

    Spring高级之注解驱动开发视频教程

    学习spring,要有一定的Java基础,同时应用过spring基于xml的配置。(或者学习过官网的Spring课程) 学习springmvc,要有一定java web开发基础。同时对spring框架要有一定了解。 3、课程亮点 系统的学习Spring框架...

    Spring中的事务管理

    Spring中基于注解的声明式事务管理和基于XML文件的声明式事务管理测试程序

    高级开发spring面试题和答案.pdf

    AOP实现方式:aop注解或者xml配置;后来工具jar包aspects; aop的属性 事务 事务编码方式: 事务注意事项; 为什么同一个类A调用b方法事务,A方法一定要有事务(编码式的不用) @transaction多个数据源事务怎么指定...

    spring框架手动提交事务,jdbctample

    注意:只是jdbc自带的jdbctample,不能 用于整合mybatis框架的事务,我整合了,事务不起作用!!!! 按老师的说法是基于xml方式,但不准确,因为也用到了注解 &lt;aop:aspectj-autoproxy proxy-target-class="true"&gt;...

    spring整合hibernate实现事务处理

    spring整合hibernate实现事务处理 1.spring整合hibernate实现事务处理-注解方式 2.spring整合hibernate实现事务处理-XML方式

Global site tag (gtag.js) - Google Analytics