Spring的事务机制实例代码

本文研究的主要是Spring的事务机制的相关内容,具体如下。

JAVA EE传统事务机制

通常有两种事务策略:全局事务和局部事务。全局事务可以跨多个事务性资源(即数据源,典型的是数据库和消息队列),通常都需要J2EE应用服务器的管理,其底层需要服务器的JTA支持。而局部事务则与底层采用的持久化技术有关,如果底层直接使用JDBC,需要用Connection对象来操事务。如果采用Hibernate持久化技术,则需要使用session对象来操作事务。

通常的,使用JTA事务,JDBC事务及Hibernate事务的编程流程大致如下,

上图也可以看出,采用传统事务编程,程序代码必须和具体的事务策略的API耦合,如果应用需要切换一种策略,意味着需要大幅修改代码。但是如果使用Spring事务的话,就不会有这个问题了。

Spring事务机制

Sring没有提供任何事务支持,它只是负责包装底层的事务,而在Spring层面,对外提供统一的编程API。Spring事务的核心是PlatformTransactionManager接口,

PlatformTransactionManager代表与具体类型无关的事务接口,可以代表任何事务,包括JDBC事务,Hibernate事务,甚至是JTA事务。

Springa事务机制是一种典型的策略模式,PlatformTransactionManager代表事务管理接口,但它并不知道到底如何管理事务,它只要求事务管理提供开始事务getTransaction(),提交事务commit()和回滚事务rollback()这三个方法,但具体如何实现则交给其实现类完成。编程人员只需要在配置文件中根据具体需要使用的事务类型做配置,Spring底层就自动会使用具体的事务实现类进行事务操作,而对于程序员来说,完全不需要关心底层过程,只需要面向PlatformTransactionManager接口进行编程即可。PlatformTransactionManager接口中提供了如下方法:getTransaction(..), commit(); rollback(); 这些都是与平台无关的事务操作。

getTransaction()的完整写法为 TransactionStatus getTransaction(TransactionDefinition definiton)

这个方法用来返回一个事务对象,其中的参数TransactionDefinition 则可以为事务对象指定各种属性,通常可以指定 事务的隔离属性, 传播属性, 超时,只读 这几个属性。

Spring具体的事务管理需要在配置文件中配置好PlatformTransactionManager,下面是不同类型的事务对应的Spring配置。

JDBC数据源的局部事务管理器的配置如下,

<!-- 定义数据源Bean,使用C3P0数据源实现,并注入数据源的必要信息 -->
  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSrouce"
    destroy-method="close"
    p:driverClass="com.mysql.jdbc.Driver"
    p:jdbcUrl="jdbc:mysql://localhost/test"
    p:user="root"
    p:password=""
    p:maxPoolSize="40"
    p:minPoolSize="2"
    p:initialPoolSize="2"
    p:maxIdleTime="30" />
  <!-- 配置JDBC数据源的局部数据管理器,使用DataSourceTransactionManager类 -->
  <bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
    p:dataSource-ref="dataSource" />

容器管理的JTA全局事务管理器的配置如下,

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"
  p:jndiName="jdbc/jpetstore" />
<!-- 使用JtaTransactionManager类, 该类实现了PlatformTransactionManager接口 -->
<!-- 使用JTA全局事务,Spring容器可以自行从Java EE服务器中获取事务性资源,无需依赖注入 -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

对于JTA全局事务,只需要指定事务管理器的实现类JtaTransactionManager即可,Spring容器会自行从J2EE服务器获取数据源,无需显式注入进事务管理器。

基于Hibernate持久化技术的Spring局部事务配置如下,

<!-- 定义数据源Bean,使用C3P0数据源实现,并注入数据源的必要信息 -->
  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSrouce"
    destroy-method="close"
    p:driverClass="com.mysql.jdbc.Driver"
    p:jdbcUrl="jdbc:mysql://localhost/test"
    p:user="root"
    p:password=""
    p:maxPoolSize="40"
    p:minPoolSize="2"
    p:initialPoolSize="2"
    p:maxIdleTime="30" />
  <!-- 定义Hibernate的SessionFactory, SessionFactory需要依赖数据源,注入dataSource -->
  <bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
    p:dataSource-ref="dataSource">
    <!-- annotatedClasses用来列出全部持久化类 -->
    <property name="annotatedClasses">
      <list>
        <!-- 以下用来列出所有PO类 -->
        <value>com.entity.User</value>
      </list>
    </property>
    <!-- 定义Hibernate的sessionFactory属性 -->
    <property name="hibernateProperties">
      <props>
        <!-- 指定Hibernate的连接方言 -->
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
        <!-- 是否根据Hibernate映射表创建数据表 -->
        <prop key="hibernate.hbm2ddl.auto">update</prop>
      </props>
    </property>
  </bean>
  <!-- 配置Hibernate的局部数据管理器,使用HibernateTransactionManager类 -->
  <!-- 该类是PlatformTransactionManager接口针对Hibernate的特定实现 -->
  <!-- 配置HibernateTransactionManager需要注入sessionFactory -->
  <bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager"
    p:sessionFactory-ref="sessionFactory" />

Spring事务如果采用Hibernate策略,一般需要配置三点:数据源, sessionFactory, 事务管理器。

如果底层采用Hibernate持久层技术,而事务采用JTA全局事务时,配置如下,

<!-- 配置JTA数据源-->
  <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"
    p:jndiName="jdbc/jpetstore" />
  <!-- 定义Hibernate的SessionFactory, SessionFactory需要依赖数据源,注入dataSource -->
  <bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
    p:dataSource-ref="dataSource">
    <!-- annotatedClasses用来列出全部持久化类 -->
    <property name="annotatedClasses">
      <list>
        <!-- 以下用来列出所有PO类 -->
        <value>com.entity.User</value>
      </list>
    </property>
    <!-- 定义Hibernate的sessionFactory属性 -->
    <property name="hibernateProperties">
      <props>
        <!-- 指定Hibernate的连接方言 -->
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
        <!-- 是否根据Hibernate映射表创建数据表 -->
        <prop key="hibernate.hbm2ddl.auto">update</prop>
      </props>
    </property>
  </bean>
  <!-- 使用JtaTransactionManager类,该类是PlatformTransactionManager接口的实现类 -->
  <!-- 针对全局事务管理的特定实现 -->
  <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

这与前面的基于Hibernate的Spring事务比起来,就是将数据源换成了JNDI数据源, 将事务管理器换成了JtaTransactionManager.

对于JTA全局事务,因为需要底层应用服务器的支持,而不同应用服务器所提供的JTA全局事务可能存在细节上的差异,因此实际配置全局事务管理器时可能需要使用JtaTransactionManager的子类,例如Oracle的JavaEE应用服务器提供的OC4JJtaTransactionManager,Oracle为WebLogic提供的WebLogicJtaTransactionManager, IBM为WebSphere提供的WebSphereUowTransactionManager等。

从上面各种事务类型的Spring配置可以看出,当应用程序采用Spring事务管理时,应用程序无需与具体的事务API耦合,应用程序只需要面向PlatormTransactionManager接口编程即可,ApplicationContext会根据配置文件选择合适的事务策略实现类(即PlatormTransactionManager的实现类)。

那么在具体在Spring中如何进行事务控制编程呢,通常有两种方式,

编程式事务管理:就是直接在代码中使用PlatormTransactionManager提供的三个抽象方法进行事务流程控制。也可以在Spring容器中获取PlatormTransactionManager类型的Bean,该Bean总是PlatormTransactionManager的具体实现类的实例,具体的实现类则由ApplicationContext按照策略模式进行选择,编程人员无需关心,只需要面向接口编程即可。

声明式事务管理:这种方式不需要讲事务控制流程写入代码中,而是通过AOP的方式,完全由配置文件完成事务的织入。即XML配置文件可以为业务组件配置事务代理,事务代理为业务组件提供事务控制。现在这种方式是最好的,源码侵入性最低。

使用声明式事务管理-使用XML Schema配置事务策略

当使用声明式事务时,只需要写好配置文件,配置需要事务控制的组件种类,业务组件就会在AOP机制下被织入事务控制,而编程人员不需要写任何事务管理代码,可以专注于业务组件的开发。因此通常都推荐使用声明式事务管理。

Spring的XML Schema方式提供了简洁的事务配置策略,通过命名空间 <tx:advice> 来配置一个事务增强处理,其中可以指定事务的各种属性(例如隔离属性, 传播属性, 超时,只读属性等等),然后通过<aop:config>标签可以将事务的增强与AOP的切入点(即Bean的执行方法)进行绑定,从而实现对Bean的方法织入事务操作。下面是一个简单的例子,配置一个NewsDaoImpl bean进行数据操作,使用c3p0数据源,Spring的JDBC事务管理器,在<tx:advice对事务设置属性。

完整的Spring配置如下,

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.springframework.org/schema/beans"
  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-4.0.xsd
  http://www.springframework.org/schema/aop
  http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
  http://www.springframework.org/schema/tx
  http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
  <!-- 定义数据源Bean,使用C3P0数据源实现,并注入数据源的必要信息 -->
  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
    destroy-method="close"
    p:driverClass="com.mysql.jdbc.Driver"
    p:jdbcUrl="jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=UTF-8"
    p:user="root"
    p:password=""
    p:maxPoolSize="40"
    p:minPoolSize="2"
    p:initialPoolSize="2"
    p:maxIdleTime="30" />
  <!-- 配置JDBC数据源的局部数据管理器,使用DataSourceTransactionManager类 -->
  <bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
    p:dataSource-ref="dataSource" />

  <!-- 配置一个业务逻辑Bean -->
  <bean id="newsDao" class="com.dao.impl.NewsDaoImpl" p:ds-ref="dataSource" />
  <!-- 配置事务增强处理, 指定事务管理器 -->
  <tx:advice id="txAdvice"
    transaction-manager="transactionManager">
    <!-- 用于配置详细的事务定义 -->
    <tx:attributes>
      <!-- 所有以get开头的方法都是只读的 -->
      <tx:method name="get*" read-only="true" />
      <!-- 其他方法默认都适用事务,指定超时5秒 -->
      <tx:method name="*" isolation="DEFAULT" propagation="REQUIRED" timeout="5" />
    </tx:attributes>
  </tx:advice>
  <aop:config>
    <!-- 配置一个切入点,匹配impl包下所有以impl结尾的类里的所有方法的执行 -->
    <aop:pointcut expression="execution(* com.dao.impl.*Impl.*(..))" id="myPointcut" />
    <!-- 将切入点myPointcut和增强txAdvice绑定-->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" />
    <!-- 再配置一个切入点,匹配impl包下所有以abc开头类里的所有方法的执行 -->
  </aop:config>
</beans>

NewsDaoImpl代码中,则是插入重复数据到表中,

package com.dao.impl;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import com.dao.NewsDao;
public class NewsDaoImpl implements NewsDao {
	private DataSource ds;
	public void setDs(DataSource ds) {
		this.ds = ds;
	}
	@Override
	  public void insert(String title, String content) {
		//c3p0数据池的用法
		JdbcTemplate jt = new JdbcTemplate(ds);
		jt.update("insert into news_inf" + " values(100,?,?)", title, content);
		jt.update("insert into news_inf" + " values(100,?,?)", title, content);
		//如果没有事务控制,则第一条记录可以被插入
		//如果增加事务控制,将发现第一条记录也插不进去
	}
}

下面是测试方法,

public static void test3() {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("beans4JDBC.xml");
    //获取事务代理Bean
    NewsDao dao = (NewsDao)ctx.getBean("newsDao", NewsDao.class);
    dao.insert("java编程核心思想", "轻量级Java EE开发");
    System.out.println("执行完毕");
  }

执行测试方法会发现抛出异常(因为有重复数据),而又因为事务控制,数据库中讲不会有数据插入。

可以看到上面例子中,通常对于XML Schema的配置中,其实就是对一个普通的Bean做了AOP配置,织入一个advice增强,而advice增强中则配置一个事务管理器,事务管理器又依赖数据源。

对于<aop:advisor>中,将advice和切入点的绑定,而在Spring底层是由Bean后处理器完成(例如BeanNameAutoProxyCreator, DefaultAdvisorAutoProxyCreator),其本质就是动态代理。

另外,在<tx:advice>配置增强中,还可以为事务指定再遇到特定异常时,进行强制rollback和强制不rollback,即rollback-for="xxxException", no-rollback-for="xxxException"

使用@Transactionl

除了使用XML Schema的方法之外,也可以直接在方法上添加@Transaction注解,使这个方法具有事务属性。 在@Transaction中可以为事务配置各种属性(例如隔离属性, 传播属性, 超时,只读属性等等),此外,还需要在在XML配置中加入<tx:annotation-triven配置表明Spring会根据注解来配置事务代理,这样,事务的属性配置和AOP切入配置就可以只通过一步(直接通过注解配置在方法名上)完成了。

<tx:annotation-driven transaction-manager="transactionManager" />

NewsDaoImpl.

@Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.DEFAULT, timeout=5)
@Override
public void insert(String title, String content) {

总结

以上就是本文关于Spring的事务机制实例代码的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

您可能感兴趣的文章:

  • 浅谈SpringBoot之事务处理机制
  • 详解Springboot事务管理
  • mybatis开启spring事务代码解析
  • 浅谈Spring的两种事务定义方式
  • 解决spring mvc 多数据源切换,不支持事务控制的问题
  • Spring的编程式事务和声明式事务详解
  • Spring boot jpa 删除数据和事务管理的问题实例详解
  • SpringBoot 注解事务声明式事务的方式
(0)

相关推荐

  • Spring的编程式事务和声明式事务详解

    入口(了解一些基本概念) Spring事务属性(事务的属性有哪些?) 我们都知道事务有开始,保存点,提交,回滚,隔离级别等属性.那么Spring对于事务属性定义有哪些呢?通过TransactionDefinition接口我们可以了解到: public interface TransactionDefinition{ int getIsolationLevel(); int getPropagationBehavior(); int getTimeout(); boolean isReadOnly

  • SpringBoot 注解事务声明式事务的方式

    springboot 对新人来说可能上手比springmvc要快,但是对于各位从springmvc转战到springboot的话,有些地方还需要适应下,尤其是xml配置.我个人是比较喜欢注解➕xml是因为看着方便,查找方便,清晰明了.但是xml完全可以使用注解代替,今天就扒一扒springboot中事务使用注解的玩法. springboot的事务也主要分为两大类,一是xml声明式事务,二是注解事务,注解事务也可以实现类似声明式事务的方法,关于注解声明式事务,目前网上搜索不到合适的资料,所以在这里

  • 浅谈SpringBoot之事务处理机制

    一.Spring的事务机制 所有的数据访问技术都有事务处理机制,这些技术提供了API用来开启事务.提交事务来完成数据操作,或者在发生错误的时候回滚数据. 而Spring的事务机制是用统一的机制来处理不同数据访问技术的事务处理.Spring的事务机制提供了一个PlatformTransactionManager接口,不同的数据访问技术的事务使用不同的接口实现: 在程序中定义事务管理器的代码如下: @Bean public PlatformTransactionManager transaction

  • 详解Springboot事务管理

    在Spring Boot事务管理中,实现自接口PlatformTransactionManager. public interface PlatformTransactionManager { org.springframework.transaction.TransactionStatus getTransaction(org.springframework.transaction.TransactionDefinition transactionDefinition) throws org.

  • 浅谈Spring的两种事务定义方式

    一.声明式 这种方法不需要对原有的业务做任何修改,通过在XML文件中定义需要拦截方法的匹配即可完成配置,要求是,业务处理中的方法的命名要有规律,比如setXxx,xxxUpdate等等.详细配置如下: <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="

  • Spring boot jpa 删除数据和事务管理的问题实例详解

    今天我们介绍的是jpa删除和事务的一些坑,接下来看看具体内容. 业务场景(这是一个在线考试系统)和代码:根据问题的id删除答案 repository层: int deleteByQuestionId(Integer questionId); service 层: public void deleteChoiceAnswerByQuestionId(Integer questionId) { choiceAnswerRepository.deleteByQuestionId(questionId)

  • 解决spring mvc 多数据源切换,不支持事务控制的问题

    一个项目中需要使用两个数据库,Oracle 和Mysql,于是参考各个blog,实现此功能.写好后才发现,原来的事务失效了,我去... spring-mybatis.xml 配置 <bean id="configReader" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"> <property name="location

  • mybatis开启spring事务代码解析

    1.事务 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的.最终都是调用数据库连接来完成事务的开启.提交和回滚. 2.模块 那么在对于spring事务而言,几个不可或缺的模块就是数据源.事务管理器以及事务编程 3.xml配置 <!--事务管理器--> <bean id="springTransactionManager" class="org.springframework.jdbc.datasourc

  • Spring的事务机制实例代码

    本文研究的主要是Spring的事务机制的相关内容,具体如下. JAVA EE传统事务机制 通常有两种事务策略:全局事务和局部事务.全局事务可以跨多个事务性资源(即数据源,典型的是数据库和消息队列),通常都需要J2EE应用服务器的管理,其底层需要服务器的JTA支持.而局部事务则与底层采用的持久化技术有关,如果底层直接使用JDBC,需要用Connection对象来操事务.如果采用Hibernate持久化技术,则需要使用session对象来操作事务. 通常的,使用JTA事务,JDBC事务及Hibern

  • Spring缓存机制实例代码

    Spring的缓存机制非常灵活,可以对容器中任意Bean或者Bean的方法进行缓存,因此这种缓存机制可以在JavaEE应用的任何层次上进行缓存. Spring缓存底层也是需要借助其他缓存工具来实现,例如EhCache(Hibernate缓存工具),上层则以统一API编程. 要使用Spring缓存,需要以下三步 1.向Spring配置文件导入context:命名空间 2.在Spring配置文件启用缓存,具体是添加 <cache:annotation-driven cache-manager="

  • Java反射机制实例代码分享

    本文旨在对Java反射机制有一个全面的介绍,希望通过本文,大家会对Java反射的相关内容有一个全面的了解. 阅读本文之前,大家可先行参阅<重新理解Java泛型>. 前言 Java反射机制是一个非常强大的功能,在很多大型项目比如Spring, Mybatis都可以看见反射的身影.通过反射机制我们可以在运行期间获取对象的类型信息,利用这一特性我们可以实现工厂模式和代理模式等设计模式,同时也可以解决Java泛型擦除等令人苦恼的问题.本文我们就从实际应用的角度出发,来应用一下Java的反射机制. 反射

  • Java之Spring注解配置bean实例代码解析

    前面几篇均是使用xml配置bean,如果有上百个bean,这是不可想象的.故而,请使用注解配置bean !!! [1]注解类别 @Component : 基本注解, 标识了一个受 Spring(点击这里可以下载<Spring应用开发完全手册>) 管理的组件 @Repository : 标识持久层组件 @Service : 标识服务层(业务层)组件 @Controller : 标识表现层组件 Spring 能够从 classpath 下自动扫描, 侦测和实例化具有特定注解的组件. 对于扫描到的组

  • java 使用memcached以及spring 配置memcached完整实例代码

    Memcached是一个高性能的分布式内存对象缓存系统,本文介绍了java 使用memcached以及spring 配置memcached完整实例代码,分享给大家 本文涉及以下内容: 1,要使用的jar包 2,java 使用memcached 3,spring 配置memcached 导入jar java_memcached-release_2.6.6.jar commons-pool-1.5.6.jar slf4j-api-1.6.1.jar slf4j-simple-1.6.1.jar 示例

  • Hibernate缓存机制实例代码解析

    本文研究的主要是Hibernate缓存机制的相关内容,具体如下. 演示项目: Student.java: public class Student { /*学生ID*/ private int id; /*学生姓名*/ private String name; /*学生和班级的关系*/ private Classes classes; //省略setter和getter方法 } Classes.java: public class Classes { /*班级ID*/ private int i

  • Spring+Junit4进行接口测试实例代码

    本文研究的主要是Spring+Junit4进行接口测试的一个相关实例,具体实现代码如下. 1.配置pom.xml <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.2.RELEASE</version> </dependency> <depende

  • 基于spring如何实现事件驱动实例代码

    干货点 通过阅读该篇博客,你可以了解了解java的反射机制.可以了解如何基于spring生命周期使用自定义注解解决日常研发问题.具体源码可以点击链接. 问题描述 在日常研发中,经常会遇见业务A的某个action被触发后,同时触发业务B的action的行为,这种单对单的形式可以直接在业务A的action执行结束后直接调用业务B的action,那么如果是单对多的情况呢? 方案解决 这里提供一种在日常研发中经常使用到的机制,基于spring实现的事件驱动,即在业务A的action执行完,抛出一个事件,

  • asp.net 身份验证机制实例代码

    ASP.NET提供了3种认证方式:windows身份验证.Forms验证和Passport验证. windows身份验证: IIS根据应用程序的设置执行身份验证.要使用这种验证方式,在IIS中必须禁用匿名访问. Forms验证:用Cookie来保存用户凭证,并将 未经身份验证的用户重定向到自定义的登录页. Passport验证:通过Microsoft的集中身份验证服务执行的,他为成员站点提供单独登录和核心配置文件服务. 关于这三种验证方式的配置,推荐一篇文章:http://www.jb51.ne

  • Java打印和打印预览机制实例代码

    复制代码 代码如下: import java.awt.BasicStroke;import java.awt.BorderLayout;import java.awt.Color;import java.awt.Component;import java.awt.Dimension;import java.awt.Font;import java.awt.FontMetrics;import java.awt.Graphics;import java.awt.Graphics2D;import

随机推荐