Spring声明型事务管理示例详解
2012-02-14 16:59
302 查看
Spring不直接实现管理事务,它只是管理哪些方法需要有事务,通过AOP的方式调用底层的事务管理器进行事务管理.有需要事务管理的类是被Spring代理创建的,代理类通过在连接点前后插入预处理过程(开始事务)和后处理过程(commit或rollbak)实现事务管理.
Spring定义了事务管理器(PlatformTransactionManager)预处理应该有些什么样的方法,在声明了事务的方法被调用的时候,通过调用PlatformTransactionManager的commit(TransactionStatus status)或者rollback(TransactionStatus status),commit和rollback由具体的TransactionManager提供实现,如下图的DataSourceTransactionManager,其真正的事务管理仍然依靠Connection的commit或者rollback来完成.(图片来源于Spring
in Action)
一,先用示例来说明一个JDBC的DataSourceTransactionManager:代码结构为在DAO中访问DB,在Service类中访问DAO,事务配置在Service类上.
Spring的配置如下:
DAO类:
a,数据库插入两条数据,serv.testTX1作为一个整体的事务.
BuzSingleService serv =(BuzSingleService)ctx.getBean("buzSingleService");
serv.testTX1();
b,serv.testTX2()方法中有"运行时"异常(RuntimeException)抛出,由于调用者不是运行在事务中,serv.testTX1();和serv.testTX2();是相互独立的,仍然有两条数据插入数据库.
BuzSingleService serv =(BuzSingleService)ctx.getBean("buzSingleService");
serv.testTX1();
serv.testTX2();
c,testTX1方法改为如下,在插入第二条数据后抛出"运行时"异常.没有数据插入到数据库,testTX1内部的所有数据库操作处于同一个事务.
CheckedException 是一个用户自定义的异常:public class CheckedException extends Exception{}
BuzSingleService serv =(BuzSingleService)ctx.getBean("buzSingleService");
serv.testTX3();
e,在一个处于事务的方法中调用BuzSingleService的两个方法,被调用的两个方法会处于同一个事务中:
BuzMultipleService serv =(BuzMultipleService)ctx.getBean("buzMultipleService");
serv.testTX();
二,集成Hibernate后通过HibernateTransactionManager来进行事务管理的方法和JDBC类似,Spring的配置如下:
**在同一个配置文件可以配置多个TransactionManager,用于不同的事务,如一个hbtxManager(通过id指定)用于管理Hibernate事务,一个jmstxManager用于管理JMS事务.
3,管理JMS事务,这里的MQ是ActiveMQ,事务commit和rollback的特性和JDBC的示例相同.Spring的配置如下:
Spring定义了事务管理器(PlatformTransactionManager)预处理应该有些什么样的方法,在声明了事务的方法被调用的时候,通过调用PlatformTransactionManager的commit(TransactionStatus status)或者rollback(TransactionStatus status),commit和rollback由具体的TransactionManager提供实现,如下图的DataSourceTransactionManager,其真正的事务管理仍然依靠Connection的commit或者rollback来完成.(图片来源于Spring
in Action)
一,先用示例来说明一个JDBC的DataSourceTransactionManager:代码结构为在DAO中访问DB,在Service类中访问DAO,事务配置在Service类上.
Spring的配置如下:
<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" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-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/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" default-autowire="byName"> <bean id="jdbcTestDAO" class="com.test.spring.tx.jdbc.JDBCTestDAO"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="buzSingleService" class="com.test.spring.tx.jdbc.BuzSingleService"/> <bean id="buzMultipleService" class="com.test.spring.tx.jdbc.BuzMultipleService"/> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@147.151.240.XX:1521:ORCL" /> <property name="username" value="but" /> <property name="password" value="but" /> </bean> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <aop:config> <aop:pointcut id="serviceOperation" expression="execution(* com.test.spring.tx.jdbc.*Service*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" /> </aop:config> </beans>**事务配置为 expression="execution(* com.test.spring.tx.jdbc.*Service*.*(..))",表示com.test.spring.tx.jdbc包中类名带有Service的所有方法都要在事务中运行.
DAO类:
public class JDBCTestDAO { private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } public void testInsert(int id, String val) { this.jdbcTemplate.update("insert into A (ID, VAL) values (?, ?)", id, val); } public void testUpdate(int id, String val) { this.jdbcTemplate.update("update A set val = ? where id = ?", val, id); } public void testDelete(int id) { this.jdbcTemplate.update("delete from A where id=?", id); } }其中一个Service类如下:
public class BuzSingleService { @Autowired JDBCTestDAO jdbcTestDAO; public void testTX1() throws Exception { jdbcTestDAO.testInsert(0, "val0"); jdbcTestDAO.testInsert(1, "val1"); } public void testTX2() throws Exception { jdbcTestDAO.testInsert(2, "runtime exception nullpoint"); String nullStr = null; nullStr.length(); } public void testTX3() throws Exception { jdbcTestDAO.testInsert(3, "checked exception CheckedException"); throw new CheckedException(); } public JDBCTestDAO getJdbcTestDAO() { return jdbcTestDAO; } public void setJdbcTestDAO(JDBCTestDAO jdbcTestDAO) { this.jdbcTestDAO = jdbcTestDAO; } }对于这个Service类里的每一个方法如果被一个客户端代码调用(该客服端代码不是在Spring配置的事务中运行),那么每一个方法就是一个独立的事务(propagation="REQUIRED"配置决定的,这里只从整体上说明Spring的事务管理,不对propagation的其他配置情况做介绍).下面举一些例子,以下代码假定都是在其他的一个main函数中运行:
a,数据库插入两条数据,serv.testTX1作为一个整体的事务.
BuzSingleService serv =(BuzSingleService)ctx.getBean("buzSingleService");
serv.testTX1();
b,serv.testTX2()方法中有"运行时"异常(RuntimeException)抛出,由于调用者不是运行在事务中,serv.testTX1();和serv.testTX2();是相互独立的,仍然有两条数据插入数据库.
BuzSingleService serv =(BuzSingleService)ctx.getBean("buzSingleService");
serv.testTX1();
serv.testTX2();
c,testTX1方法改为如下,在插入第二条数据后抛出"运行时"异常.没有数据插入到数据库,testTX1内部的所有数据库操作处于同一个事务.
public void testTX1() throws Exception { jdbcTestDAO.testInsert(0, "val0"); jdbcTestDAO.testInsert(1, "val1"); String nullStr = null; nullStr.length(); }d,在默认情况下,抛出不是"运行时"异常类型的异常不会rollback事务.异常会被抛出到调用者,但是事务已经提交.
CheckedException 是一个用户自定义的异常:public class CheckedException extends Exception{}
BuzSingleService serv =(BuzSingleService)ctx.getBean("buzSingleService");
serv.testTX3();
e,在一个处于事务的方法中调用BuzSingleService的两个方法,被调用的两个方法会处于同一个事务中:
public class BuzMultipleService { @Autowired BuzSingleService buzSingleService; public void testTX() throws Exception { buzSingleService.testTX1(); buzSingleService.testTX2(); String nullStr = null; nullStr.length(); } public BuzSingleService getBuzSingleService() { return buzSingleService; } public void setBuzSingleService(BuzSingleService buzSingleService) { this.buzSingleService = buzSingleService; } }在一个main方法中如下调用,没有数据会被插入到数据库.因为BuzMultipleService.testTX方法处于事务中,buzSingleService.testTX1 和buzSingleService.testTX2在一个有事务的方法中被调用的话,它们形成一个整体的事务.(变化和propagation的设置有关系)
BuzMultipleService serv =(BuzMultipleService)ctx.getBean("buzMultipleService");
serv.testTX();
二,集成Hibernate后通过HibernateTransactionManager来进行事务管理的方法和JDBC类似,Spring的配置如下:
<bean id="plainHibernateDAO" class="com.test.spring.tx.hibernate.PlainHibernateDAO"> <property name="sessionFactory" ref="mySessionFactory" /> </bean> <bean id="hbSingleService" class="com.test.spring.tx.hibernate.HBSingleService"/> <bean id="hbMultipleService" class="com.test.spring.tx.hibernate.HBMultipleService"/> <bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:config/Hibernate.cfg.xml" /> </bean> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="mySessionFactory" /> </bean> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="hbOperation" expression="execution(* com.test.spring.tx.hibernate.*Service*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="hbOperation" /> </aop:config>需要注意的是在Hibernate的配置文件中不能指定 <property name="current_session_context_class">thread</property>
**在同一个配置文件可以配置多个TransactionManager,用于不同的事务,如一个hbtxManager(通过id指定)用于管理Hibernate事务,一个jmstxManager用于管理JMS事务.
3,管理JMS事务,这里的MQ是ActiveMQ,事务commit和rollback的特性和JDBC的示例相同.Spring的配置如下:
<bean id="jmsAccessor" class="com.test.spring.tx.jms.JmsAccessor"> <property name="jmsTemplate" ref="jmsTemplate"/> <property name="destination" ref="destination"/> </bean> <bean id="jmsSingleService" class="com.test.spring.tx.jms.JMSSingleService"/> <bean id="jmstxManager" class="org.springframework.jms.connection.JmsTransactionManager"> <property name="connectionFactory" ref="jmsConnectionFactory"/> </bean> <bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://localhost:61616"/> </bean> <bean id="destination" class="org.apache.activemq.command.ActiveMQQueue"> <constructor-arg index="0" value="example.yorker" /> </bean> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <property name="connectionFactory" ref="jmsConnectionFactory"/> <property name="defaultDestination" ref="destination"/> <property name="receiveTimeout" value="10000"/> </bean> <tx:advice id="jmstxAdvice" transaction-manager="jmstxManager"> <tx:attributes> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="jmsOperation" expression="execution(* com.test.spring.tx.jms.*Service*.*(..))" /> <aop:advisor advice-ref="jmstxAdvice" pointcut-ref="jmsOperation" /> </aop:config>JMS访问的JAVA类如下:
public class JmsAccessor { JmsTemplate jmsTemplate; Destination destination; public void send() { MessageCreator messageCreator = new MessageCreator() { public Message createMessage(Session session) { TextMessage message = null; try { message = session.createTextMessage("Hello message"); } catch (JMSException e) { e.printStackTrace(); } return message; } }; jmsTemplate.send(this.destination, messageCreator); } public void receive() { TextMessage message = (TextMessage) jmsTemplate.receive(); try { System.out.println("Message received:" + message.getText()); } catch (JMSException e) { e.printStackTrace(); } } public JmsTemplate getJmsTemplate() { return jmsTemplate; } public void setJmsTemplate(JmsTemplate jmsTemplate) { this.jmsTemplate = jmsTemplate; } public Destination getDestination() { return destination; } public void setDestination(Destination destination) { this.destination = destination; } }
相关文章推荐
- (转)使用Spring注解方式管理事务与传播行为详解
- spring的annotation-driven配置事务管理器详解
- Spring事务管理之编程式事务场景及使用详解
- spring的annotation-driven配置事务管理器详解
- spring管理事务详解
- Spring boot jpa 删除数据和事务管理的问题实例详解
- 使用Spring注解方式管理事务与传播行为详解
- JAVAWEB开发之Spring详解之——Spring事务管理详解(四种事务管理方式)
- 详解Spring学习之编程式事务管理
- spring的annotation-driven配置事务管理器详解
- Spring详解(七)------事务管理
- Spring的annotation-driven配置事务管理器详解
- 使用Spring注解方式管理事务与传播行为详解
- Spring详解之三:配置事务管理
- spring的annotation-driven配置事务管理器详解
- Spring中的事务管理实例详解
- Spring 数据加载和事务管理器配置注释详解
- Spring之旅、装配Bean、最小化Spring XML配置、面向切面的Spring、征服数据库、事务管理示例源代码
- Spring详解(八)------事务管理
- Spring中annotation-driven配置事务管理器详解