Spring 的事务管理不需要 与任何特定的事务API耦合。
Spring同时支持编程式事务策略和声明式事务策略,声明式事务管理的配置方法有下面四种:
1、使用TransactionProxyFactoryBean为目标Bean生成事务代理的配置。
2、采用Bean继承的事务代理配置方法。
3、采用BeanNameAutoProxyCreator , 根据Bean Name 自动生成事务代理的方式。这是直接利用Spring 的AOP框架配置事务代理的方式。
4、采用DefaultAdvisorAutoProxyCreator,直接利用Spring 的AOP框架配置事务代理的方式。
1、使用TransactionProxyFactoryBean为目标Bean生成事务代理的配置
采用这种方式的配置。每一个Bean需要两个Bean配置,一个是目标Bean,一个是使用TransactionProxyFactoryBean 配置的一个代理Bean。事务代理的方法改写了目标Bean的方法,就在目标Bean的方法执行前加入开始事务,在目标Bean的方法正常结束之前提交事务,如果遇到特定异常则回滚事务。
TransactionProxyFactoryBean 创建事务代理时,需要了解当时事务所处的环境,该该环境属性通过PlateTransactionManager 实例(其实现类的实例)传入,而相关事务规则则在该Bean定义中给出。
import javax.sql.DataSource; import java.sql.Connection; import org.springframework.jdbc.core.JdbcTemplate; /** * Description: * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a> * <br/>Copyright (C), 2001-2012, Yeeku.H.Lee * <br/>This program is protected by copyright laws. * <br/>Program Name: * <br/>Date: * @author Yeeku.H.Lee kongyeeku@163.com * @version 1.0 */ public class NewDaoImp1 implements NewDao { private DataSource ds; public void setDs(DataSource ds) { this.ds = ds; } public void insert(String title , String content) { JdbcTemplate jt = new JdbcTemplate(ds); jt.update("insert into news_inf" + " values(null , ? , ?)" , title , content); //两次插入的数据违反唯一键约束 jt.update("insert into news_inf" + " values(null , ? , ?)" , title , content); //如果增加事务控制,我们发现第一条记录也插不进去。 //如果没有事务控制,则第一条记录可以被插入 } }
如果在没有事务控制的环境下,前一条代码将会想数据库插入一条记录;但如果添加了事务控制的环境下,则这两条语句是一个整体,因为第二条语句插入失败
,所以将导致第一条语句插入的数据也被回滚。
并使用TransactionProxyFactoryBean为它配置事务代理:
<?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> ... <!-- 配置JDBC数据源的局部事务管理器,使用DataSourceTransactionManager 类 --> <!-- 该类实现PlatformTransactionManager接口,是针对采用数据源连接的特定实现--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 配置DataSourceTransactionManager时需要依注入DataSource的引用 --> <property name="dataSource" ref="dataSource"/> </bean> <!-- 配置一个业务逻辑Bean --> <bean id="newsDao" class="org.crazyit.app.dao.impl.NewsDaoImpl"> <property name="ds" ref="dataSource"/> </bean> <!-- 为业务逻辑Bean配置事务代理 --> <bean id="newsDaoTrans" class= "org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!-- 为事务代理工厂Bean注入事务管理器 --> <property name="transactionManager" ref="transactionManager"/> <property name="target" ref="newsDao"/> <!-- 指定事务属性 --> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> </beans>
配置事务代理时需要传入一个事务管理器、一个目标Bean,并指定该事务代理的事务属性,事务属性由transactionAttrubuters 属性指定。上面的事务属性只有一条事务传播规则,该规则指定对于所有方法都使用PROPAGATION_REQUIRED的传播规则。
PROPAGATION_REQUIRED:要求在事务环境中执行该方法,如果当前执行线程已处于事务中,则直接调用;如果当前执行线程不处于事务中,则启动新的事务后执行该方法。
package lee; import org.springframework.context.support.*; import org.springframework.context.*; import org.crazyit.app.dao.*; /** * Description: * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a> * <br/>Copyright (C), 2001-2012, Yeeku.H.Lee * <br/>This program is protected by copyright laws. * <br/>Program Name: * <br/>Date: * @author Yeeku.H.Lee kongyeeku@163.com * @version 1.0 */ public class SpringTest { public static void main(String[] args) { //创建Spring容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml"); //获取事务代理Bean NewsDao dao = (NewsDao)ctx .getBean("newsDaoTrans" , NewsDao.class); //执行插入操作 dao.insert("疯狂Java" , "轻量级Java EE企业应用实战"); } }
参考《轻量级java EE 企业应用实战》