续spring事务管理之前的话-spring编程式事务管理
在上一章节中,我们实践了事务管理如何在程序中进行维护,我们采用的是传统的手动设置事务的提交和回滚操作,那么srping在事务管理方面给我们带来了什么呢?首先spring为我们提供了两种事务管理的方式,声明式事务管理和编程式事务管理,大部分的应用开发者更倾向于前者,因为他应用程序代码实现了更高层次的解耦,编程式事务管理也有一些自己的优势,比如相比之下,他更容易在应用中做细粒度的事务管理,本篇文章尽量用实例和白话做编程式事务开发的示例。
public class TicketBookingServiceThroughPlatformManager extends JdbcDaoSupport{ private PlatformTransactionManager transactionManager; public void setTransactionManager(PlatformTransactionManager transactionManager){ this.transactionManager = transactionManager; } public void bookTicket(int userId, int ticketId, int noOfTickets){ TransactionDefinition transactionDefinition = new DefaultTransactionDefinition(); TransactionStatus status = transactionManager.getTransaction(transactionDefinition); try{ int accountId = TicketUtils.getAccountId(getJdbcTemplate(), userId); float ticketCost = TicketUtils.findTicketCost(getJdbcTemplate(), ticketId); float totalCost = (noOfTickets * ticketCost); TicketUtils.deductMoneyFromAccount(getJdbcTemplate(), accountId, totalCost); TicketUtils.reduceTicketCount(getJdbcTemplate(), ticketId, noOfTickets); transactionManager.commit(status); }catch (Exception e){ transactionManager.rollback(status); } } }
在上面的代码清单中,我们使用了编程式事务管理平台(PlatformTransactionManager)来进行事务的管理,这个平台是spring框架的编程式事务管理的核心api,这个类完成了对事务管理细节的封装,使应用开发者可以将精力集中在开发业务逻辑上。该平台事务管理类包含了数据源对数据库的连接,跟这个事务管理平台密切相关的对象是事务定义对象和事务状态对象
事务定义对象封装了事务属性比如 隔离级别、传播行为,超时。事务状态对象代表事务执行的状态,开始状态或者完成状态,在方法的开始,我们从事务定义对象中获取了一个事务状态对象,在成功的场景(scenario)事务将在状态对象中被commit,否则回滚
public class Main { public static void main(String[] args) { ApplicationContext context = Utils.getContext(); TicketBookingServiceThroughPlatformManager service = new TicketBookingServiceThroughPlatformManager(); DataSource dataSource = (DataSource)context.getBean("myOralceDataSource"); service.setDataSource(dataSource); PlatformTransactionManager transactionManager = (PlatformTransactionManager)context.getBean("transactionManager"); service.setTransactionManager(transactionManager); service.bookTicket(1, 2, 3); } }
客户端代码创建一个恰当的服务对象,并且在调用bookTicket()方法之前设置恰当的数据源和事务管理对象 。这个bean在xml中的定义如下:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="myOralceDataSource" /> </bean>
控制台输出:
2012-10-24 11:54:39 org.springframework.context.support.AbstractApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@171bbc9: display name [org.springframework.context.support.ClassPathXmlApplicationContext@171bbc9]; startup date [Wed Oct 24 11:54:39 CST 2012]; root of context hierarchy 2012-10-24 11:54:39 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [main.xml] 2012-10-24 11:54:39 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory 信息: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@171bbc9]: org.springframework.beans.factory.support.DefaultListableBeanFactory@b6e39f 2012-10-24 11:54:39 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@b6e39f: defining beans [myOralceDataSource,transactionManager]; root of factory hierarchy 2012-10-24 11:54:39 org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName 信息: Loaded JDBC driver: oracle.jdbc.driver.OracleDriver Key值是 - ID, Value值是 - 1 Key值是 - NAME, Value值是 - 华为 Key值是 - TICKETID, Value值是 - 32 Key值是 - ACCOUNTID, Value值是 - 22 *******************************************-1 Key - ID, Value - 2 Key - MOVIENAME, Value - 精武风云 Key - TOTALTICKETSCOUNT, Value - 197
编程式事务管理之事务模板
下面我们介绍一下实现了更高一层封装的事务模版类,这个部分我们将通过TransactionTemplate类替换事务管理的方式,像其他spring众多的模板类一样,这个类被用来简化事务管理的工作,注意下边的类TicketBookingService类似于上部分的类,但是不同的是他完全没有了与事务关联的代码像(commit 、rollback)。
public class TicketBookingServiceThroughTemplate extends JdbcDaoSupport{ private PlatformTransactionManager transactionManager; public void setTransactionManager(PlatformTransactionManager transactionManager){ this.transactionManager = transactionManager; } public void bookTicket(int userId, int ticketId, int noOfTickets){ TransactionTemplate template = new TransactionTemplate(transactionManager); BookingTransactionCallback callback = new BookingTransactionCallback(this, userId, ticketId, noOfTickets); template.execute(callback); } }
上面的类将所有的操作委托给BookingTransactionCallback,这个类我们将在下边讨论:
public class BookingTransactionCallback extends TransactionCallbackWithoutResult{ private JdbcDaoSupport daoSupport; private int userId; private int ticketId; private int noOfTickets; public BookingTransactionCallback(JdbcDaoSupport daoSupport, int userId, int ticketId, int noOfTickets){ this.daoSupport = daoSupport; this.userId = userId; this.ticketId = ticketId; this.noOfTickets = noOfTickets; } @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { int accountId = TicketUtils.getAccountId(daoSupport.getJdbcTemplate(), userId); float ticketCost = TicketUtils.findTicketCost(daoSupport.getJdbcTemplate(), ticketId); float totalCost = (noOfTickets * ticketCost); TicketUtils.deductMoneyFromAccount(daoSupport.getJdbcTemplate(), accountId, totalCost); TicketUtils.reduceTicketCount(daoSupport.getJdbcTemplate(), ticketId, noOfTickets); } }
这里有两种类型的TransactionTemplate类,一种返回结果(TransactionCallback ),一种不返回结果(TransactionCallbackWithoutResult)在我们的例子中我们不需要返回任何结果,因此我们继承TransactionCallbackWithoutResult客户端应用程序加载上下文、事务管理引用和数据源对象的定义如下:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="myOralceDataSource" /> </bean>
测试输出:
2012-10-24 12:47:33 org.springframework.context.support.AbstractApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@8fce95: display name [org.springframework.context.support.ClassPathXmlApplicationContext@8fce95]; startup date [Wed Oct 24 12:47:33 CST 2012]; root of context hierarchy 2012-10-24 12:47:33 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [main.xml] 2012-10-24 12:47:34 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory 信息: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@8fce95]: org.springframework.beans.factory.support.DefaultListableBeanFactory@c05d3b 2012-10-24 12:47:34 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@c05d3b: defining beans [myOralceDataSource,transactionManager]; root of factory hierarchy 2012-10-24 12:47:34 org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName 信息: Loaded JDBC driver: oracle.jdbc.driver.OracleDriver Key值是 - ID, Value值是 - 1 Key值是 - NAME, Value值是 - 华为 Key值是 - TICKETID, Value值是 - 32 Key值是 - ACCOUNTID, Value值是 - 22 *******************************************-1 Key - ID, Value - 1 Key - MOVIENAME, Value - 精武风云 Key - TOTALTICKETSCOUNT, Value - 193
通过上面的章节我们可以看到spring给我们带来的事务管理的改变。
北京市海淀区
邮箱:rafx_z@hotmail.com