Spring编程事务
编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate
事务超时
所谓事务超时,指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。
默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。
事务只读属性
只读事务用于客户代码只读但不修改数据的情形,“只读事务”并不是一个强制选项,只是一个“暗示”,提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。
Spring 框架中,最重要的事务管理的 API 有三个:TransactionDefinition、PlatformTransactionManager 和 TransactionStatus。 所谓事务管理,实质上就是按照给定的事务规则来执行提交或者回滚操作。其中,“给定的事务规则”是用 TransactionDefinition 表示的,“按照……来执行提交或者回滚操作”是用 PlatformTransactionManager 表示的,而 TransactionStatus 可以看作代表事务本身状态
PlatformTransactionManager 接口
Spring事务策略是通过PlatformTransactionManager接口体现的,该接口是Spring事务策略的核心。该接口的源代码如下:
public interface PlatformTransactionManager {
//平台无关的获得事务的方法
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
//平台无关的事务提交方法
void commit(TransactionStatus status) throws TransactionException;
//平台无关的事务回滚方法
void rollback(TransactionStatus status) throws TransactionException;
}
PlatformTransactionManager是一个与任何事务策略分离的接口。PlatformTransactionManager接口有许多不同的实现类,应用程序面向与平台无关的接口编程,而对不同平台的底层支持由PlatformTransactionManager接口的实现类完成,故而应用程序无须与具体的事务API耦合。因此使用PlatformTransactionManager接口,可将代码从具体的事务API中解耦出来。
在PlatformTransactionManager接口内,包含一个getTransaction(TransactionDefinition definition)方法,该方法根据一个TransactionDefinition参数,返回一个TransactionStatus对象。TransactionStatus对象表示一个事务,该事务可能是一个新的事务,也可能是一个已经存在的事务对象,这由TransactionDefinition所定义的事务规则所决定。
PlatformTransactionManager.getTransaction(…) 方法返回一个 TransactionStatus 对象,该对象可能代表一个新的或已经存在的事务(如果在当前调用堆栈有一个符合条件的事务)。TransactionStatus 接口提供一个简单的控制事务执行和查询事务状态的方法。该接口的源代码如下:
public interface TransactionStatus{ boolean isNewTransaction(); void setRollbackOnly(); boolean isRollbackOnly(); }
基于 TransactionTemplate 的编程式事务管理
TransactionTemplate 的 execute() 方法有一个 TransactionCallback 类型的参数,该接口中定义一个 doInTransaction() 方法,通常以匿名内部类的方式实现 TransactionCallback 接口,并在其 doInTransaction() 方法中书写业务逻辑代码。可以使用默认的事务提交和回滚规则,这样在业务代码中就不需要显式调用任何事务管理的 API。doInTransaction() 方法有一个TransactionStatus 类型的参数,可以在方法的任何位置调用该参数的 setRollbackOnly() 方法将事务标识为回滚的,以执行事务回滚。
TransactionCallback 接口有一个子接口 TransactionCallbackWithoutResult,该接口中定义一个 doInTransactionWithoutResult() 方法,TransactionCallbackWithoutResult 接口主要用于事务过程中不需要返回值的情况。当然,对于不需要返回值的情况,仍然可以使用 TransactionCallback 接口,并在方法中返回任意值即可。
Spring的核心事务管理对象是PlatformTransactionManager,只提供三个方法,有commit()和rollback()。有一个实现类AbstractPlatformTransactionManager,这个实现类也有两个实现类:
DataSourceTransactionManager:管理一个数据源,并且通过JDBC来完成对数据库的操作;
JtaTransactionManager:使用JTA进行事务管理;
Spring配置文件中,事务配置总是由三个组成部分,分别是DataSource、TransactionManager和 代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分
域对象
package com.smart.domain; public class Forum implements Serializable { private int forumId; private String forumName; private String forumDesc; public String getForumDesc() { return forumDesc; } public void setForumDesc(String forumDesc) { this.forumDesc = forumDesc; } public int getForumId() { return forumId; } public void setForumId(int forumId) { this.forumId = forumId; } public String getForumName() { return forumName; } public void setForumName(String forumName) { this.forumName = forumName; } public String toString(){ return ToStringBuilder.reflectionToString(this); } }
DAO层
package com.smart.dao; @Repository public class ForumDao { private JdbcTemplate jdbcTemplate; public void addForum(final Forum forum){ final String sql="insert into t_forum(forum_name,forum_desc) values (?,?)"; KeyHolder key = new GeneratedKeyHolder(); jdbcTemplate.update(new PreparedStatementCreator() { @Override public PreparedStatement createPreparedStatement(Connection con) throws SQLException { PreparedStatement ps = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); ps.setString(1,forum.getForumName()); ps.setString(2,forum.getForumDesc()); return ps; } },key); forum.setForumId(key.getKey().intValue()); System.out.println(forum); } @Autowired public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } }
Service层
package com.smart.service; @Service public class ForumService { private ForumDao forumDao; private TransactionTemplate template; public void addForum(final Forum forum){ template.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { forumDao.addForum(forum); } }); } @Autowired public void setForumDao(ForumDao forumDao) { this.forumDao = forumDao; } @Autowired public void setTemplate(TransactionTemplate template) { this.template = template; } }
applicationContext.xml
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context-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"> <context:component-scan base-package="com.smart"/> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}"/> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" p:dataSource-ref="dataSource"/> <bean id="template" class="org.springframework.transaction.support.TransactionTemplate" p:transactionManager-ref="txManager"/> <!--基于数据源的数据管理器--> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"/> </beans>
测试
package com.smart; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:applicationContext.xml"}) public class TestForumService extends AbstractTransactionalTestNGSpringContextTests { @Autowired private ForumService forumService; @Test public void testForumService(){ Forum forum = new Forum(); forum.setForumName("Jim"); forum.setForumDesc("okkk"); forumService.addForum(forum); } }
浙公网安备 33010602011771号