zoukankan      html  css  js  c++  java
  • 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多年的朋友,也没解决此问题-_-||


  • 相关阅读:
    顶级Kagglers的心得和技巧
    大数加法
    TensorFlow 2.0高效开发指南
    Java 8 特性 —— Stream
    Java 8 特性 —— 函数式接口
    Java 8 特性 —— 方法引用
    Java 8 特性 —— 默认方法和静态方法
    Java 8 特性 —— lambda 表达式
    Effective Java 读书笔记
    jQuery动态添加、删除按钮及input输入框
  • 原文地址:https://www.cnblogs.com/wugang/p/14232334.html
Copyright © 2011-2022 走看看