Spring事务服务
Spring为事务管理提供了一流的支持。同时支持编程式事务和声明式事务。无论是编程式事务,还是声明式事务,在开发Spring应用工程中,开发者都不需要同具体的事务管理实现进行交互。
事务管理抽象是Spring提供的最为重要的一种抽象。秉承Spring的设计原则,对于事务管理而言,Soring的食物抽象具有如下几方面的优势:
● 对于采用手工控制事务,即程序控制事务的编程方式而言,Spring提供的事务抽象易于使用。
● 无论底层的事务API是什么,Spring都能够提供一致的编程模型。
● Spring支持以声明方式管理事务,这其中主要依赖于Spring AOP模块提供的功能。因此,Spring
AOP在Spring事务抽象服务中起了重要作用。
● 能够同Spring的DAO抽象进行集成。
● 在不同事务服务之间切换,只会涉及到Spring配置文件的修改,而不会涉及到代码的修改。
数据库事务
通常,数据库事务都具备ACID的特性。
●
A,即原子性(Atomicity)。表示组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有的操作成功执行,整个事务才提交,事务中任何一个数据库操作失败,已经执行的任何操作都必须撤销,让数据库返回到初始状态。继而保证事物的原子性。
●
C,即一致性(Consistency)。事务操作将导致一致性的结果,即使得其操作的资源处于一致性状态。无论是事务成功提交,还是回滚,都必须保证资源状态的一致性。当然,这种一致性在很大程度上需要由应用保证,因此C同A、I、D存在很大区别。
●
I,即隔离性(Isolation)。是事务执行过程中,其操作的资源的状态信息不能够被其他事务操作到。因此,不同事务不能够并发对同一数据资源进行读取或写入操作。在对RDBMS操作过程中,为保证隔离性,经常需要对表、列进行锁定操作。
● D即持久性(Durability)。一旦事务成功提交,则事务所导致的结果应该是持久的,即使系统瘫痪都需要保证持久性。
对于声明式事务,Spring支持各种事务管理器,它提供TransactionProxyFactoryBean类,供实现声明式事务使用。
对于编程式事务,Spring也支持各种事务管理器,而且,比声明式事务更灵活。
在Spring提供的所有事务管理器中,PlatformTransactionManager(org.springframework.transaction.PlatformTransactionManager)是最基本的接口也是很重要的接口。
开发者应该很清楚,Spring框架肯定会为它提供若干个实现,供Spring
IOC实现控制反转使用。对于Hiberante,需要借助于 HiberanteTransactionManager
将会把事务处理的具体工作委派给Hiberante中的net.sf.hiberante.Transation对象。其实,Spring提供的所用事务管理器中,都是对底层事务对象的封装。它自身并没有实现底层事务的管理。这也符合Spring的设计初衷——“不重复发明轮子”。对HibernateTransactionManager的commit
和 rollback操作将委派给Transaction对象。
<bean id=”transactionManager”
class=”org.springframework.orm.hibernate.HibernateTransactionManager”>
<property
name=”sessionFactory”>
<ref
local=”sessionFactory”/>
</property>
</bean>
HibernateTransactionManager就是实现PlatformTransactionManager接口,而且还是通过Spring
IoC容器加载的。
Spring主要涉及到的事务管理器有:
●
JDBC事务:借助于DataSourceTransactionManager实现。
●
JTA事务:借助于JtaTransactionManager、WebLogicJtaTransactionManager实现。
●
Hibernate事务:借助于HibernateTransactionManager实现。
●
JDO事务:借助于JdoTransactionManager实现。
●
OJB事务:借助于PersistenceBrokerTransactionManager实现。
●
JMS事务:借助于JmsTransactionManager实现。
对于JDBC事务而言,需要配置DataSourceTransactionManager。配置示例如下。
<bean id=”transactionManager”
class=”org.springframework.jdbc.datasource.DataSourceTransactionManager”>
<property name=”dataSource”>
<ref local=”dataSource”/>
</property>
</bean>
<bran id=”dataSource”
class=”org.springframework.jndi.JndiObjectFactoryBean”>
<property name=”jndiName”>
<value>java:/MySqlDS</value>
</property>
</bean>
开发者需要为它准备dataSource
取值。至于dataSource的具体来源,DataSourceTransactionManager可以不用关注。这或许就是IoC的好处,而且还可以在产品部署场合动态切换。DataSourceTransactionManager会将事务
commit 和 rollback 操作委派给java.sql.Commection。
对于JDO事务而言,需要配置JdoTransactionManager。配置如下:
<bean id=”transactionManager”
class=”org.springframework.orm.jdo.JdoTransactionManager”>
<property
name=”persistenceManagerFactory”>
<ref
local=”persistenceManagerFactory”/>
</property>
</bean>
对于JTA事务而言,需要配置JtaTransactionManager或者WebLogicJtaTransactionManager实现。配置如下:
<bean id=”transactionManager”
class=”org.springframework.transaction.jta.JtaTransactionManager”>
<property
name=”userTransactionName”>
<value>java:comp/UserTransaction</value>
</property>
</bean>
其中,指定了userTransactionName
属性。默认时,JtaTransactionManager设定userTransactionName属性取值为java:comp/UserTransaction,因此如果目标JTA实现的UserTransaction
名为java:comp/UserTransaction,则不用给出userTransactionName属性。当然,除了userTransactionName
属性外,还具有transactionManagerName、jndiTemplate、autodetectTransactionManager、等属性。其中,TransactionManagerName指定事务管理器名字;jndiTemplate
指定JNDI 模版,供查找事务管理器和
UserTransaction对象使用;autodetectTransactionManager用于指定是否自动查找事务管理器(默认时为true)。
声明式事务
借助Spring AOP,Spring提供了
TransactionProxyFactoryBean,它是为简化声明式事务处理而引入的代理工厂
JavaBean。当然,也可以使用ProxyFactoryBean 和
TransactionInterceptor的组合。在TransactionProxyFactoryBean 内部使用了事务拦截器,即
TransactionInterceptor。
使用声明式事务管理器,首先要搭建SSH框架,添加 Spring AOP JAR包,添加方法详见上篇:http://blog.sina.com.cn/s/blog_655974a60101c891.html#bsh-75-262512748
事务配置
首先在/WEB-INF/applicationContext.xml添加以下内容:
<!-- 配置事务管理器
-->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>
注:这是作为公共使用的事务管理器Bean。这个会是事先配置好的,不需各个模块各自去配。
下面就开始配置各个模块所必须的部分,在各自的applicationContext-XXX-beans.xml配置的对于事务管理的详细信息。
首先就是配置事务的传播特性,如下:
<!-- 配置事务传播特性
-->
<tx:advice id="TestAdvice"
transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*"
propagation="REQUIRED"/>
<tx:method name="del*"
propagation="REQUIRED"/>
<tx:method name="update*"
propagation="REQUIRED"/>
<tx:method name="add*"
propagation="REQUIRED"/>
<tx:method name="find*"
propagation="REQUIRED"/>
<tx:method name="get*"
propagation="REQUIRED"/>
<tx:method name="apply*"
propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置参与事务的类
-->
<aop:config>
<aop:pointcut
id="allTestServiceMethod" expression="execution(*
com.test.testAda.test.model.service.*.*(..))"/>
<aop:advisor
pointcut-ref="allTestServiceMethod" advice-ref="TestAdvice"
/>
</aop:config>
事务的几种传播特性
1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务。如果没有事务则开启
2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行
3. PROPAGATION_MANDATORY:
如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
4. PROPAGATION_REQUIRES_NEW:
总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
5. PROPAGATION_NOT_SUPPORTED: 总是非事务地执行,并挂起任何存在的事务。
6. PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常
7. PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中.
如果没有活动事务,则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行
需要注意的地方:
(1)
advice(建议)的命名:由于每个模块都会有自己的Advice,所以在命名上需要作出规范,初步的构想就是模块名+Advice(只是一种命名规范)。
(2) tx:attribute标签所配置的是作为事务的方法的命名类型。
如<tx:method name="save*"
propagation="REQUIRED"/>
其中*为通配符,即代表以save为开头的所有方法,即表示符合此命名规则的方法作为一个事务。
propagation="REQUIRED"代表支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
(3)
aop:pointcut标签配置参与事务的类,由于是在Service中进行数据库业务操作,配的应该是包含那些作为事务的方法的Service类。
首先应该特别注意的是id的命名,同样由于每个模块都有自己事务切面,所以我觉得初步的命名规则因为
all+模块名+ServiceMethod。而且每个模块之间不同之处还在于以下一句:
expression="execution(*
com.test.testAda.test.model.service.*.*(..))"
其中第一个*代表返回值,第二*代表service下子包,第三个*代表方法名,“(..)”代表方法参数。
(4) aop:advisor标签就是把上面我们所配置的事务管理两部分属性整合起来作为整个事务管理。
图解:
下面给出详细的applicationContext.xml 文件的注释:
<?xml version="1.0"
encoding="gb2312"?>
<!--
Spring配置文件的文件头,包含DTD等信息-->
<!DOCTYPE
beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!--定义数据源-->
<bean
id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!--
定义数据库驱动-->
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<!--
定义数据库url-->
<property name="url"><value>jdbc:mysql://localhost:3306/spring</value></property>
<!--
定义数据库用户名-->
<property name="username"><value>root</value></property>
<!--
定义数据库密码-->
<property name="password"><value>32147</value></property>
</bean>
<!--定义一个hibernate的SessionFactory-->
<bean
id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!--
定义SessionFactory必须注入DataSource-->
<property name="dataSource"><ref
local="dataSource"/></property>
<property name="mappingResources">
<list>
<!--以下用来列出所有的PO映射文件-->
<value>Person.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<!--此处用来定义hibernate的SessionFactory的属性:
不同数据库连接,启动时选择create,update,create-drop-->
<prop
key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop
key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!--
定义事务管理器,使用适用于Hibernte的事务管理器-->
<bean
id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<!--
HibernateTransactionManager
bean需要依赖注入一个SessionFactory
bean的引用-->
<property name="sessionFactory"><ref
local="sessionFactory"/></property>
</bean>
<!--定义DAO Bean ,
作为事务代理的目标-->
<bean id="personDaoTarget" class="lee.PersonDaoHibernate">
<!--
为DAO
bean注入SessionFactory引用-->
<property name="sessionFactory"><ref
local="sessionFactory"/></property>
</bean>
<!--
定义DAO
bean的事务代理-->
<bean id="personDao" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!--
为事务代理bean注入事务管理器-->
<property name="transactionManager"><ref
bean="transactionManager"/></property>
<!--
设置事务属性-->
<property
name="transactionAttributes">
<props>
<!--
所有以find开头的方法,采用required的事务策略,并且只读-->
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<!--
其他方法,采用required的事务策略
->
<prop
key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
<!--
为事务代理bean设置目标bean
-->
<property
name="target">
<ref
local="personDaoTarget"/>
</property>
</bean>
</beans>
在上面的配置文件中,personDao需要配置两个部分,一个是personDao的目标bean,该目标bean是实际DAO
bean,以实际的DAO bean为目标,建立事务代理。一个组件,需要来个bean组成,一个目标bean,一个事务代理。
这种配置方式还有一个坏处:目标bean直接暴露在Spring容器中,可以直接引用,如果目标bean被误引用,将导致业务操作不具备事务性。
为了避免这种现象,可将目标bean配置成嵌套bean,下面是目标bean和事务代理的配置片段:
<!--
定义DAO
bean的事务代理-->
<bean
id="personDao" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!--
为事务代理bean注入事务管理器-->
<property
name="transactionManager"><ref
bean="transactionManager"/></property>
<!--
设置事务属性-->
<property
name="transactionAttributes">
<props>
<!--
所有以find开头的方法,采用required的事务策略,并且只读-->
<prop
key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<!--
其他方法,采用required的事务策略
->
<prop
key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
<!--
为事务代理bean设置目标bean
-->
<property
name="target">
<!--
采用嵌套bean配置目标bean-->
<bean
class="lee.PersonDaoHibernate">
<!--
为DAO
bean注入SessionFactory引用-->
<property name="sessionFactory"><ref
local="sessionFactory"/></property>
</bean>
</property>
</bean>
0
喜欢
0
赠金笔
-->
0
赠金笔
转载列表:
转载是分享博文的一种常用方式...
- 评论加载中,请稍候...
Spring事务服务的更多相关文章
- spring事务管理器设计思想(二)
上文见<spring事务管理器设计思想(一)> 对于第二个问题,涉及到事务的传播级别,定义如下: PROPAGATION_REQUIRED-- 如果当前没有事务,就新建一个事务.这是最常见 ...
- Spring事务传播属性
Spring 对事务控制的支持统一在 TransactionDefinition 类中描述,该类有以下几个重要的接口方法: int getPropagationBehavior():事务的传播行为 i ...
- Spring 事务管理高级应用难点剖析--转
第 1 部分 http://www.ibm.com/search/csass/search/?q=%E4%BA%8B%E5%8A%A1&sn=dw&lang=zh&cc=CN& ...
- Spring事务传播机制
Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播,即协调已经有事务标识的方法之间的发生调用时的事务 ...
- Spring事务传播特性的浅析——事务方法嵌套调用的迷茫
Spring事务传播机制回顾 Spring事务一个被讹传很广说法是:一个事务方法不应该调用另一个事务方法,否则将产生两个事务.结果造成开发人员在设计事务方法时束手束脚,生怕一不小心就踩到地雷. 其实这 ...
- 2015第24周一Spring事务
1. Spring事务管理简介 (1)Spring为多种不同类型的事务管理机制提供统一编程模型,这些事务管理模型包括JTA.JDBC.Hibernate.JPA和JDO. (2)Spring支持声明式 ...
- spring事务管理器设计思想(2)
spring事务管理器设计思想(二) 上文见<spring事务管理器设计思想(一)> 对于第二个问题,涉及到事务的传播级别,定义如下: PROPAGATION_REQUIRED-- 如果当 ...
- spring事务探索
spring自建事务管理模块.而且这个事务管理是一个抽象设计,可以应用到很多场合,包括普通的DataSource,jta,jms和hibernate上. 要正确使用spring的事务,首先需要了解s ...
- Spring事务事件监控
前面我们讲到了Spring在进行事务逻辑织入的时候,无论是事务开始,提交或者回滚,都会触发相应的事务事件.本文首先会使用实例进行讲解Spring事务事件是如何使用的,然后会讲解这种使用方式的实现原理. ...
随机推荐
- 洛谷P1086花生采摘(简单模拟)
题目描述 鲁宾逊先生有一只宠物猴,名叫多多.这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:“欢迎免费品尝我种的花生!――熊字”. 鲁宾逊先生和多多都很开心,因为花生正是他 ...
- Python语言——map/reduce的用法
Python内建了map()和reduce()函数. 如果你读过Google的那篇大名鼎鼎的论文“MapReduce: Simplified Data Processing on Large Clus ...
- rtt之通用bootloader
目前只支持F1/F4;使用步骤 1 在官网注册产品,根据系列设定参数,接收邮箱,点击生成就可以在自己的邮箱中收到对应的bootloader.bin文件.用jlink就可以将其烧写进单片机. 2 存储被 ...
- 如何用VBA代码依次打开文件夹下的Excel文件
'Check Public Function Check() As Variant On Error GoTo erlb Dim StrDir As String StrDir = T ...
- String方法阅读笔记
String类常用方法 1.int Length(): 参数:无 返回值:调用此方法的字符串的长度(int) 实例: public class Test { public static void ma ...
- 「NOI2009」植物大战僵尸
「NOI2009」植物大战僵尸 传送门 这是一道经典的最大权闭合子图问题,可以用最小割解决(不会的可以先自学一下) 具体来说,对于这道题,我们对于两个位置的植物 \(i\) 和 \(j\) ,如果 \ ...
- Python 之并发编程之线程下
七.线程局部变量 多线程之间使用threading.local 对象用来存储数据,而其他线程不可见 实现多线程之间的数据隔离 本质上就是不同的线程使用这个对象时,为其创建一个只属于当前线程的字典 拿空 ...
- C/C++网络编程7——多进程服务器端之fork函数
通过前面几节的内容,我们已经可以实现基本的C/S结构的程序了,但是当多个客户端同时向服务器端请求服务时,服务器端只能按顺序一个一个的服务,这种情况下,客户端的用户是无法忍受的.所以虚实现并发的服务器端 ...
- TCP通讯代码
服务端代码: import socket server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 使用固定端口 server_ ...
- cmd常用小命令
#设置n秒后自动关机 -a取消 shutdown -s -t n #输出内容到fileName里,如果文件不存在将会创建文件,>是替换,>>是追加echo something > ...