Introduction
事务是什么?
事务的作用
- 事务的特性
- Atomic原子性、Consistency一致性、Isolation隔离性和Durability持久性。
- 原子性:指整个事务是不可以分割的工作单元。只有事务中所有的操作执行成功,才算整个事务成功,事务中任何一个SQL语句执行失败,那么已经执行成功的SQL语句也必须撤销,数据库状态应该回到执行事务前的状态。
- 一致性:指数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。例如对于银行转账事务,不管事务成功还是失败,应该保证事务结束后两个转账账户的存款总额是与转账前一致的。
- 隔离性:指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。
- 持久性:指的是只要事务成功结束它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。
BEGIN; COMMIT;
- 使用场景
简单举个例子就是你要同时修改数据库中两个不同表的时候,如果它们不是一个事务的话,当第一个表修改完,可是第二表改修出现了异常而没能修改的情况下,就只有第二个表回到未修改之前的状态,而第一个表已经被修改完毕。
jdbc处理事务的方法
- example
try{ Connection conn = getConnection(); // 不管如何我们得到了链接 conn.setAutoCommit(false); // 插入订单 // 修改库存 conn.commit(); // 成功的情况下,提交更新。 } catch(SQLException ex) { conn.rollback(); // 失败的情况下,回滚所有的操作 } finally { conn.close(); }
- 优点
简单、直观 - 缺点
- 代码罗嗦
- 多个连接时,处理起来更罗嗦
现有系统中,对事务的处理
- 取出 ExecutorType.BATCH的session
- 一次传入多个sqlId,
public static int[] batchUpdate(String sqlId, List<?> objList) { int[] idArr = new int[objList.size()]; SqlSession session = null; try { session = sqlSessionFactory.openSession(ExecutorType.BATCH); int index = 0; for (Object obj : objList) { idArr[index++] = session.update(sqlId, obj); } session.commit(); } catch (Exception e) { logger.warn("batch update error:" + sqlId, e); e.printStackTrace(); } finally { if (session != null) { session.close(); } } return idArr; }
- 缺点
- 直接操作sqlId,service 和 dao不好分层
- 不支持update 和 select、insert交叉的情况
- 不能简单的支持跨db操作
spring里对事务的支持
spring为多种不同类型的事务管理机制提供统一编程模型,简化了对事务的使用。
spring处理事务的结构
Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。
- DataSource
数据库连接源 - TransactionManager
Spring的事务管理通过org.springframework.transaction.PlatformactionManager接口完成.PlatformTransactionManager是一个服务提供商接口(SPI),针对不同类型的底层事务框架,Spring提供了不同的PlatFormTransactionManager实现版本
接口定义如下public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }
- 代理机制
用代理类来替代你真实操作db的方法
spring配置事务的方法
Spring里对事务的使用
这里只介绍使用@Transactional注解的方法
简单的来说,只需要在DAO或者Service的类或者方法加上@Transactional的注解。 譬如
@Transactional public class TransactionShowCaseService extends BaseService { public int insertWithoutException(User record) { return userMapper.insert(record); } }
查看代码 testTransactionAdd() 和 testTransactionAddThrowException()
testTransactionMethod() 和 testNoTransactionMethod()
查看代码testNotSupportTransAction()
实现方法
AOP,在注解的方法完成之后,调用commit;
查看 代码 testTransactionWithSleep(),等事务完成之后,最后才提交.数据库记录为
[searcher b2c_product [unknown] 192.168.10.65 2014-03-29 15:13:31.009 CST]LOG: execute S_1: BEGIN [searcher b2c_product [unknown] 192.168.10.65 2014-03-29 15:13:31.011 CST]LOG: execute <unnamed>: INSERT INTO testUser (id,userName,phone) VALUES ($1,$2,$3) [searcher b2c_product [unknown] 192.168.10.65 2014-03-29 15:13:31.011 CST]DETAIL: parameters: $1 = '3033', $2 = NULL, $3 = '2123' [searcher b2c_product [unknown] 192.168.10.65 2014-03-29 15:13:41.022 CST]LOG: execute S_2: COMMIT
系统中曾出现的问题:
在事务里,先更新订单状态,然后调用外部接口。由于外部接口看不到这个事务里的修改,发现订单状态错误,于是报错
spring事务行为
传播行为定义了调用方法之间的事务边界。传播规则回答了这样的问题:新的时候应该被启动,还是挂起? 方法是否要在事务环境中运行
PROPAGATION_REQUIRED
当前事务必须出现在事务中,如果有则使用原来的session。否则,创建一个新的.
– 默认的行为
PROPAGATION_NOT_SUPPORT
不应该运行在事务中,如果当前存在事务,那么在该方法运行期间,事务被挂起。
查看代码 testNotSupportTransAction()
猜测 testNotSupport 的运行结果
DEBUG java.sql.Connection 2014-04-03 12:19:54 - ooo Connection Opened DEBUG java.sql.PreparedStatement 2014-04-03 12:19:54 - ==> Executing: INSERT INTO testUser (id,userName,phone) VALUES (?,?,?) DEBUG java.sql.PreparedStatement 2014-04-03 12:19:54 - ==> Parameters: 4154(Integer), null, 2123(String) DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager 2014-04-03 12:19:54 - Suspending current transaction DEBUG org.springframework.jdbc.datasource.DataSourceUtils 2014-04-03 12:19:54 - Fetching JDBC Connection from DataSource DEBUG org.springframework.jdbc.datasource.DataSourceUtils 2014-04-03 12:19:54 - Registering transaction synchronization for JDBC Connection DEBUG java.sql.Connection 2014-04-03 12:19:54 - ooo Connection Opened DEBUG java.sql.PreparedStatement 2014-04-03 12:19:54 - ==> Executing: SELECT id, userName, phone FROM testUser WHERE id = ? DEBUG java.sql.PreparedStatement 2014-04-03 12:19:54 - ==> Parameters: 4154(Integer) DEBUG org.springframework.jdbc.datasource.DataSourceUtils 2014-04-03 12:19:54 - Returning JDBC Connection to DataSource DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager 2014-04-03 12:19:54 - Resuming suspended transaction after completion of inner transaction DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager 2014-04-03 12:19:54 - Initiating transaction commit
Propagation.MANDATORY
如果上下文不在事务中,则抛出异常。
运行代码 testErrorMandatory() , testOkMandatory()
Propagation_NEVER
不应该出现在事务上下文中,如果出现在上下文中,则抛出异常
testNever
Propagation_requires_new
必须运行在自己的事务中。如果已经存在事务,则当前事务会被挂起,自己另起一个事务
Propagation_supports
不需要上下文,但是如果存在当前的事务,那么这个方法会在这个事务中进行
Propagation.NEST
如果存在一个事务,则单独起一个嵌套的事务,对事物单独的提交。如果没有起事务,就启动一个新的事务. 貌似比较少见。。。。。看不太明白. 具体请参考 http://ahujyy.iteye.com/blog/1544304
运行代码 testNest()
DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager 2014-04-03 11:44:16 - Switching JDBC Connection [DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager 2014-04-03 11:44:16 - Participating in existing transaction DEBUG java.sql.Connection 2014-04-03 11:44:16 - ooo Connection Opened DEBUG java.sql.PreparedStatement 2014-04-03 11:44:16 - ==> Executing: INSERT INTO testUser (id,userName,phone) VALUES (?,?,?) DEBUG java.sql.PreparedStatement 2014-04-03 11:44:16 - ==> Parameters: 6238(Integer), null, 2123(String) DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager 2014-DEBUG java.sql.PreparedStatement 2014-04-03 11:44:16 - ==> Executing: INSERT INTO testUser (id,userName,phone) VALUES (?,?,?) DEBUG java.sql.PreparedStatement 2014-04-03 11:44:16 - ==> Parameters: 6238(Integer), null, 2123(String) DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager 2014-04-03 11:44:16 - Releasing transaction savepoint DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager 2014-04-03 11:44:16 - Initiating transaction commit DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager 2014-0DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager 2014-0DEBUG org.springframework.jdbc.datasource.DataSourceUtils 2014-04-03 11:44:16 - Returning JDBC Connection to DataSource
回滚的策略
异常分类
- checked异常
表示无效,不是程序中可以预测的。比如无效的用户输入,文件不存在,网络或者数据库链接错误。这些都是外在的原因,都不是程序内部可以控制的。
必须在代码中显式地处理。比如try-catch块处理,或者给所在的方法加上throws说明,将异常抛到调用栈的上一层。
继承自java.lang.Exception(java.lang.RuntimeException除外)。熟悉的checked 异常包括
Java.lang.ClassNotFoundException
Java.lang.NoSuchMetodException
java.io.IOException - unchecked异常
表示错误,程序的逻辑错误。是RuntimeException的子类,比如IllegalArgumentException, NullPointerException和IllegalStateException。
不需要在代码中显式地捕获unchecked异常做处理。
继承自java.lang.RuntimeException(而java.lang.RuntimeException继承自java.lang.Exception)。
- Error
当程序发生不可控的错误时,通常做法是通知用户并中止程序的执行。与异常不同的是Error及其子类的对象不应被抛出。
Error是throwable的子类,代表编译时间和系统错误,用于指示合理的应用程序不应该试图捕获的严重问题。
Error由Java虚拟机生成并抛出,包括动态链接失败,虚拟机错误等。程序对其不做处理。
回滚策略
Spring的事务管理默认只对出现unchecked excpetion (java.lang.RuntimeException及其子类)进行回滚。
如果一个方法抛出Exception或者Checked异常,Spring事务管理默认不进行回滚
查看代码 testTransactionAddThrowError() 以及 testThrowException()
配置回滚策略
- rollbackFor
- noRollbackFor
提问,如果是子类,是否会回滚? 查看 testNoRollback() 和 testRollback()
超时
在达到超时时间之后,事务自动回滚. — 这个貌似有问题。稍后补充
看代码testTimeout()。 这个代码不会回滚
@Transactional(timeout = 3, propagation = Propagation.REQUIRED) public void insertTimeout(User record) { userMapper.insert(record); try { Thread.sleep(4000); } catch (Exception e) { e.printStackTrace(); } userMapper.insert(record); }
只读
数据库可能可以针对这个只读的事务做优化。
在只读业务里,更新操作会有异常.
事务的隔离性
多数据源+ 事务
代码 testInsertTwoDb(), 和 testInsertTwoUserReqireNew()
atomikos
http://iteye.blog.163.com/blog/static/1863080962012102945116222/
结论 && Future works
- 在spring里,事务比较强大。
- 还需要研究 事务的隔离性 、 timeout的具体用法
- 编程式事务也需要进一步研究
- 多数据源情况下,事务的使用
随意记录
- 如果想要使用@Transaction标注,必须在ApplicationContext里加上
<!-- 事务管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 使用annotation定义事务 --> <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
- 输出JDBC相关操作的日志配置
<logger name="org.springframework" level="WARN" > </logger> <logger name="org.springframework.jdbc" level="DEBUG"/> <logger name="org.springframework.transaction" level="DEBUG"/> <logger name="java.sql" level="DEBUG" />
输出的日志文件类似于
DEBUG java.sql.Connection 2014-03-29 23:32:19 - ooo Connection Opened DEBUG java.sql.PreparedStatement 2014-03-29 23:32:19 - ==> Executing: INSERT INTO testUser (id,userName,phone) VALUES (?,?,?) DEBUG java.sql.PreparedStatement 2014-03-29 23:32:19 - ==> Parameters: 8983(Integer), null, 2123(String) DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager 2014-03-29 23:32:29 - Initiating transaction commit DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager 2014-0DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager 2014-0
附录
- http://blog.csdn.net/roroyangivan/article/details/7083385
- spring事务控制 http://www.cnblogs.com/ysxlin/archive/2008/06/06/1215300.html
- 异常的分类 http://woshixy.blog.51cto.com/5637578/1071966
- spring分布式事务 http://blog.chinaunix.net/uid-21162795-id-3424973.html 和http://iteye.blog.163.com/blog/static/1863080962012102945116222/
相关推荐
### Spring事务与数据库操作 #### 一、Spring的声明式事务管理 在现代软件开发中,事务处理是非常关键的一部分,特别是在涉及多个数据操作时。Spring框架提供了强大的事务管理能力,可以方便地集成到应用程序中。...
Spring事务管理的目的是确保数据的一致性和完整性,尤其是在多操作、多资源的环境中。本Demo将深入探讨Spring如何实现事务的管理。 首先,Spring提供了两种主要的事务管理方式:编程式事务管理和声明式事务管理。 ...
Spring事务管理是Spring框架的核心特性之一,主要用于处理应用程序中的数据一致性问题。在Spring中,事务管理分为编程式和声明式两种方式。本篇文章将详细解释Spring事务管理的流程,以及如何通过时序图来理解这一...
Spring事务原理和配置 Spring事务原理是指Spring框架中的一种机制,用于管理事务,并提供了多种配置方式。事务是指一系列的操作,作为一个整体执行,如果其中某个操作失败,整个事务将回滚。Spring事务原理围绕着两...
本资源包提供了进行Spring事务管理开发所需的所有关键库,包括框架基础、核心组件、AOP(面向切面编程)支持、日志处理、编译工具以及与数据库交互的相关jar包。下面将对这些知识点进行详细解释: 1. **Spring框架*...
本主题将深入探讨“Spring事务案例分析.zip”中的关键知识点,包括Spring事务管理及其在实际项目中的应用。 首先,我们来了解什么是Spring事务管理。在分布式系统或数据库操作中,事务管理是确保数据一致性和完整性...
在Spring框架中,事务管理是核心特性之一,它允许开发者以声明式或编程式的方式处理事务。本示例“spring 事务传播 demo”将聚焦于Spring的事务传播行为,这是在多个方法调用中控制事务边界的关键概念。下面我们将...
这个名为"Spring事务小demo"的项目提供了一个实践示例,帮助开发者了解Spring事务处理的基本概念和用法。 首先,Spring事务管理是Spring框架的核心特性之一,它允许我们以声明式或编程式的方式管理事务。声明式事务...
本文将深入探讨在Spring框架中如何管理事务,以“Spring 事务简单完整例子”为出发点,结合标签“spring,事务,jdbc事务”,我们将详细解释Spring事务管理的原理和实践。 首先,Spring提供了两种事务管理方式:编程...
### Spring中事务的传播属性详解 #### 一、引言 在使用Spring框架进行应用程序开发时,事务管理是一项非常重要的特性。Spring提供了两种事务管理方式:编程式事务管理和声明式事务管理。其中,声明式事务管理因其...
标题“Spring事务管理失效原因汇总”指出了本文的核心内容是分析在使用Spring框架进行事务管理时可能遇到的问题及其原因。描述部分进一步说明了事务失效的后果往往不明显,容易在测试环节被忽略,但在生产环境中出现...
本篇将深入探讨Spring事务管理的核心概念、工作原理以及如何使用`spring-tx-3.2.0.RELEASE.jar`这个jar包。 首先,我们需要理解什么是事务。在数据库系统中,事务是一组操作,这些操作被视为一个整体,要么全部完成...
本文将深入探讨在"spring事务操作试验"中涉及的关键知识点,并结合提供的资源进行详细阐述。 首先,Spring事务管理的核心概念是ACID(原子性、一致性、隔离性和持久性),这是所有事务系统的基础。在Spring中,事务...
Spring事务详细讲解 在 Spring 框架中,事务管理扮演着非常重要的角色。Spring 声明式事务让我们从复杂的事务处理中得到解脱,使得我们再也无需要去处理获得连接、关闭连接、事务提交和回滚等这些操作。再也无需要...
实验 "Spring 声明事务" 是 Java 高级编程中的一个重要环节,旨在让学生掌握 Spring 框架中声明式事务管理的配置和使用。在实际应用中,事务管理是确保数据一致性、完整性和可靠性的关键组件。Spring 提供了声明式...
Spring事务机制是Java开发中非常重要的一个概念,它在企业级应用中扮演着核心角色,确保数据的一致性和完整性。Spring提供了多种事务管理方式,包括编程式事务管理和声明式事务管理。在这篇DEMO中,我们将重点探讨...
本文将深入探讨Spring事务管理的源码,理解其背后的实现机制。 首先,Spring事务管理有两种主要模式:编程式事务管理和声明式事务管理。编程式事务管理通过调用`PlatformTransactionManager`接口提供的方法进行显式...
spring事务的底层实现流程图 spring事务的底层实现流程图 spring事务的底层实现流程图 spring事务的底层实现流程图 spring事务的底层实现流程图 spring事务的底层实现流程图 spring事务的底层实现流程图 spring事务...
Spring事务操作示例(四种方式),包含完整代码和数据库文件(基于MySQL,在项目sql文件夹中),可运行,学习Spring事务详见博客:http://blog.csdn.net/daijin888888/article/details/51822257