一、编程式事务管理
事务属性包含了5个方面,如图所示: 下面详细介绍一下各个事务属性:
1.1 传播行为事务的第一个方面是传播行为(propagation behavior)。当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。Spring定义了七种传播行为:
案例:
1.2 隔离级别事务的第二个维度就是隔离级别(isolation level)。隔离级别定义了一个事务可能受其他并发事务影响的程度。
不可重复读与幻读的区别 不可重复读的重点是修改: con1 = getConnection();
select salary from employee empId ="Mary";
在事务2中,这时财务人员修改了Mary的工资为2000,并提交了事务. con2 = getConnection(); update employee set salary = 2000; con2.commit(); 在事务1中,Mary 再次读取自己的工资时,工资变为了2000 //con1 select salary from employee empId ="Mary"; 在一个事务中前后两次读取的结果并不一致,导致了不可重复读。 幻读的重点在于新增或者删除: con1 = getConnection();
Select * from employee where salary =1000;
共读取10条记录 这时另一个事务向employee表插入了一条员工记录,工资也为1000 con2 = getConnection(); Insert into employee(empId,salary) values("Lili",1000); con2.commit(); 事务1再次读取所有工资为1000的员工 //con1 select * from employee where salary =1000; 共读取到了11条记录,这就产生了幻像读。 从总的结果来看, 似乎不可重复读和幻读都表现为两次读取的结果不一致。但如果你从控制的角度来看, 两者的区别就比较大。
(2)隔离级别
1.3 只读事务的第三个特性是它是否为只读事务。如果事务只对后端的数据库进行该操作,数据库可以利用事务的只读特性来进行一些特定的优化。通过将事务设置为只读,你就可以给数据库一个机会,让它应用它认为合适的优化措施。 1.4 事务超时为了使应用程序很好地运行,事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定,所以长时间的事务会不必要的占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。 1.5 回滚规则事务五边形的最后一个方面是一组规则,这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的)
1.6 事务状态上面讲到的调用PlatformTransactionManager接口的getTransaction()的方法得到的是TransactionStatus接口的一个实现,这个接口的内容如下: public interface TransactionStatus{ boolean isNewTransaction(); // 是否是新的事物 boolean hasSavepoint(); // 是否有恢复点 void setRollbackOnly(); // 设置为只回滚 boolean isRollbackOnly(); // 是否为只回滚 boolean isCompleted; // 是否已完成 } 可以发现这个接口描述的是一些处理事务提供简单的控制事务执行和查询事务状态的方法,在回滚或提交的时候需要应用对应的事务状态。
二、案例
package transaction_1; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import util.DBUtil; /** * 一个方法内的的事务管理 * @author 半颗柠檬、 * */ public class UserDao_1 { public void insert_1(){ Connection conn=null; Statement stat=null; StringBuffer SQL=new StringBuffer(); try { /** * 插入到user表 */ conn=DBUtil.getConn(); SQL.append("insert into user values('111',11,'11')"); conn.setAutoCommit(false); stat=conn.createStatement(); stat.executeUpdate(SQL.toString()); /** * 插入到角色表 */ SQL.setLength(0); SQL.append("insert into role1 values(3,'普通用户','普通用户备注')"); stat.executeUpdate(SQL.toString()); //全部正确则提交 conn.commit(); } catch (Exception e) { //出现异常则回滚 e.printStackTrace(); try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } }finally{ //释放资源 } } public static void main(String[] args) { UserDao_1 userDao_1=new UserDao_1(); userDao_1.insert_1(); } }
解决方法 :方法 1. 将Conenction作为参数传到两个方法中 方法 2. 将Connection放到ThreadLocal中管理 UserDao_2.java package transaction_1; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import util.DBUtil; /** * 一个类中两个方法事务管理(本例中采用方法2) * 解决方法: 方法 1. 将Conenction作为参数传到两个方法中 * 方法 2. 将Connection放到ThreadLocal中管理
package util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtil { private static ThreadLocal<Connection> local=new ThreadLocal<Connection>(); private static final String DRIVER="com.mysql.jdbc.Driver"; private static final String USER="root"; private static final String PASSWD=""; private static final String URL="jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=UTF-8"; static{ try { Class.forName(DRIVER); } catch (Exception e) { throw new RuntimeException("无法加载驱动包"); } } public static Connection getConn(){ Connection conn=null; try { if(local.get() !=null ){ conn=local.get(); }else{ conn= DriverManager.getConnection(URL,USER,PASSWD); local.set(conn); } } catch (SQLException e) { e.printStackTrace(); } return conn; } }
package transaction_2; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.support.JdbcDaoSupport; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; /** * 编程式事务:无法在多个方法或者多个类中,共享一个事务。 * 本例中update_1方法和update_2方法没有办法共享同一个事务,即执行update方法,如果update_2出现异常,那么update_1还是会执行,不会被回滚。 * @author 半颗柠檬、 * */ public class UserDao_TransactionManager extends JdbcDaoSupport{ private void update() { this.update_1(); this.update_2(); } public void update_1(){ //创建事务的平台管理器 PlatformTransactionManager transactionManager=new DataSourceTransactionManager(this.getDataSource()); //定义事务的属性 DefaultTransactionDefinition definition=new DefaultTransactionDefinition(); //设置超时时间 definition.setTimeout(1000); //设置不只读 definition.setReadOnly(false); //设置事务隔离级别 definition.setIsolationLevel(DefaultTransactionDefinition.ISOLATION_READ_UNCOMMITTED); //设置事务的传播属性 definition.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); //获取事务的状态 TransactionStatus status=transactionManager.getTransaction(definition); try { //执行语句 this.getJdbcTemplate().update("update user set age=11 where userName='张三'"); this.getJdbcTemplate().update("update user set age=22 where userName='李四'"); transactionManager.commit(status); } catch (Exception e) { e.printStackTrace(); }finally{ //释放资源 } } public void update_2(){ //创建事务的平台管理器 PlatformTransactionManager transactionManager=new DataSourceTransactionManager(this.getDataSource()); //定义事务的属性 DefaultTransactionDefinition definition=new DefaultTransactionDefinition(); //设置超时时间 definition.setTimeout(1000); //设置不只读 definition.setReadOnly(false); //设置事务隔离级别 definition.setIsolationLevel(DefaultTransactionDefinition.ISOLATION_READ_UNCOMMITTED); //设置事务的传播属性 definition.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); //获取事务的状态 TransactionStatus status=transactionManager.getTransaction(definition); try { //执行语句 this.getJdbcTemplate().update("update user set sex='男' where userName='张三'"); this.getJdbcTemplate().update("update user1 set sex='男' where userName='李四'"); transactionManager.commit(status); } catch (Exception e) { e.printStackTrace(); }finally{ //释放资源 } } public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml"); UserDao_TransactionManager dao_TransactionManager=(UserDao_TransactionManager)context.getBean("UserDao_TransactionManager"); dao_TransactionManager.update(); } } spring.xml <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <constructor-arg index="0" name="driverClassName" value="com.mysql.jdbc.Driver" ></constructor-arg> <constructor-arg index="1" name="url" value="jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=UTF-8" ></constructor-arg> <constructor-arg index="2" name="username" value="root"></constructor-arg> <constructor-arg index="3" name="password" value=""></constructor-arg> </bean> <bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg name="dataSource" ref="dataSource"></constructor-arg> </bean> <bean id="UserDao_TransactionManager" class="transaction_2.UserDao_TransactionManager"> <property name="jdbcTemplate" ref="jdbctemplate"></property> </bean>
UserDao_TransactionManager_2.java package transaction_2; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.support.JdbcDaoSupport; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; /** * 编程式事务:无法在多个方法或者多个类中,共享一个事务。 * 本例中update_1方法和update_2方法没有办法共享同一个事务。即如果update方法里的update_2出现异常,那么update_1方法不会回滚。 * @author 半颗柠檬、 * */ public class UserDao_TransactionManager_2 extends JdbcDaoSupport{ /** * 此方法中将一个平台事务管理器作为参数传到方法里,但仍旧无法使这两个方法共享一个事务。 */ private void update() { PlatformTransactionManager platformTransactionManager=new DataSourceTransactionManager(this.getDataSource()); this.update_1(platformTransactionManager); this.update_2(platformTransactionManager); } public void update_1(PlatformTransactionManager platformTransactionManager ){ //创建事务的平台管理器 //定义事务的属性 DefaultTransactionDefinition definition=new DefaultTransactionDefinition(); //设置超时时间 definition.setTimeout(1000); //设置不只读 definition.setReadOnly(false); //设置事务隔离级别 definition.setIsolationLevel(DefaultTransactionDefinition.ISOLATION_READ_UNCOMMITTED); //设置事务的传播属性 definition.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); //获取事务的状态 TransactionStatus status=platformTransactionManager.getTransaction(definition); try { //执行语句 this.getJdbcTemplate().update("update user set age=11 where userName='张三'"); this.getJdbcTemplate().update("update user set age=11 where userName='李四'"); platformTransactionManager.commit(status); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); }finally{ //释放资源 } } public void update_2(PlatformTransactionManager platformTransactionManager){ //定义事务的属性 DefaultTransactionDefinition definition=new DefaultTransactionDefinition(); //设置超时时间 definition.setTimeout(1000); //设置不只读 definition.setReadOnly(false); //设置事务隔离级别 definition.setIsolationLevel(DefaultTransactionDefinition.ISOLATION_READ_UNCOMMITTED); //设置事务的传播属性 definition.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); //获取事务的状态 TransactionStatus status=platformTransactionManager.getTransaction(definition); try { //执行语句 this.getJdbcTemplate().update("update user set sex='女' where userName='张三'"); this.getJdbcTemplate().update("update user set sex='女' where userName='李四'"); platformTransactionManager.commit(status); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); }finally{ //释放资源 } } public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml"); UserDao_TransactionManager_2 dao_TransactionManager=(UserDao_TransactionManager_2)context.getBean("UserDao_TransactionManager_2"); dao_TransactionManager.update(); } } spring.xml <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <constructor-arg index="0" name="driverClassName" value="com.mysql.jdbc.Driver" ></constructor-arg> <constructor-arg index="1" name="url" value="jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=UTF-8" ></constructor-arg> <constructor-arg index="2" name="username" value="root"></constructor-arg> <constructor-arg index="3" name="password" value=""></constructor-arg> </bean> <bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg name="dataSource" ref="dataSource"></constructor-arg> </bean> <bean id="UserDao_TransactionManager_2" class="transaction_2.UserDao_TransactionManager_2"> <property name="jdbcTemplate" ref="jdbctemplate"></property> </bean>
package transaction_2; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.support.JdbcDaoSupport; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; /** * 使用声明式事务 * 本例中使用第一种声明式事务,可以实现在多个方法或者多个类中,共享一个事务。即如果update方法里的update_2出现异常,那么update_1方法回滚。 * @author 半颗柠檬、 * */ public class UserDao_TransactionManager_3 extends JdbcDaoSupport implements UserDao_Interface{ public void update() { this.update_1(); this.update_2(); } public void update_1(){ this.getJdbcTemplate().update("update user set age=111 where userName='张三'"); this.getJdbcTemplate().update("update user set age=221 where userName='李四'"); } public void update_2(){ this.getJdbcTemplate().update("update user set sex='女1' where userName='张三'"); this.getJdbcTemplate().update("update user1 set sex='女1' where userName='李四'"); } public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml"); UserDao_Interface userDao_Interface=(UserDao_Interface)context.getBean("UserDao_TransactionManager_3_proxy"); userDao_Interface.update(); } } spring.xml <bean id="UserDao_TransactionManager_3" class="transaction_2.UserDao_TransactionManager_3"> <property name="jdbcTemplate" ref="jdbctemplate"></property> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="UserDao_TransactionManager_3_proxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="target" ref="UserDao_TransactionManager_3"></property> <property name="transactionManager" ref="transactionManager"></property> <property name="transactionAttributes"> <props> <!-- update*方法使用的是同一个事务,因为传播属性为PROPAGATION_REQUIRED,有事务则使用本事务,没有事务则创建一个新事务 --> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="add*">PROPAGATION_REQUIRED</prop> <prop key="delete*">PROPAGATION_REQUIRED</prop> <prop key="list*">readOnly</prop> </props> </property> </bean>
package transaction_2; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.support.JdbcDaoSupport; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; /** * 编程式事务:无法在多个方法或者多个类中,共享一个事务。 * 本例中使用第二种声明式事务,可以实现在多个方法或者多个类中,共享一个事务。即如果update方法里的update_2出现异常,那么update_1方法回滚。 * @author 半颗柠檬、 * */ public class UserDao_TransactionManager_4 extends JdbcDaoSupport implements UserDao_Interface{ public void update() { this.update_1(); this.update_2(); } public void update_1(){ this.getJdbcTemplate().update("update user set age=111 where userName='张三'"); this.getJdbcTemplate().update("update user set age=221 where userName='李四'"); } public void update_2(){ this.getJdbcTemplate().update("update user set sex='女1' where userName='张三'"); this.getJdbcTemplate().update("update user set sex='女1' where userName='李四'"); } public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml"); UserDao_Interface userDao_Interface=(UserDao_Interface)context.getBean("UserDao_TransactionManager_4"); userDao_Interface.update(); } } spring.xml <bean id="baseProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"> <!-- false:只能针对接口做代理。true表示可以对接口和类做代理 --> <property name="proxyTargetClass" value="true"></property> <property name="transactionManager" ref="transactionManager"></property> <property name="transactionAttributes"> <props> <prop key="update*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <bean id="UserDao_TransactionManager_4" parent="baseProxy"> <property name="target" > <bean class="transaction_2.UserDao_TransactionManager_4"> <property name="jdbcTemplate" ref="jdbctemplate"></property> </bean> </property> </bean>
UserDao_TransactionManager_5.java package transaction_3; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.support.JdbcDaoSupport; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; import transaction_2.UserDao_Interface; /** * 编程式事务:无法在多个方法或者多个类中,共享一个事务。 * 本例中使用第三种声明式事务,可以实现在多个方法或者多个类中,共享一个事务。即如果update方法里的update_2出现异常,那么update_1方法回滚。 * @author 半颗柠檬、 * */ public class UserDao_TransactionManager_5 extends JdbcDaoSupport implements UserDao_Interface{ public void update() { this.update_1(); this.update_2(); } public void update_1(){ this.getJdbcTemplate().update("update user set age=111 where userName='张三'"); this.getJdbcTemplate().update("update user set age=221 where userName='李四'"); } public void update_2(){ this.getJdbcTemplate().update("update user set sex='女1' where userName='张三'"); this.getJdbcTemplate().update("update user1 set sex='女1' where userName='李四'"); } public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml"); UserDao_Interface userDao_Interface=(UserDao_Interface)context.getBean("UserDao_TransactionManager_5"); userDao_Interface.update(); } } spring.xml <!-- id为advice_1的事务,其管理器为transactionManager --> <tx:advice id="advice_1" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="append*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="modify*" propagation="REQUIRED" /> <tx:method name="edit*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="repair" propagation="REQUIRED" /> <tx:method name="delAndRepair" propagation="REQUIRED" /> <tx:method name="get*" propagation="SUPPORTS" /> <tx:method name="find*" propagation="SUPPORTS" /> <tx:method name="load*" propagation="SUPPORTS" /> <tx:method name="search*" propagation="SUPPORTS" /> <tx:method name="datagrid*" propagation="SUPPORTS" /> <tx:method name="*" propagation="SUPPORTS" /> </tx:attributes> </tx:advice> <aop:config> <!-- Pointcut 是指那些方法需要被执行"AOP",是由"Pointcut Expression"来描述的. --> <aop:pointcut expression="execution(* transaction_3.*.*(..))" id="point_1"/> <aop:advisor advice-ref="advice_1" pointcut-ref="point_1"/> </aop:config> <bean id="UserDao_TransactionManager_5" class="transaction_3.UserDao_TransactionManager_5"> <property name="jdbcTemplate" ref="jdbctemplate"></property> </bean>
包里的任意子类中的任意方法(参数也是任意)。
其中execution 是用的最多的,其格式为:
UserDao_TransactionManager_6.java package transaction_3; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.support.JdbcDaoSupport; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; import dao.RoleDao; import dao.UserDao; import transaction_2.UserDao_Interface; /** * 本例中使用第三种声明式事务,实现在者多个类中,共享一个事务。即如果Roledao类的update_2方法异常,则Userdao类的update_1也进行回滚操作 * <aop:pointcut expression="execution(* transaction_3.*.*(..))" id="point_1"/> 中的事务定义一定要在service层(本例中为transaction_3包), * 才能共享一个事务,如果expression="execution(* dao.*.*(..))" 则无法共享事务 * @author 半颗柠檬、 * */ public class UserDao_TransactionManager_6 extends JdbcDaoSupport implements UserDao_Interface{ private UserDao userdao; private RoleDao roledao; public void setUserdao(UserDao userdao) { this.userdao = userdao; } public void setRoledao(RoleDao roledao) { this.roledao = roledao; } public void update() { userdao.update_1(); roledao.update_2(); } public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml"); UserDao_Interface userDao_Interface=(UserDao_Interface)context.getBean("UserDao_TransactionManager_6"); userDao_Interface.update(); } } UserDao.java package dao; import org.springframework.jdbc.core.support.JdbcDaoSupport; public class UserDao extends JdbcDaoSupport{ public void update_1(){ this.getJdbcTemplate().update("update user set age=111 where userName='张三'"); this.getJdbcTemplate().update("update user set age=111 where userName='李四'"); } } RoleDao.java package dao; import org.springframework.jdbc.core.support.JdbcDaoSupport; public class RoleDao extends JdbcDaoSupport { public void update_2(){ this.getJdbcTemplate().update("update role set role_name='aa' where role_id=1 "); this.getJdbcTemplate().update("update role1 set role_name='bb' where role_id=2 "); } } spring.xml <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <constructor-arg index="0" name="driverClassName" value="com.mysql.jdbc.Driver" ></constructor-arg> <constructor-arg index="1" name="url" value="jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=UTF-8" ></constructor-arg> <constructor-arg index="2" name="username" value="root"></constructor-arg> <constructor-arg index="3" name="password" value=""></constructor-arg> </bean> <bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg name="dataSource" ref="dataSource"></constructor-arg> </bean> <!-- Spring事务的第3种配置方式,使用Spring中拦截器的方式 --> <!-- id为advice_1的事务,其管理器为transactionManager --> <tx:advice id="advice_1" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="append*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="modify*" propagation="REQUIRED" /> <tx:method name="edit*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="repair" propagation="REQUIRED" /> <tx:method name="delAndRepair" propagation="REQUIRED" /> <tx:method name="get*" propagation="SUPPORTS" /> <tx:method name="find*" propagation="SUPPORTS" /> <tx:method name="load*" propagation="SUPPORTS" /> <tx:method name="search*" propagation="SUPPORTS" /> <tx:method name="datagrid*" propagation="SUPPORTS" /> <tx:method name="*" propagation="SUPPORTS" /> </tx:attributes> </tx:advice> <aop:config proxy-target-class="true"> <!-- Pointcut 是指那些方法需要被执行"AOP",是由"Pointcut Expression"来描述的. --> <aop:pointcut expression="execution(* transaction_3.*.*(..))" id="point_1"/> <aop:advisor advice-ref="advice_1" pointcut-ref="point_1"/> </aop:config> <!-- end --> <!-- UserDao_TransactionManager_6 配置 --> <bean id="userdao" class="dao.UserDao"> <property name="jdbcTemplate" ref="jdbctemplate"></property> </bean> <bean id="roledao" class="dao.RoleDao"> <property name="jdbcTemplate" ref="jdbctemplate"></property> </bean> <bean id="UserDao_TransactionManager_6" class="transaction_3.UserDao_TransactionManager_6"> <property name="roledao" ref="roledao"></property> <property name="userdao" ref="userdao"></property> <property name="jdbcTemplate" ref="jdbctemplate"></property> </bean> <!-- end --> 路径如图:
spring aop异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获runtimeexception的异常,但可以通过 配置来捕获特定的异常并回滚
方案1.例如service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw new
RuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异常并处理
|
|