Spring 的宣告式事务管理依赖于它的AOP框架来完成,使用宣告式事务管理的好处是,事务管 理不侵入您所开发的组件,具体来说,您的DAO物件不会意识到正在事务 管理之中,事实上也 应当如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部份,如果您想要改变交 易管理策略的话,也只需要在定义档中重新组态 即可。
举个例子来说,可以将使 用 JdbcTemplate 修改一下,在不修改UserDAO类别的情况下,您可 以为它加入事务管理的服务,一个简化的方法是使用TransactionProxyFactoryBean,指 定要介入的事务管理对象及其方法,这需要在定义档案修改,如下所示:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN""http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:mysql://localhost:3306/demo</value> </property> <property name="username"> <value>caterpillar</value> </property> <property name="password"> <value>123456</value> </property> </bean> <bean id="transactionManager" class="org.springframework.jdbc. → datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref bean="dataSource"/> </property> </bean> <bean id="userDAO" class="onlyfun.caterpillar.UserDAO"> <property name="dataSource"> <ref bean="dataSource"/> </property> </bean> <bean id="userDAOProxy" class="org.springframework.transaction. → interceptor.TransactionProxyFactoryBean"> <property name="proxyInterfaces"> <list> <value>onlyfun.caterpillar.IUserDAO</value> </list> </property> <property name="target"> <ref bean="userDAO"/> </property> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> </beans>
TransactionProxyFactoryBean 需要一个 TransactionManager,由于这边使用 JDBC, 所以使用 DataSourceTransactionManager,TransactionProxyFactoryBean 是个代 理物件,"target"属 性指定要代理的对象,事务管理会自动介入指定的方法前后,这边是使 用"transactionAttributes"属性指定,insert*表示指定方 法名称 insert 开头的都要 纳入事务管理,您也可以指定方法全名,如果在方法执行过程中发生错误,则所有先前的操作自 动撤回,否则正常提交。
insert*等方法上指定了"PROPAGATION_REQUIRED",表示在目前的事务中执行操作,如果 交 易 不存在 就 建立一 个 新的, 相 关的常 数意 义都 可以 在 API 文件中 TransactionDefinition介面中找到。您可以加上多个事务定义,中间使用逗号 "," 区隔, 例如您可以加上唯读,或者是指定某个例外发生时撤回操作:
PROPAGATION_REQUIRED,readOnly,-MyCheckedException
MyCheckedException 前面加上"-"时,表示发生指定例外时撤消操作,如果前面加上"+", 表示发生例外时立即提交。 由于 userDAO 被 userDAOProxy 代理了,所以要作的是取得 userDAOProxy,而不是 userDAO,例如:
package onlyfun.caterpillar; import org.springframework.context.ApplicationContext; import org.springframework.context. support.FileSystemXmlApplicationContext; public class SpringDAODemo { public static void main(String[] args) { ApplicationContext context = new FileSystemXmlApplicationContext( "beans-config.xml"); User user = new User(); user.setName("caterpillar"); user.setAge(new Integer(30)); IUserDAO userDAO =(IUserDAO) context.getBean("userDAOProxy"); userDAO.insert(user); user = userDAO.find(new Integer(1)); System.out.println("name: " + user.getName()); } }
您也可以设定不同的 TransactionInterceptor 来得到更多的管理细节,例如:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN""http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:mysql://localhost:3306/demo</value> </property> <property name="username"> <value>caterpillar</value> </property> <property name="password"> <value>123456</value> </property> </bean> <bean id="transactionManager" class="org.springframework.jdbc. →?datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref bean="dataSource"/> </property> </bean> <bean id="userDAO" class="onlyfun.caterpillar.UserDAO"> <property name="dataSource"> <ref bean="dataSource"/> </property> </bean> <bean id="transactionInterceptor" class="org.springframework.transaction. →?interceptor.TransactionInterceptor"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="transactionAttributeSource"> <value> onlyfun.caterpillar.UserDAO. →?insert*=PROPAGATION_REQUIRED </value> </property> </bean> <bean id="userDAOProxy" class="org.springframework.aop. →?framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <list> <value>onlyfun.caterpillar.IUserDAO</value> </list> </property> <property name="target"> <ref bean="userDAO"/> </property> <property name="interceptorNames"> <value>transactionInterceptor</value> </property> </bean> </beans>
即使您后来不再需要事务管理,则直接在 Bean 定义档中修改配置即可,而不用修改程式进行重 新编译等动作。 宣告式事务管理是利用 Spring AOP 来达成,所以执行以上的程式时,请记得您的 Classpath设定中必须包括 spring-aop.jar。