事务详解
2. 事务管理
2.1 回顾事务
什么是事务?
在数据库开发中,一组业务逻辑操作,要么全部成功,要么全部失败。
事务有什么特定?ACID
原子性:整体,原子不可分割的。整个操作被看成一个整体,要么成功,要么失败。
一致性:数据,事务操作的前后数据一致。
隔离性:并发,两个事务之间并发访问情况。
持久性:结果,事务一旦提交,不能回滚。
隔离有什么问题?
脏读:一个事务读到了另一个事务没有提交的数据。
不可重复读:一个事务读到了另一个事务已有提交的数据(update)。
幻读:一个事务读到了另一个事务已有提交的数据(insert)。
隔离级别有那些?
读未提交:存在3个问题(脏读、不可重复读、幻读)
读已提交:解决1个问题(脏读),存在2个问题(不可重复读、幻读)
可重复读:解决2个问题(脏读、不可重复读)、存在1个问题(幻读)
串行化:解决3个问题(脏读、不可重复读、幻读)–单事务
2.2 事务详解
研究Spring事务,需要学习事务管理平台管理器: PlatformTransactionManager
在平台管理器中,通过 事务的定义 获得事务,从而进行事务提交或回滚操作。
事务定义 TransactionDefinition 的详解:

传播行为:一个事务调用另一个事务,事务共享问题。
PROPAGATION_REQUIRED,required:支持当前事务,如果没有事务,创建一个新的。
A 有事务,B使用A的事务。(支持当前事务)
A没有事务,B创建新的。()
PROPAGATION_SUPPORTS,supports:支持当前事务,如果没有事务,以非事务执行。
A 有事务,B使用A的事务。(支持当前事务)
A没有事务,B以非事务执行。
PROPAGATION_MANDATORY,mandatory:支持当前事务,如果没有事务,抛异常
A 有事务,B使用A的事务。(支持当前事务)
A没有事务,B抛异常。
PROPAGATION_REQUIRES_NEW,requires_new:创建一个新事物,如果当前有事务,将挂起。
A 有事务,B创建新事务,同时挂起A事务。
A 没有事务,B创建新事务。
PROPAGATION_NOT_SUPPORTED, not_supported:不支持当前事务,以非事务执行,如果有挂起
A 有事务,B以非事务执行,同时挂起A事务。
A 没有事务,B以非事务执行。
PROPAGATION_NEVER, never:不支持当前事务,如果有抛异常。
A 有事务,B抛异常
A 没有事务,B以非事务执行。
PROPAGATION_NESTED, nested :嵌套事务,底层使用 savepoint 进行嵌套事务操作。
保存点允许回顾部分事务。
相关源码:
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/packageorg.springframework.transaction;importjava.sql.Connection;/** * Interface that defines Spring-compliant transaction properties. * Based on the propagation behavior definitions analogous to EJB CMT attributes. * *
Note that isolation level and timeout settings will not get applied unless * an actual new transaction gets started. As only {@link#PROPAGATION_REQUIRED}, * {@link#PROPAGATION_REQUIRES_NEW} and {@link#PROPAGATION_NESTED} can cause * that, it usually doesn't make sense to specify those settings in other cases. * Furthermore, be aware that not all transaction managers will support those * advanced features and thus might throw corresponding exceptions when given * non-default values. * *
The {@link#isReadOnly() read-only flag} applies to any transaction context, * whether backed by an actual resource transaction or operating non-transactionally * at the resource level. In the latter case, the flag will only apply to managed * resources within the application, such as a Hibernate {@codeSession}. * *@authorJuergen Hoeller *@since08.05.2003 *@seePlatformTransactionManager#getTransaction(TransactionDefinition) *@seeorg.springframework.transaction.support.DefaultTransactionDefinition *@seeorg.springframework.transaction.interceptor.TransactionAttribute */publicinterfaceTransactionDefinition{/**
* Support a current transaction; create a new one if none exists.
* Analogous to the EJB transaction attribute of the same name.
* <p>This is typically the default setting of a transaction definition,
* and typically defines a transaction synchronization scope.
*/intPROPAGATION_REQUIRED =0;/** * Support a current transaction; execute non-transactionally if none exists. * Analogous to the EJB transaction attribute of the same name. *
NOTE: For transaction managers with transaction synchronization, * {@codePROPAGATION_SUPPORTS} is slightly different from no transaction * at all, as it defines a transaction scope that synchronization might apply to. * As a consequence, the same resources (a JDBC {@codeConnection}, a * Hibernate {@codeSession}, etc) will be shared for the entire specified * scope. Note that the exact behavior depends on the actual synchronization * configuration of the transaction manager! *
In general, use {@codePROPAGATION_SUPPORTS} with care! In particular, do * not rely on {@codePROPAGATION_REQUIRED} or {@codePROPAGATION_REQUIRES_NEW} * within a {@codePROPAGATION_SUPPORTS} scope (which may lead to * synchronization conflicts at runtime). If such nesting is unavoidable, make sure * to configure your transaction manager appropriately (typically switching to * "synchronization on actual transaction"). *@seeorg.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization *@seeorg.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION */intPROPAGATION_SUPPORTS =1;/** * Support a current transaction; throw an exception if no current transaction * exists. Analogous to the EJB transaction attribute of the same name. *
Note that transaction synchronization within a {@codePROPAGATION_MANDATORY} * scope will always be driven by the surrounding transaction. */intPROPAGATION_MANDATORY =2;/** * Create a new transaction, suspending the current transaction if one exists. * Analogous to the EJB transaction attribute of the same name. *
NOTE: Actual transaction suspension will not work out-of-the-box * on all transaction managers. This in particular applies to * {@linkorg.springframework.transaction.jta.JtaTransactionManager}, * which requires the {@codejavax.transaction.TransactionManager} to be * made available it to it (which is server-specific in standard Java EE). *
A {@codePROPAGATION_REQUIRES_NEW} scope always defines its own * transaction synchronizations. Existing synchronizations will be suspended * and resumed appropriately. *@seeorg.springframework.transaction.jta.JtaTransactionManager#setTransactionManager */intPROPAGATION_REQUIRES_NEW =3;/** * Do not support a current transaction; rather always execute non-transactionally. * Analogous to the EJB transaction attribute of the same name. *
NOTE: Actual transaction suspension will not work out-of-the-box * on all transaction managers. This in particular applies to * {@linkorg.springframework.transaction.jta.JtaTransactionManager}, * which requires the {@codejavax.transaction.TransactionManager} to be * made available it to it (which is server-specific in standard Java EE). *
Note that transaction synchronization is not available within a * {@codePROPAGATION_NOT_SUPPORTED} scope. Existing synchronizations * will be suspended and resumed appropriately. *@seeorg.springframework.transaction.jta.JtaTransactionManager#setTransactionManager */intPROPAGATION_NOT_SUPPORTED =4;/** * Do not support a current transaction; throw an exception if a current transaction * exists. Analogous to the EJB transaction attribute of the same name. *
Note that transaction synchronization is not available within a * {@codePROPAGATION_NEVER} scope. */intPROPAGATION_NEVER =5;/** * Execute within a nested transaction if a current transaction exists, * behave like {@link#PROPAGATION_REQUIRED} else. There is no analogous * feature in EJB. *
NOTE: Actual creation of a nested transaction will only work on * specific transaction managers. Out of the box, this only applies to the JDBC * {@linkorg.springframework.jdbc.datasource.DataSourceTransactionManager} * when working on a JDBC 3.0 driver. Some JTA providers might support * nested transactions as well. *@seeorg.springframework.jdbc.datasource.DataSourceTransactionManager */intPROPAGATION_NESTED =6;/** * Use the default isolation level of the underlying datastore. * All other levels correspond to the JDBC isolation levels. *@seejava.sql.Connection */intISOLATION_DEFAULT = -1;/** * Indicates that dirty reads, non-repeatable reads and phantom reads * can occur. *
This level allows a row changed by one transaction to be read by another * transaction before any changes in that row have been committed (a "dirty read"). * If any of the changes are rolled back, the second transaction will have * retrieved an invalid row. *@seejava.sql.Connection#TRANSACTION_READ_UNCOMMITTED */intISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;/** * Indicates that dirty reads are prevented; non-repeatable reads and * phantom reads can occur. *
This level only prohibits a transaction from reading a row * with uncommitted changes in it. *@seejava.sql.Connection#TRANSACTION_READ_COMMITTED */intISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;/** * Indicates that dirty reads and non-repeatable reads are prevented; * phantom reads can occur. *
This level prohibits a transaction from reading a row with uncommitted changes * in it, and it also prohibits the situation where one transaction reads a row, * a second transaction alters the row, and the first transaction re-reads the row, * getting different values the second time (a "non-repeatable read"). *@seejava.sql.Connection#TRANSACTION_REPEATABLE_READ */intISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;/** * Indicates that dirty reads, non-repeatable reads and phantom reads * are prevented. *
This level includes the prohibitions in {@link#ISOLATION_REPEATABLE_READ} * and further prohibits the situation where one transaction reads all rows that * satisfy a {@codeWHERE} condition, a second transaction inserts a row * that satisfies that {@codeWHERE} condition, and the first transaction * re-reads for the same condition, retrieving the additional "phantom" row * in the second read. *@seejava.sql.Connection#TRANSACTION_SERIALIZABLE */intISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;/**
* Use the default timeout of the underlying transaction system,
* or none if timeouts are not supported.
*/intTIMEOUT_DEFAULT = -1;/** * Return the propagation behavior. *
Must return one of the {@codePROPAGATION_XXX} constants * defined on {@linkTransactionDefinition this interface}. *@returnthe propagation behavior *@see#PROPAGATION_REQUIRED *@seeorg.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive() */intgetPropagationBehavior();/** * Return the isolation level. *
Must return one of the {@codeISOLATION_XXX} constants * defined on {@linkTransactionDefinition this interface}. *
Only makes sense in combination with {@link#PROPAGATION_REQUIRED} * or {@link#PROPAGATION_REQUIRES_NEW}. *
Note that a transaction manager that does not support custom isolation levels * will throw an exception when given any other level than {@link#ISOLATION_DEFAULT}. *@returnthe isolation level */intgetIsolationLevel();/** * Return the transaction timeout. *
Must return a number of seconds, or {@link#TIMEOUT_DEFAULT}. *
Only makes sense in combination with {@link#PROPAGATION_REQUIRED} * or {@link#PROPAGATION_REQUIRES_NEW}. *
Note that a transaction manager that does not support timeouts will throw * an exception when given any other timeout than {@link#TIMEOUT_DEFAULT}. *@returnthe transaction timeout */intgetTimeout();/** * Return whether to optimize as a read-only transaction. *
The read-only flag applies to any transaction context, whether * backed by an actual resource transaction * ({@link#PROPAGATION_REQUIRED}/{@link#PROPAGATION_REQUIRES_NEW}) or * operating non-transactionally at the resource level * ({@link#PROPAGATION_SUPPORTS}). In the latter case, the flag will * only apply to managed resources within the application, such as a * Hibernate {@codeSession}. << *
This just serves as a hint for the actual transaction subsystem; * it will not necessarily cause failure of write access attempts. * A transaction manager which cannot interpret the read-only hint will * not throw an exception when asked for a read-only transaction. *@return{@codetrue} if the transaction is to be optimized as read-only *@seeorg.springframework.transaction.support.TransactionSynchronization#beforeCommit(boolean) *@seeorg.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly() */booleanisReadOnly();/** * Return the name of this transaction. Can be {@codenull}. *
This will be used as the transaction name to be shown in a * transaction monitor, if applicable (for example, WebLogic's). *
In case of Spring's declarative transactions, the exposed name will be * the {@codefully-qualified class name + "." + method name} (by default). *@returnthe name of this transaction *@seeorg.springframework.transaction.interceptor.TransactionAspectSupport *@seeorg.springframework.transaction.support.TransactionSynchronizationManager#getCurrentTransactionName() */StringgetName();}
网友评论