一、Spring事务 的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。
对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行:
1. 获取连接 Connection con = DriverManager.getConnection()
2.开启事务con.setAutoCommit(true/false);
3.执行CRUD (
增删改查
)
4. 提交事务/回滚事务 con.commit() / con.rollback();
5.关闭连接 conn.close();
使用Spring的事务管理功能后,我们可以不再写步骤 2 和 4 的代码,而是由Spirng 自动完成。 那么Spring是如何在我们书写的 CRUD 之前和之后开启事务和关闭事务的呢?解决这个问题,也就可以从整体上理解Spring的事务管理实现原理了。下面简单地介绍下,注解方式为例子
配置文件开启注解驱动,在相关的类和方法上通过注解@
Transactional
标识。
spring 在启动的时候会去解析生成相关的bean,这时候会查看拥有相关注解的类和方法,并且为这些类和方法生成代理,并根据@Transaction的相关参数进行相关配置注入,这样就在代理中为我们把相关的事务处理掉了(开启正常提交事务,异常回滚事务)。
真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。
事务: 将若干的数据库操作作为一个整体控制,一起成功或一起失败,没有中间状态。
原子性
:指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性
:指事务前后数据的完整性必须保持一致。
隔离性
:指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要相互隔离。
持久性
:指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,即时数据库发生故障也不应该对其有任何影响。
-
TransactionDefinition
事务定义信息(隔离、传播、超时、只读)
脏读:一个事务读取了另一个事务改写但还未提交的数据,如果这些数据被回滚,则读到的数据是无效的。
不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同。
幻读:一个事务读取了几行记录后,另一个事务插入一些记录,幻读就发生了。再后来的查询中,第一个事务就会发现有些原来没有的记录。
二
、
事务隔离(
isolation
)级别
:(五种)
- 默认 DEFAULT--使用后端数据库默认的隔离级别(Spring中的选择项)
- 读未提交 READ_UNCOMMITED--允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读
- 读已提交 READ_COMMITTED--允许在并发事务已经提交后读取。可防止脏读,但幻读和不可重复读仍可发生
- 可重复读 REPEATABLE_READ--对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生
- 可序列化 SERIALIZABLE--完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的
总结:
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
大多数的数据库默认隔离级别为 Read Commited,比如 SqlServer、Oracle
少数数据库默认隔离级别为:Repeatable Read 比如: MySQL InnoDB,MySQL默认采用REPEATABLE_READ隔离级别;Oracle默认采用READ_COMMITTED隔离级别
三
、
Spring 事务的传播属性
所谓spring事务的传播属性,就是定义在
有多个事务同时存在
的时候,spring应该如何处理这些事务的行为。这些属性在TransactionDefinition(
事务定义
)中定义,具体常量的解释见下表:
事务传播(
propagation
)行为:(七种)
常量名称 常量解释
- required --支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
- supports --支持当前事务,如果当前没有事务,就以非事务方式执行。
- mandatory --支持当前事务,如果当前没有事务,就抛出异常。
- requires_new --新建事务,如果当前存在事务,把当前事务挂起。
- not_supported --以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- never--以非事务方式执行,如果当前存在事务,则抛出异常。
- nested --如果当前存在活动的事务,则在嵌套事务内执行。如果当前没有活动事务,则进行与required类似的操作。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点,内部回滚不会对外部事务产生影响。只对DataSourceTransactionManager管理器有效
![](https://i-blog.csdnimg.cn/blog_migrate/f4d445ffc34d8a68f16ee46095609351.png)
总结如下:
Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。
DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用
hibernate
进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。
五、Spring事务管理的四种方式(以银行转账为例)点击打开链接
六、总结
对于项目中需要使用到事务的地方,我建议开发者还是使用spring的TransactionCallback接口来实现事务,不要盲目使用spring事务注解,如果一定要使用注解,那么一定要对spring事务的传播机制和隔离级别有个详细的了解,否则很可能发生意想不到的效果。