概述
了解Spring事务前 先要了解ACID(原子性,一致性,隔离性,持久性)这是可靠数据库所应具备的几个特性。
原子性: 网上买一件商品要执行两个操作,1,扣款。2、发货。 这两个要么都执行成功,要么都失败,不能没交钱就发货,也不能光交钱不发货,怎么都说不过去是吧。
一致性: 就是在一定的规则下你的数据要是完整的,比如银行开户,可能要往很多个表插入你的各种信息,其中一个表没有插入都会导致数据库自身校验规则的报错,如果你不想成为黑户,这时候应该报错调查原因。。。。
隔离性: 当我开启一个word,编辑一篇文章时,我就不能再删除这篇文章,因为他被隔离了,其他的事务不能修改他。同理数据库的一条数据需要保证一个事务对数据的修改不能影响其他事务,数据库有自己的机制去保证,会有比加锁效率高很多的办法。
持久性: 当数据入库后,不能再被回滚。就像嫁出去的闺女泼出去的水一样。You have no choice!
====================================================================
ok当你了解数据库的基本特性后,反观我们的程序,如果数据库爆出错误,或者程序爆出错误,导致违背了上述部分性质时,那么这样的数据是不能持久化到数据库中的。
=====================================================================
什么是事务:事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言书写的,事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。说白了事务就是执行一段或者多段sql的方法。
======================================================================
Spring事务原理
首先要明确:Spring提供了很多事务管理器,这些管理器分别将管理任务交给了JDBC,Hibernate,JTA,JPA等数据库连接持久化工具。
在package org.springframework.transaction;中 有接口 PlatformTransactionManager
它提供了三个方法:
- TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
- void commit(TransactionStatus status) throws TransactionException;
- void rollback(TransactionStatus status) throws TransactionException;
他们分别是
- 得到TransactionStatus对象
- 提交数据
- 回滚数据
在JDBC Hibernate JTA JPA中分别实现了这些方法(事务管理器)。做出自己针对性的操作。。
例如:下图是jdbc的包,其中datasource里的DataSourceTransactionManager就是JDBC的事务管理器。
-》
再例如:下面这个是Hibernate的包,这个HibernateTransactionManager.class就是hibernate的事务管理器。
-》
你需要在Spring中配置事务管理器,用来管理这个datasource连接池,如下所示:
<!-- 事务管理器配置 -->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Tomcat JDBC连接池 -->
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${${jdbc.dbtype}.jdbc.username}" />
<property name="password" value="${${jdbc.dbtype}.jdbc.password}" />
<property name="defaultAutoCommit" value="false" />
<!-- 可以从对象池中取出的对象最大个数,为0则表示没有限制,默认为100 -->
<property name="maxActive" value="${jdbc.pool.maxActive}" />
<property name="maxIdle" value="${jdbc.pool.maxIdle}" />
<!-- 最小空间连接数 一般与初始化连接数相等 默认10个 -->
<property name="minIdle" value="${jdbc.pool.minIdle}" />
<!-- 创建连接池时初始化连接数,默认10 -->
<property name="initialSize" value="${jdbc.pool.initialSize}"/>
<!-- 验证连接是否成功, SQL SELECT 指令至少要返回一行 -->
<property name="validationQuery" value="SELECT 1"/>
<!-- 验证间隔,避免额外验证,在此时间内若通过验证,则再次请求不会验证,默认30000 (30秒) -->
<property name="validationInterval" value="30000"/>
<!-- 空闲时是否进行验证,检查对象是否有效,默认为false -->
<property name="testWhileIdle" value="true"/>
<!-- 取得对象时是否进行验证,检查对象是否有效,默认为false -->
<property name="testOnBorrow" value="true"/>
<!-- 返回对象时是否进行验证,检查对象是否有效,默认为false -->
<property name="testOnReturn" value="true"/>
<!-- 多久检查一次空闲链接,并且验证空闲链接,不能设置小于1,默认5000 (5 秒) -->
<property name="timeBetweenEvictionRunsMillis" value="30000"/>
<!-- 无链接可用时最大等待秒数,超过时间会丟出错误信息 默认30000 (30 秒) -->
<property name="maxWait" value="10000"/>
</bean>
</beans>
===============================================================
如何使用添加事务的注解@Transactional
你可以将这个事务注解写在你需要的逻辑代码处,可以写全局
或者写类里面的方法中,局部调用处理事务
事务的属性
1、事务的传播行为(propagation behavior)
传播行为 | 含义 |
---|---|
PROPAGATION_REQUIRED | 表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务 |
PROPAGATION_SUPPORTS | 表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行 |
PROPAGATION_MANDATORY | 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常 |
PROPAGATION_REQUIRED_NEW | 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager |
PROPAGATION_NOT_SUPPORTED | 表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager |
PROPAGATION_NEVER | 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常 |
PROPAGATION_NESTED | 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务 |
2、事务的隔离级别(isolation level)
隔离级别 | 含义 |
---|---|
ISOLATION_DEFAULT | 使用后端数据库默认的隔离级别 |
ISOLATION_READ_UNCOMMITTED | 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读 |
ISOLATION_READ_COMMITTED | 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生 |
ISOLATION_REPEATABLE_READ | 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生 |
ISOLATION_SERIALIZABLE | 最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的 |
3、事务的只读
所谓的只读就是readOnly,也就是只能select 不能 insert update delete。
4、事务的超时
是一个定时器,当更新数据时间过长会自动回滚,以此保证数据库连接的可用性
5、事务的回滚
一般程序,发生sql执行错误,则执行回滚操作,数据不入库。
捕获异常,不作处理,数据库不会滚,数据入库。
捕获异常,并且抛出异常,数据库会回滚,数据不会入库
捕获异常,并且抛出新定义的异常Exception e,数据库不会回滚
所以:Spring事务管理是根据异常来进行回滚操作,具体遇到什么异常进行回滚,
可以采用默认的机制 遇到RuntimeException或者Error回滚,异常的继承结构:Throwable为基类,Error和Exception继承Throwable。Error和RuntimeException及其子类成为未检查异常(unchecked),其它异常成为已检查异常(checked)。
也可以自己进行配置。如果希望定义自己的已检查异常exception并回滚,参阅下面的示例“自定义异常进行回滚”
示例事务
@Transactional(
propagation=Propagation.REQUIRES_NEW,
isolation=Isolation.READ_COMMITTED,
noRollbackFor={UserAccountException.class},
readOnly=true,
timeout=3
)
对自定义异常进行回滚
@Transactional(rollbackFor=AException.class,noRollbackFor=BException.class)
public void insertUser(User user){
iTdao.insertUser(user);
}最后
以上就是高大曲奇为你收集整理的言简意赅的描述什么是事务 和 Spring事务处理 Spring事务原理 的全部内容,希望文章能够帮你解决言简意赅的描述什么是事务 和 Spring事务处理 Spring事务原理 所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复