ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
考虑下面的接口和实现,这里使用了`Foo` 和 `Bar`集中事务的使用,不需要关注域对象.为了达到测试目的`DefaultFooService `会抛出`UnsupportedOperationException `让你看到事务的回滚. ~~~java //想要使用事务的接口 package x.y.service; public interface FooService { Foo getFoo(String fooName); Foo getFoo(String fooName, String barName); void insertFoo(Foo foo); void updateFoo(Foo foo); } ~~~ ~~~java // 上面接口的实现 package x.y.service; public class DefaultFooService implements FooService { public Foo getFoo(String fooName) { throw new UnsupportedOperationException(); } public Foo getFoo(String fooName, String barName) { throw new UnsupportedOperationException(); } public void insertFoo(Foo foo) { throw new UnsupportedOperationException(); } public void updateFoo(Foo foo) { throw new UnsupportedOperationException(); } } ~~~ 假设接口`FooService`前两个方法是事务只读的,后两个方法是事务读写的,配置如下: ~~~xml <!-- from the file 'context.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: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.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 想要使用事务的对象--> <bean id="fooService" class="x.y.service.DefaultFooService"/> <!-- 事务建议(发生了什么,可参看下面的<aop:advisor/>) --> <tx:advice id="txAdvice" transaction-manager="txManager"> <!-- the transactional semantics... --> <tx:attributes> <!-- 所有get开头的方法,只读--> <tx:method name="get*" read-only="true"/> <!-- 其他方法,使用默认事务,见下说明--> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- 确保上面的事务建议在FooService接口的所有方法上执行 --> <aop:config> <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/> </aop:config> <!-- 数据源配置 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/> <property name="username" value="scott"/> <property name="password" value="tiger"/> </bean> <!-- 驱动事务管理的 PlatformTransactionManager --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> </beans> ~~~ 这里的依赖关系,先有数据源dataSource,然后有依赖数据源的事务txManager, 然后有依赖事务的建议txAdvice,最后通过`<aop:config>`把建议和切点关联起来. >如果 `<tx:advice/>`的属性`transaction-manager`指向的`PlatformTransactionManager` 事务名称为`transactionManager`,则可以忽略这个属性,如果是其他值,必须明确指定. > 常见的需求是使整个业务层具有事务性。 最佳方法是更改切入点表达式以匹配业务层中的任何方法。 例如: ~~~xml <aop:config> <aop:pointcut id="fooServiceMethods" expression="execution(* x.y.service.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods"/> </aop:config> ~~~ 上面的配置会创建事务代理围绕着`fooService `的实现类.根据切点配置,调用了适当的代理方法,事务就会根据配置开启或暂停,或只读等等,看下面的测试过程 ~~~java public final class Boot { public static void main(final String[] args) throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("context.xml", Boot.class); FooService fooService = (FooService) ctx.getBean("fooService"); fooService.insertFoo (new Foo()); } } ~~~ log4j的日志输出信息如下 ~~~xml <!-- spring容器启动... --> [AspectJInvocationContextExposingAdvisorAutoProxyCreator] - Creating implicit proxy for bean 'fooService' with 0 common interceptors and 1 specific interceptors <!--DefaultFooService代理被创建 --> [JdkDynamicAopProxy] - Creating JDK dynamic proxy for [x.y.service.DefaultFooService] <!-- 调用代理对象的insertFoo(..) --> [TransactionInterceptor] - Getting transaction for x.y.service.FooService.insertFoo <!--交易的事务建议创建--> [DataSourceTransactionManager] - Creating new transaction with name [x.y.service.FooService.insertFoo] [DataSourceTransactionManager] - Acquired Connection [org.apache.commons.dbcp.PoolableConnection@a53de4] for JDBC transaction <!-- DefaultFooService 的insertFoo(..)方法抛出exception... --> [RuleBasedTransactionAttribute] - Applying rules to determine whether transaction should rollback on java.lang.UnsupportedOperationException [TransactionInterceptor] - Invoking rollback for transaction on x.y.service.FooService.insertFoo due to throwable [java.lang.UnsupportedOperationException] <!-- 事务回滚 (默认 RuntimeException导致回滚) --> [DataSourceTransactionManager] - Rolling back JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@a53de4] [DataSourceTransactionManager] - Releasing JDBC Connection after transaction [DataSourceUtils] - Returning JDBC Connection to DataSource Exception in thread "main" java.lang.UnsupportedOperationException at x.y.service.DefaultFooService.insertFoo(DefaultFooService.java:14) <!-- 为清晰起见,删除了AOP基础架构堆栈信息--> at $Proxy0.insertFoo(Unknown Source) at Boot.main(Boot.java:11) ~~~