什么是事务?
事务(Transaction),一般是指要做的或所做的事情,在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元.事务通常由高级数据库曹总语言或编程语言书写并用形式如begin transaction和end tranaction语句来界定,事务由事务开始和事务结束之间执行的全体操作组成
为什么要事务?
事务事务是为解决数据操作提出的,其实就是控制数据的安全访问
事务的四个特性
-
原子性: 事务是数据库逻辑工作单位,而且是必须是源自工作单位,对于其数据修改,要么全部执行,要不全不执行.
-
一致性: 事务在完成时,必须所有的数据都保持一直状态,在相关数据库中所有规则都必须应用于事务的修改,以保持所有数据的完整性.
-
隔离性: 一个事务的执行不能被其他事务所影响.
-
持久性: 一个事务一旦提交,事务的操作永久性的保存在DB中,几遍在数据库系统遇到故障的情况下也不会丢失提交事务的操作.
JDBC事务
在JDBC
中处理事务,都是通过Connection
完成的,同一事务中所有的操作,都在使用同一个Connection
对象.JDBC
事务默认是开启的,并且默认提交.
JDBC Connection
接口提供了两种事务模式:自动提交和手工提交
JDBC
中的事务java.sql.Connection
的三个方法与事务有关:
setAutoCommt(bolean): 设置是否自动提交事务,如果true(默认true)表示自动提交,也就是每条执行的SQL语句都是一个单独的事务,如果设置为false,需要手动提交事务.
commit(): 提交结束事务
rollback(): 回滚事务
传统JDBC操作流程:
(1) 获取JDBC连接
(2) 声明SQL
(3) 预编译SQL
(4) 执行SQL
(5) 处理结果集
(6) 释放结果集
(7) 释放Statement
(8) 提交事务
(9) 处理异常并回滚事务
(10) 释放JDBC连接
JDBC优缺点 :
1. 冗长,重复
2. 显示事务控制
3. 每个步骤不可获取
4. 显示处理检查异常
Spring容器事务
Spring事务管理器的实现由许多细节,如果对整个接口框架有个大体了解会非常有利于我们理解事务,下面通过讲解Spring的事务接口来了解Spring实现事务的具体策略.
Spring事务管理设计的接口及联系:
Spring并不直接管理事务,而是提供了多种事务管理器,他们讲事务管理的职责委托给Hibernate
或者JTA等JTA等持戒话机制所提供的的相关平台的事务来实现.Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager
,通过这个接口,Spring为各个平台如JDBC,Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了.
Public interface PlatformTransactionManager{
// 由TransactionDefinition得到TransactionStatus对象
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
// 提交
Void commit(TransactionStatus status) throws TransactionException;
// 回滚
Void rollback(TransactionStatus status) throws TransactionException;
}
1 Spring JDBC事务
如果应用程序中直接使用JDBC来进行持久化,
DataSource TransactionManager
会为你处理事务边界.为了使用DataSourceTransactionManager
,你需要使用如下的XML将其装配到应用程序的上下文定义中
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
2 Hibernate事务
如果应用程序的持久化是通过
Hibernate
实现的,那么你需要使用HibernateTranscationManager
.对于Hibernate3,
需要在Spring上下文中添加如下的声明:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
sessionFactory
属性需要装配一个Hibernate的session
工厂,HibernateTransactionManager
的实现细节是它将事务管理的职责委托给org.hibernate.Transaction
对象,而后者是从Hibernate Session
中获取到的。当事务成功完成时,HibernateTransactionManager
将会调用Transaction
对象的commit()
方法,反之,将会调用rollback()
方法。
3 Java持久API事务
Hibernate多年依赖一直是事实上的Java持久化标准,但是现在Java持久化API作为真正的Java持久化标准进入大家的视野.如果你计划使用JPA的话,那你需要使用Spring的JpaTransactionManager来处理事务,你需要在SpringH中这样的配置JpaTransactionManager:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
基本的事务属性的定义:
事务管理器接口PlatformTransactionManager通过getTransaction(TransactionDefinition definition)方法来得到事务,这个方法里面的参数是TransactionDefinition类,这个类就定义了一些基本的事务属性。
事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。
事务属性包含了5个方面:
传播行为、隔离规则、回滚规则、事务超时、是否只读
TransactionDefinition:
public interface TransactionDefinition { int getPropagationBehavior(); // 返回事务的传播行为 int getIsolationLevel(); // 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据 int getTimeout(); // 返回事务必须在多少秒内完成 boolean isReadOnly(); // 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的}
7种传播行为:
****PROPAGATION_REQUIRED:****如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
****PROPAGATION_SUPPORTS:****支持当前事务,如果当前没有事务,就以非事务方式执行。
****PROPAGATION_MANDATORY:****支持当前事务,如果当前没有事务,就抛出异常。
****PROPAGATION_REQUIRES_NEW:****新建事务,如果当前存在事务,把当前事务挂起。
****PROPAGATION_NOT_SUPPORTED:****以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
****PROPAGATION_NEVER:****以非事务方式执行,如果当前存在事务,则抛出异常。
虽然有7种,但是常用的就第一种REQUIRED和第四种REQUIRES_NEW
五个隔离级别:
****ISOLATION_DEFAULT:****这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
另外四个与JDBC的隔离级别相对应;
****ISOLATION_READ_UNCOMMITTED:****这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。
这种隔离级别会产生脏读,不可重复读和幻像读。
****ISOLATION_READ_COMMITTED:****保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
****ISOLATION_REPEATABLE_READ:****这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
****ISOLATION_SERIALIZABLE:****这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
除了防止脏读,不可重复读外,还避免了幻像读。
事务的属性可同通过注解方式或配置文件配置:
注解方式:
@Transactional只能被应用到public方法上,对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
默认情况下,一个有事务方法, 遇到RuntimeException 时会回滚 . 遇到 受检查的异常 是不会回滚 的. 要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常})
@Transactional( readOnly = false, //读写事务 timeout = -1 , //事务的超时时间,-1为无限制 noRollbackFor = ArithmeticException.class, //遇到指定的异常不回滚 isolation = Isolation.DEFAULT, //事务的隔离级别,此处使用后端数据库的默认隔离级别 propagation = Propagation.REQUIRED //事务的传播行为)
配置文件( aop拦截器方式):
<tx:advice id="advice" transaction-manager="txManager">
<tx:attributes>
<!-- tx:method的属性:
* name 是必须的,表示与事务属性关联的方法名(业务方法名),对切入点进行细化。通配符
(*)可以用来指定一批关联到相同的事务属性的方法。
如:'get*'、'handle*'、'on*Event'等等.
* propagation:不是必须的,默认值是REQUIRED表示事务传播行为,
包括REQUIRED,SUPPORTS,MANDATORY,REQUIRES_NEW,NOT_SUPPORTED,NEVER,NESTED
* isolation:不是必须的 默认值DEFAULT ,表示事务隔离级别(数据库的隔离级别)
* timeout:不是必须的 默认值-1(永不超时),表示事务超时的时间(以秒为单位)
* read-only:不是必须的 默认值false不是只读的表示事务是否只读?
* rollback-for: 不是必须的表示将被触发进行回滚的 Exception(s);以逗号分开。
如:'com.foo.MyBusinessException,ServletException'
* no-rollback-for:不是必须的表示不被触发进行回滚的 Exception(s),以逗号分开。
如:'com.foo.MyBusinessException,ServletException'
任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚
-->
<tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
<tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
<tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT" read-only="false" rollback-for="Exception"/>
<!-- 其他的方法之只读的 -->
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>