服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Spring的事务机制实例代码

Spring的事务机制实例代码

2021-04-02 13:33云中之歌 Java教程

这篇文章主要介绍了Spring的事务机制实例代码,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下

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

java ee传统事务机制

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

通常的,使用jta事务,jdbc事务及hibernate事务的编程流程大致如下,

Spring的事务机制实例代码

上图也可以看出,采用传统事务编程,程序代码必须和具体的事务策略的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数据源的局部事务管理器的配置如下,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- 定义数据源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全局事务管理器的配置如下,

?
1
2
3
4
5
<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局部事务配置如下,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!-- 定义数据源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全局事务时,配置如下,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- 配置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配置如下,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?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代码中,则是插入重复数据到表中,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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);
        //如果没有事务控制,则第一条记录可以被插入
        //如果增加事务控制,将发现第一条记录也插不进去
    }
}

下面是测试方法,

?
1
2
3
4
5
6
7
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切入配置就可以只通过一步(直接通过注解配置在方法名上)完成了。

?
1
<tx:annotation-driven transaction-manager="transactionmanager" />

newsdaoimpl.

?
1
2
3
@transactional(propagation=propagation.required, isolation=isolation.default, timeout=5)
@override
public void insert(string title, string content) {

总结

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

原文链接:http://www.cnblogs.com/fysola/p/6384399.html

延伸 · 阅读

精彩推荐