7.spring事务

        事务是一个完整的逻辑单元,在执行的时候要嘛同时成功,要嘛同时失败,中间不允许被中断,也就是说事务是一个全有或全无的过程。

事务拥有4个特性:

原子性:事务是由一个或者多个活动单元组成的。原子性确保了事务中所有操作全部发生或者全部不发生。如果所有活动都成功了,事务也就成功了。如果任意一个活动失败了,整个事务也就失败并回滚。

一致性:一旦事务完成(不管成功或者失败),事务保证业务处于一致的状态,数据不允许被破坏(所有活动要嘛成功一致,要嘛失败一致)。

隔离性:事务允许多个用户对相同数据进行操作,每个用户的操作不会与其他用户纠缠在一起。因此,事务会被隔离,避免发生同步读写数据的事情(隔离往往会涉及到锁定数据库的行或者表)

永久性:一旦事务完成,事务的结果应该被持久化,这样就能从任意的系统崩溃中恢复过来。

        Spring对编程式和声明式事务进行支持,编程式事务允许用户进行精确的事务控制,声明式(方法级别)以用户透明的形式对目标对象应用事务管理,无论采用何种方式,spring自己没有事务控制,而是提供了自己的事务管理器,将事务的职责委托给了其他的持久化平台进行实现,例如hibernate,JPA,JTA等等,对于在spring中使用事务,基本都可以不用关心持久化平台(框架)对事务的实现。

 

所有的事务管理器都实现了PlatformTransactionManager。

 

JDBC事务:

 

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource"></property>
</bean>

hibernate事务:

 

 

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory"></property>
</bean>

 注意:如果使用hibernate2.0,必须使用spring2.0用于集成,不然会出现错误

 

 

JPA事务:

 

<bean id="transactionManager3" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="emf"></property>
</bean>	

 让JPA事务支持高级特性:

 

 

<bean id="transactionManager3" class="org.springframework.orm.jpa.JpaTransactionManager">
	<property name="entityManagerFactory" ref="emf"></property>
	<property name="jpaDialect" ref="jpaDialect"></property>
</bean>	
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"></bean>

 这里配置了JpaDialect,JpaDialect支持使用特定的事务语义(例如用户自定义的事务隔离级别和事务超时),获取具备事务功能的Connection对象(暴露给基于JDBC的DAO),从 PersistenceExceptions 到Spring的 DataAccessExceptions 高级转化。

 

Spring编程式事务:

<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
	<property name="transactionManager" ref="transactionManager"></property>
</bean>

 

@Inject
private TransactionTemplate txTemplate;

public void test(){
	txTemplate.execute(new TransactionCallback<Void>() {
		@Override
		public Void doInTransaction(TransactionStatus status) {
			//do your business code
			return null;
		}
		
	});
}

 调用execute方法,构造匿名内部类,在doInTransaction方法中编写的代码就位于事务当中

 

Spring声明式事务:

        spring对声明式事务的支持是通过spring AOP实现的,在过去的日子里,spring采用TransactionProxyFacotyBean来代理需要进行事务的对象,进行声明式事务的管理,目前这种方式已经被淘汰,取而代之的是spring2.0之后的命名空间配置和@Transactional注解。

声明式事务通过事务属性来进行定义,通过配置事务属性来进行事务管理策略

以下是事务属性:

传播行为:定义了客户端与被调用方法之间的事务边界

传播行为含义
PROPAGATION_MANDATORY表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常
PROPAGATION_NESTED表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行,嵌套事务可以独立于当前事务进行单独的提交或者回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样,各厂商对其支持不同,参考文档是否支持嵌套事务
PROPAGATION_NEVER表示当前方法不应该运行在事务上下文中,如果当前有一个事务正在运行,则会抛出异常
PROPAGATION_NOT_SUPPORTED表示当前方法不应该运行在事务上下文当中,如果存在当前事务,该方法在运行期间,当前事务将会被挂起,如果使用JTATransactionManager的话,则需要访问TransactionManager
PROPAGATION_REQUIRED表示当前方法必须运行在事务当中,如果当前事务存在,方法会在当前事务中运行,否则,会启动一个新的事务
PROPAGATION_REQUIRES_NEW表示当前方法必须运行在它自己的事务当中,一个新的事务将会被启动,如果当前存在事务,在该方法运行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
PROPAGATION_SUPPORTS表示当前方法不需要事务上下文,但是存在当前事务,那么该方法会运行在当前事务当中

 

 隔离级别:定义事务与其他事务之间相互的影响程度

事务隔离级引发的现象:

脏读:一个事务改写了数据,但是没有提交,另外一个事务可以读到之前事务改写但是未提交的数据

不可重复读:一个事务针对某一个数据执行相同的两次查询,另外一个事务在此期间对该数据进行了修改和删除,那么之前的事务查询出来的两次结果会不同

幻读:一个事务针对某一个数据执行了相同的两次查询,另外一个事务在此期间对该数据进行了新增,那么之前的事务查询出来的第二次结果会出现新数据

理想状态下,两个事务之间是完全隔离的,但是完全隔离之后会造成性能问题(表和行锁),这叫造就了用户需要灵活的根据情况在程序中自定义隔离级别:

隔离级别含义
ISOLATION_DEFAULT使用后端数据库默认的隔离级别
ISOLATION_READ_UNCOMMITTED允许读取尚未提交的数据变更,可能会影响脏读,不可重读以及幻读
ISOLATION_READ_COMMITED允许读取并发事务中已经提交的数据,可以组织脏读,但是幻读和不可重复读仍有可能发生
ISOLATION_REPEATABLE_READ对同一字段的多次读取结果是一致的,除非是被本事务修改,可以组织脏读和不可重复读,但幻读仍有可能产生(因为幻读是新增操作)
ISOLATION_SERIALIZABLE完全服从ACID的隔离级别,确保阻止脏读,不可重复读,以及幻读,这是性能最慢的事务隔离级别,因为通常是完全锁定表来进行实现的

并不是所有的数据库都支持以上表格中的隔离级别,详细情况请参照数据库文档

 

只读:

只读是由后端的数据库进行的,数据库可以利用事务的只读操作进行特定的优化,只读优化只有在事务启动的时候由数据库实施的,所以配置PROPAGATION_NESTED,PROPAGATION_REQUIRES_NEW,PROPAGATION_REQUIRED才有意义。

 

事务超时:

为了使程序运行良好,事务不能占用太长时间,设置事务超时来管理事务。超时时钟会在事务启动的时候开始计时,所以只针对启动一个新事务的传播行为事务才有意义(PROPAGATION_NESTED,PROPAGATION_REQUIRES_NEW,PROPAGATION_REQUIRED

 

回滚规则:

定义了事务如果运行失败的回滚策略,默认情况事务只有遇到运行期异常的时候才会回滚,遇到检查期异常不会回滚,但是通过设置回滚规则可以自定义回滚的策略

 

在XML定义事务:

 增加命名空间配置:

 

xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation="http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
 
<tx:advice id="txAdvice">
	<tx:attributes>
		<tx:method name="save*" propagation="REQUIRED"/>
		<tx:method name="*" propagation="SUPPORTS" read-only="true" />
	</tx:attributes>
</tx:advice>
<aop:config>
	<aop:advisor advice-ref="txAdvice" pointcut="execution(* org.robbie.test.spring.beans.MyDao.*(..))"/>
</aop:config>
 配置事务通知txAdvice,这个通知会拦截以save开头的方法,并启动 REQUIRED 事务,其余的所有方法指定 SUPPORTS事务, 值得注意的是tx:method中定义的事务属性说明如下:

 

事务属性说明
isolation指定事务的隔离级别
propagation指定事务的传播行为
read-only指定事务为只读

rollback-for

no-rollback-for

rollback-for指定事务对于哪些检查异常应该回滚而不提交,no-rollbackfor-for指定事务对于哪些异常应该继续运行而不回滚
timeout指定超时时间

 

基于注解的事务配置:

<tx:annotation-driven/>

 

@Repository
@Transactional
public class MyService{
    
    @Transactional
    public void saveObject(){

    }

}

在XML上增加<tx:annotation-driven/> 需要指定事务管理器,本例中默认不配会引用id为transactionManager的事务管理器,如果spring配置中没有id为transacManager的事务管理器,需要手动指定transaction-manager属性。 在需要事务的类或者方法上标注@Transactional。配置上注解的类或者方法就被spring事务管理器管理了

 

关于JTA的配置,JTA通常是通过第三方厂商实现的,需要配置分布式的数据源,已经JTA的事务管理器,配置完成之后能够跨数据源进行事务提交和回滚,具体详细配置可以参见其他技术文档。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值