`

spring日记(七):声明式事务机制

阅读更多

数据库事务必须满足四个特性:

*  原子性(Atomic):表示一个事务的多个数据库操作时一个整体,要么都成功提交,要么都撤销

*  一致性(Consistency):事务操作成功后,数据库状态和它的业务状态一致,数据不会被破坏

*  隔离性(Isolation):在并发数据操作时,不同事务拥有各自的数据空间,它们的操作彼此不影响。数据库有多种隔离级别,隔离级别越高,数据越安全

*  持久性(Durability):一旦事务提交后,所有数据操作都必须被持久化到数据库中,即使事务提交后,数据库马上崩溃,在重启时,也必须保证能通过某种机制恢复。

幻读是指读到了其他已经提交事务的新增数据(insert),而不可重复读是指读到其他已经提交事务的更改数据(update或者delete)

>> spring的事务管理器实现类

spring将事务管理委托给底层具体的持久化实现框架完成。因此,spring为不同的持久化框架提供了PlatformTransactionManager接口的实现类:

org.springframework.orm.jpa.JpaTransactionManager:使用JPA进行持久化

org.springframework.orm.hibernate3.HibernateTransactionManager:使用Hibernate3.0版本进行持久化

org.springframework.orm.jdo.JdoTransactionManager:使用JDO进行持久化

org.springframework.jdbc.datasource.DataSourceTransactionManager:使用spring JDBC 或iBatis等基于DataSource数据源的持久化技术

org.springframework.transaction.jta.JtaTransactionMnager:具有多个数据源的全局事务使用该事务管理器(不管采用何种持久化技术)

下面看一下几个常见的事务管理器的配置:

* Spring JDBC 和 iBatis

<context:property-placeholder location="classpath:jdbc.properties"/>
 
<bean id="dataSource"
  class="org.apache.commons.dbcp.BasicDataSource"
  destroy-method="close"
  p:driverClassName="${jdbc.driverClassName}"
  p:url="${jdbc.url}"
  p:username="${jdbc.username}"
  p:password="${jdbc.password}"/>
 
<!-- 基于数据源的事务管理器 -->
<bean id="txManager"
  class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
  p:dataSource-ref="dataSource"/>

spring的事务同步管理器为:TransactionSynchronizationManager,spring框架为不同的持久化技术提供了一套从TransactionSynchronizationManager中获取对应线程绑定资源的工具类:

org.springframework.jdbc.datasource.DataSourceUtils、org.springframework.orm.hibernate3.SessionFactoryUtils等。如果使用模板类则不需要这些,如果手工的话就应该使用这些工具类获取connection或者session等这些非线程安全的资源了。内部使用ThreadLocal技术实现的。

>> spring的事务传播机制

spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时候事务如何进行传播,如下:

* PROPAGATION_REQUIRED:如果当前没有事务,新建一个事务,如果已经存在于一个事务中,加入这个事务中。这个是最常见的选择

* PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行

* PROPAGATION_MANDATORY:使用当前事务,如果当前没有事务,抛出异常

* PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,将当前事务挂起

* PROPAGATION_NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,把当前事务挂起

* PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,抛出异常

* PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似操作

有两个类:UserService(有login()和updateLastLoginTime()方法)、ScoreService(有addScore()方法),login方法调用updateLastLoginTime()后再调用ScoreService的addScore方法,而两个类均设置了事务管理,当内部方法调用的时候,代码自动合并,不会发生任何的传播行为,而当调用其他类的方法的时候,会通过上面的7种定义的传播机制进行事务传播行为,默认是PROPAGATION_REQUIRED,也就是说这三个方法工作在同一个事务中,一损俱损,一荣俱荣。

还有一个要注意的:在相同线程中进行相互嵌套调用的事务方法工作于相同的事务中,而如果这些相互嵌套调用的方法工作于不同的线程中,则不同的线程下的事务方法工作在各自独立的事务中。

下面基于aop/tx命名空间配置一个事务管理器:

package com.springzoo.service;
 
import com.springzoo.domain.Forum;
import com.springzoo.domain.Topic;
 
public interface BbtForum {
    void addTopic(Topic topic) throws Exception;
    void updateForum(Forum forum);
    Forum getForum(int forumId);
    int getForumNum();
}

下面是接口的实现:

package com.springzoo.service.impl;
 
import com.springzoo.dao.ForumDao;
import com.springzoo.dao.PostDao;
import com.springzoo.dao.TopicDao;
import com.springzoo.domain.Forum;
import com.springzoo.domain.Topic;
import com.springzoo.service.BbtForum;
 
public class BbtForumImpl implements BbtForum {
    private ForumDao forumDao;
    private TopicDao topicDao;
    private PostDao postDao;
    public void addTopic(Topic topic) throws Exception {
        topicDao.addTopic(topic);
        if(true) throw new PessimisticLockingFailureException("fail");
        postDao.addPost(topic.getPost());
    }
    public Forum getForum(int forumId) {
        return forumDao.getForum(forumId);
    }
    public void updateForum(Forum forum) {
        forumDao.updateForum(forum);
    }
    public int getForumNum() {
        return forumDao.getForumNum();
    }
     
    public void setForumDao(ForumDao forumDao) {
        this.forumDao = forumDao;
    }
    public void setPostDao(PostDao postDao) {
        this.postDao = postDao;
    }
    public void setTopicDao(TopicDao topicDao) {
        this.topicDao = topicDao;
    }
}

下面是xml配置:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
    //http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    //http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    //http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <import resource="classpath:applicationContext-dao.xml" />
    <bean id="bbtForum"
        class="com.springzoo.service.impl.BbtForumImpl"
        p:forumDao-ref="forumDao"
        p:topicDao-ref="topicDao"
        p:postDao-ref="postDao"/>
 
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
        p:dataSource-ref="dataSource"/>
 
    <aop:config>
        <aop:pointcut id="serviceMethod"
            expression="execution(* com.springzoo.service.*Forum.*(..))" />
        <aop:advisor pointcut-ref="serviceMethod"
            advice-ref="txAdvice" />
    </aop:config>
    <tx:advice id="txAdvice" >
        <tx:attributes> 
            <tx:method name="get*" read-only="true"/>
            <tx:method name="add*" rollback-for="PessimisticLockingFailureException"/>
            <tx:method name="update*"/>         
        </tx:attributes>
    </tx:advice>
</beans>

<tx:method>元素属性表:

属性名 | 是否必须 | 默认值 | 描述

name | 是 | 与事务属性关联的方法名,可以使用通配符* | 如get*、handle*、on*Event等

propagation | 否 | REQUIRED | 事务传播行为,可选值为REQUIRED、SUPPORTS、MANDATORY等

isolation | 否 | DEFAULT | 事务隔离级别,可选值为DEFAULT、READ_UNCOMMITTED等

timeout | 否 | -1 | 事务超时时间秒,如果设置为-1,事务超时时间由底层事务系统决定

read-only | 否 | false | 事务是否只读

rollback-for | 否 | 所有RuntimeException回滚 | 触发事务回滚的Exception,用异常名称的片段进行匹配

no-rollback-for | 否 | 所有CheckedException不回滚 | 不触发回滚的Exception,用异常名称的片段匹配

>> 基于注解的事务管理

只需在子类上加入@Transactional即可,最好是放在业务实现类上,因为注解是不能被继承的,然后在配置文件中加一行代码:

<import resource="classpath:applicationContext-dao.xml" />
 
<bean id="bbtForum"
     class="com.springzoo.service.impl.BbtForumImpl"
     p:forumDao-ref="forumDao"
     p:topicDao-ref="topicDao"
     p:postDao-ref="postDao" />
      
<bean id="txManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
    p:dataSource-ref="dataSource"/>
 
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />

关于@Transactional的属性:

* propagation:事务传播行为,例如:@Transactional(propagation=Propagation.REQUIRES_NEW)

* isolation:事务隔离级别,例如:@Transactional(isolation=Isolation.READ_COMMITTED)

* readOnly:事务读写性,boolean型

* timeout:超时时间秒

* rollbackFor:一组异常类,遇到就回滚类型为:Class<? extends Throwable>[],默认为{},例如:@Transactional(rollbackFor={SQLException.class, IOException.lcass})

* rollbackForClassNmae:一组异常类名字

* noRollbackFor:一组异常类,遇到不回滚

* noRollbackForClassName:一组异常类型的名字,遇到不回滚

>> 多线程的困惑

单实例Bean的最大好处是线程无关性,不存在多线程并发访问的问题,也就是线程安全的。而一个类能够以单实例的方式运行的前提是无状态,也就是说该类不能有状态化的成员变量。我们知道传统的DAO必须持有一个Connection,而Connection即使状态化的对象。但spring通过ThreadLocal将有状态的变量Connection本地线程化,达到另一个层面上的线程无关从而实现线程安全。

>> 不能被spring AOP事务增强的方法:

基于接口的动态代理了:public之外的所有方法(还包括public static方法)

基于CGLib的动态代理:private、static、final(这个要特别注意了)

 

本人博客已搬家,新地址为:http://yidao620c.github.io/

分享到:
评论

相关推荐

    Spring源代码解析(六):Spring声明式事务处理.doc

    Spring 声明式事务处理 Spring 中的事务处理可以分为两种方式:声明式事务处理和编程式事务处理。声明式事务处理通过 AOP 的实现,把事务管理代码作为方面封装到业务代码中,使得事务管理代码和业务代码解藕。这...

    spring+mybatis的声明式事务

    本文将深入探讨"spring+mybatis的声明式事务"这一主题,帮助你理解并掌握这一核心技术。 1. **Spring事务管理** Spring提供两种事务管理方式:编程式事务管理和声明式事务管理。编程式事务管理通过编写代码来控制...

    spring编程式事务与声明式事务详解

    Spring 编程式事务与声明式事务详解 本文将详细解释 Spring 的编程式事务管理及声明式事务管理,帮助读者理清思路。 事务管理的重要性 事务管理对于企业应用至关重要。它保证了用户的每一次操作都是可靠的,即便...

    Spring使用XML配置声明式事务

    在Spring框架中,声明式事务管理是实现事务处理的一种高效且灵活的方式,它允许开发者通过XML配置或注解来定义事务边界,而无需在业务逻辑代码中显式地调用开始、提交或回滚事务的方法。这篇博文"Spring使用XML配置...

    基于java的企业级应用开发:声明式事务管理.ppt

    在Spring框架中,声明式事务管理是实现事务控制的重要手段,它使得开发者无需在代码中显式地管理事务,极大地提高了代码的可维护性和可读性。本篇内容主要涉及两种声明式事务管理方式:基于XML和基于Annotation。 1...

    spring声明式事务配置

    根据提供的信息,我们可以深入探讨Spring框架中的声明式事务配置及其多种实现方式。声明式事务管理是一种简化事务管理的方式,它允许开发人员通过配置而非编程来指定事务边界,从而减少了代码的复杂性并提高了可维护...

    Spring声明式事务配置管理方法

    Spring 声明式事务管理是Spring框架中的一个重要特性,它允许开发者在不编写任何事务管理代码的情况下,通过配置来管理事务。这种方式极大地简化了事务处理,并提高了代码的可维护性。以下是关于Spring声明式事务...

    Spring声明式事务处理

    Spring框架的声明式事务处理是Java企业级应用中不可或缺的一部分,它为开发者提供了一种方便、高效的方式来管理事务。在Spring中,事务管理分为编程式和声明式两种方式,而声明式事务处理则是通过配置来控制事务的...

    spring声明式事务处理demo

    Spring框架的声明式事务处理是其企业级应用中的核心特性之一,它允许开发者通过配置来管理事务,而无需在代码中显式地控制事务的开始、提交和回滚。这种方式极大地提高了代码的可读性和可维护性。在这个"spring声明...

    Hibernate编程式事务与Spring Aop的声明式事务(spring与hibernate集成)

    本主题将深入探讨Hibernate的编程式事务管理和Spring AOP的声明式事务管理,以及两者如何在实际项目中集成使用。 **Hibernate编程式事务管理** Hibernate作为流行的ORM(对象关系映射)框架,提供了对JDBC事务的...

    Spring技术内幕:深入解析Spring架构与设计原理(第2版) .pdf

    4. **事务管理**:Spring提供了声明式事务管理功能,使得事务管理变得更加简单易用。 5. **MVC框架**:Spring的Web MVC框架是一种高度可配置的模型-视图-控制器框架,用于构建Web应用程序。 ### Spring架构分析 ...

    spring3,hibernate4 配置声明式事务管理(annotation方式)

    当我们需要在应用程序中进行事务管理时,Spring提供了一种声明式的方式,使得事务配置更为简洁。本篇将详细介绍如何在Spring 3和Hibernate 4中通过注解来实现声明式事务管理。 首先,我们需要在项目中引入Spring和...

    spring声明式事务管理配置方式

    在Spring框架中,声明式事务管理是实现事务处理的一种高效且灵活的方式,它允许开发者通过在服务层方法上添加特定的注解来控制事务的边界,而无需编写大量的事务管理代码。这种方式使得业务逻辑和事务控制得以分离,...

    全面分析_Spring_的编程式事务管理及声明式事务管理.

    Spring提供了一套基于TaskExecutor的异步任务处理机制,结合@Transactional注解,可以在异步执行的代码块中使用声明式事务管理。但这需要开发者对异步执行的事务特性有充分理解,因为事务的同步特性可能会受到影响。...

    Spring声明式事务

    spring声明式事务实例 可复制修改使用。。。。。。。。。。

    Spring+Hibernate 声明式事务

    本资源主要是结合博文 Spring+Hibernate: 声明式事务 http://blog.csdn.net/ManagementAndJava/article/details/78050519 的源代码,主要是讲解了spring4.3和hibernate5.2.11集成实现原理;

    Spring延迟加载和声明式事务处理最终解决方案(修正版)

    Spring框架的延迟加载和声明式事务处理是两个关键特性,它们极大地简化了企业级应用的开发。延迟加载允许在需要时才加载关联的对象,而声明式事务处理则使得事务管理更加自动化,无需在代码中显式处理。 在Spring与...

    全面分析 Spring 的编程式事务管理及声明式事务管理

    本文将全面分析Spring中的编程式事务管理和声明式事务管理,旨在帮助开发者深入理解这两种事务管理方式,并在实际项目中合理选择。 **编程式事务管理** 编程式事务管理是通过代码直接控制事务的开始、提交、回滚等...

Global site tag (gtag.js) - Google Analytics