`
空指针异常
  • 浏览: 22583 次
  • 性别: 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配置和注解两种方式,使得开发者能够灵活地控制事务的边界和行为。XML方式适合于传统应用,而注解方式则更加简洁,易于理解和维护。无论选择哪种方式,Spring事务管理都能帮助我们...

    Spring事务管理Demo

    Spring事务管理的目的是确保数据的一致性和完整性,尤其是在多操作、多资源的环境中。本Demo将深入探讨Spring如何实现事务的管理。 首先,Spring提供了两种主要的事务管理方式:编程式事务管理和声明式事务管理。 ...

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

    如果采用XML配置方式,则需要在Spring的XML配置文件中进行事务配置,并通过aop命名空间来定义事务通知及切点,从而实现声明式事务管理。 对于开发者而言,Spring与MyBatis的整合简化了事务和持久层的处理,减少了...

    Spring全注解project示例 (无web.xml配置)

    标题 "Spring全注解project示例 (无web.xml配置)" 提供了我们即将探讨的核心主题:一个使用Spring框架,完全依赖注解配置的项目,且没有传统的web.xml部署描述符。这种配置方式在现代Spring应用中非常常见,因为它...

    spring3.0两种事务管理配置

    Spring 3.0 提供了两种事务管理配置方法:基于 XML 的事务管理和基于 @Transactional 的事务管理,这两种方法都是为了实现事务管理的目标,分别具有不同的配置方式和优缺点。 基于 XML 的事务管理 这种方法不需要...

    spring aop注解方式、xml方式示例

    下面将详细介绍Spring AOP的注解方式和XML配置方式。 ### 注解方式 #### 1. 定义切面(Aspect) 在Spring AOP中,切面是包含多个通知(advisors)的类。使用`@Aspect`注解标记切面类,例如: ```java @Aspect ...

    Spring基于XML方式配置事务

    编程式事务管理通过`PlatformTransactionManager`接口及其实现类(如`DataSourceTransactionManager`)进行手动控制,而声明式事务管理则更加简便,通过在XML配置或注解中声明事务边界。 在XML配置中,事务管理主要...

    Spring框架xml注解配置方式实例

    Spring框架通过读取这个文件来创建和管理对象。XML配置允许我们声明性地配置bean,但随着注解的引入,我们可以在代码中直接标注bean的属性,简化配置。 3. **类源码(springtest3)** "springtest3"通常代表一个或...

    spring mvc+hibernate 实现事务管理(全注解版)

    1. **Spring事务管理**: Spring提供了PlatformTransactionManager接口,它定义了事务管理的核心操作。在Spring MVC中,我们可以使用DataSourceTransactionManager,它依赖于JDBC的数据源来管理事务。在配置文件中,...

    SSM中进行注解式和XML配置式事务管理代码

    本篇将详细探讨在SSM中如何进行注解式和XML配置式的事务管理,以实现数据的一致性和完整性。 **一、Spring事务管理简介** Spring作为核心容器,提供了强大的事务管理功能,支持编程式和声明式事务管理。编程式事务...

    Xml文件配置实现声明式事务管理

    在Spring框架中,声明式事务管理是一种非常重要的特性,它允许开发者通过XML配置或注解来定义事务的边界,而无需在业务代码中显式地管理事务。这种方式极大地提高了代码的可读性和可维护性。本篇文章将深入探讨如何...

    spring 事务管理的理解

    Spring 框架是Java开发中...理解并熟练掌握Spring事务管理,对于提升应用程序的稳定性和可靠性至关重要。在实际开发中,结合声明式事务管理、事务传播行为、隔离级别和回滚规则,可以有效地确保数据的完整性和一致性。

    spring事务管理5种方法

    本篇文章将深入探讨Spring事务管理的五种方法,旨在帮助开发者更好地理解和运用这一核心特性。 首先,我们来了解什么是事务。在数据库操作中,事务是一组逻辑操作,这些操作要么全部成功,要么全部失败,确保数据的...

    JavaEE spring事务操作环境和基本功能搭建

    - 配置:在Spring的XML配置文件中,使用`&lt;tx:annotation-driven&gt;`启用基于注解的事务管理。 - 注解:在需要事务控制的方法上使用`@Transactional`注解,该注解可以指定事务的传播行为、隔离级别、读写模式等属性。...

    spring事务与数据库操作

    ### Spring事务与数据库操作 #### 一、Spring的声明式事务管理 在现代软件开发中,事务处理是非常关键的一部分,特别是在涉及多个数据操作时。Spring框架提供了强大的事务管理能力,可以方便地集成到应用程序中。...

    Spring中Aop的使用包括xml和注解

    这里我们将深入探讨两种在Spring中实现AOP的方式:XML配置和注解配置。 首先,让我们来看看**XML配置AOP**。在Spring的早期版本中,XML配置是主要的配置方式。在`spring-aop-xml`中,你可能会看到以下关键元素: 1...

    Spring事务管理的jar包

    开发者可以在XML配置文件中定义事务管理器,并声明需要事务管理的bean。 对于声明式事务管理,Spring主要通过AOP(面向切面编程)来实现。我们可以使用@Transactional注解标记在类或者方法级别,表示该类或方法需要...

    Spring+Hibernate注解事务实例

    其中,声明式事务管理通过注解或者XML配置实现,更为简洁且易于维护。 Hibernate是一个流行的Java ORM(对象关系映射)框架,它简化了数据库操作,使得开发者可以像操作对象一样操作数据库。通过Hibernate,我们...

    Spring事务管理配置文件问题排查

    当出现像描述中那样的问题——SQL语句执行出错但事务未回滚时,我们需要深入理解Spring事务管理的配置和机制。以下是一些关键知识点: 1. **Spring事务管理类型**: - **编程式事务管理**:通过`...

    Spring的事务管理小案例

    在本文中,我们将深入探讨Spring框架中的事务管理。Spring是一个广泛应用的Java企业级应用开发框架,它提供...如果你想要深入了解,可以参考提供的博客链接或其他相关资料,进一步学习Spring事务管理的细节和最佳实践。

Global site tag (gtag.js) - Google Analytics