Spring的事务管理(XML)

1.导包

blob.png

2.目标类

首先是dao

package com.kye.dao;

public interface AccountDao {
	void add(double money);

 
	int get();
}
package com.kye.daoImpl;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

import com.kye.dao.AccountDao;

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

	@Override
	public void add(double money) {
		this.getJdbcTemplate().update("update tb_account set money=money+?", money);
	}

	@Override
	public int get() {
		int result = this.getJdbcTemplate().queryForInt("select money from tb_account");
		return result;
	}

}

然后是service

package com.kye.service;

public interface AccountService {
	void transfer(int monehy);

	int get();
}
package com.kye.serviceImpl;

import com.kye.dao.AccountDao;
import com.kye.service.AccountService;

public class AccountServiceImpl implements AccountService {

	AccountDao dao;

	public void setDao(AccountDao dao) {
		this.dao = dao;
	}

	@Override
	public void transfer(int monehy) {
		dao.add(monehy);
		// int a = 1 / 0;
		if (1 == 1)
		    throw new RuntimeException();
		dao.add(monehy);
	}

	@Override
	public int get() {
		return dao.get();
	}

}

在transfer中,手动抛出运行时异常

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
	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/aop 
       					   http://www.springframework.org/schema/aop/spring-aop.xsd 
       					   http://www.springframework.org/schema/context 
       					   http://www.springframework.org/schema/context/spring-context.xsd 
       					   http://www.springframework.org/schema/tx 
       					   http://www.springframework.org/schema/tx/spring-tx.xsd">


	<!-- <bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl"
			value="jdbc:mysql://127.0.0.1/db"></property>
		<property name="user" value="root"></property>
		<property name="password" value="1234"></property>
	</bean> -->
	<bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"></property>
		<property name="jdbcUrl"
			value="jdbc:sqlserver://127.0.0.1:1433;DatabaseName=db"></property>
		<property name="user" value="sa"></property>
		<property name="password" value="sa123456"></property>
	</bean>

	<bean id="accountDao" class="com.kye.daoImpl.AccountDaoImpl">
		<property name="dataSource" ref="c3p0"></property>
	</bean>

	<bean id="service" class="com.kye.serviceImpl.AccountServiceImpl">
		<property name="dao" ref="accountDao"></property>
	</bean>

	<bean id="txManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="c3p0"></property>
	</bean>

	<tx:advice id="txAdvice" transaction-manager="txManager">
		<tx:attributes>
			<tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT" rollback-for="Exception"/>
		</tx:attributes>
	</tx:advice>

	<aop:config>
		<aop:advisor advice-ref="txAdvice"
			pointcut="execution(* com.kye.serviceImpl.AccountServiceImpl.*(..))" />
	</aop:config>
</beans>

最后junit测试

package com.kye.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.kye.service.AccountService;

public class MyTest {

	@Test
	public void Test() {

		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		AccountService service = context.getBean("service", AccountService.class);
		service.transfer(1);
		int result = service.get();
		System.out.println("result:" + result);
		 
	}
}

总结

在demo过程中,遇到了一个问题。就是在transfer中,最开始我是手动抛出Exception,结果导致事物不会滚。后来查看spring的运行机制才发现, 默认spring事务只在发生未被捕获的 runtimeexcetpion时才回滚。  

Spring aop异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获runtimeexception的异常,但可以通过配置来捕获特定的异常并回滚。换句话说在service的方法中不使用try catch 或者在catch中最后加上抛出运行时异常(RuntimeException),这样程序异常时才能被aop捕获进而回滚。

解决方案: 

1)例如service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw new RuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异常并处理

2)在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常

3)在事物管理器中,指定某些异常也回滚事物。例如:<tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT" rollback-for="MyException,ServletException,Exception"/>

遗留问题

使用mysql数据库无法回滚,同时也保证数据库是可以使用事物的,如下图

blob.png

换成sqlserver就没问题了,找了几个做Java多年的朋友,也没解决此问题-_-||


原文地址:https://www.cnblogs.com/wugang/p/14232334.html