zoukankan      html  css  js  c++  java
  • 注解方式实现声明式事务管理

    使用注解实现Spring的声明式事务管理,更加简单!

    步骤:

             1) 必须引入Aop相关的jar文件

             2) bean.xml中指定注解方式实现声明式事务管理以及应用的事务管理器类

             3)在需要添加事务控制的地方,写上: @Transactional

    @Transactional注解:

             1)应用事务的注解

             2)定义到方法上: 当前方法应用spring的声明式事务

             3)定义到类上:   当前类的所有的方法都应用Spring声明式事务管理;

             4)定义到父类上: 当执行父类的方法时候应用事务。

    修改bean.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:p="http://www.springframework.org/schema/p"
    	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/context
             http://www.springframework.org/schema/context/spring-context.xsd
             http://www.springframework.org/schema/aop
             http://www.springframework.org/schema/aop/spring-aop.xsd
             http://www.springframework.org/schema/tx
         	 http://www.springframework.org/schema/tx/spring-tx.xsd">
    	
    	<!-- 1、数据源对象:C3P0连接池 -->
    	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    		<property name="driverClass" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"></property>
    		<property name="jdbcUrl" value="jdbc:sqlserver://localhost:1433;DataBaseName=Test"></property>
    		<property name="user" value="sa"></property>
    		<property name="password" value="123456"></property>
    		<property name="initialPoolSize" value="3"></property>
    		<property name="maxPoolSize" value="11"></property>
    		<property name="maxStatements" value="50"></property>
    		<property name="acquireIncrement" value="2"></property>
    	</bean>
    	
    	<!-- 2、创建JdbcTemplate对象 -->
    	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    		<constructor-arg ref="dataSource"></constructor-arg>
    		<!-- 或者<property name="dataSource" ref="dataSource"></property> -->
    	</bean>
    	
    	<!-- 3、开启注解扫描 -->
    	<context:component-scan base-package="cn.gqx.b_anno"></context:component-scan>
    	
    	<!-- 4、注解方式实现事物 -->
    	<!-- 事物管理器类 -->
    	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<property name="dataSource" ref="dataSource"></property>
    	</bean>
    	<tx:annotation-driven transaction-manager="txManager"/>
    </beans>
         
    

    DeptService如下

    @Service
    public class DeptService {
    	//接受容器注入的dao
    	@Resource
    	private DeptDao deptDao;
    
    	//事物控制注解
    	@Transactional(
    			readOnly=false,	//读写事物
    			timeout=-1,		//事物的超时时间不限制
    			//noRollbackFor=ArithmeticException.class	//遇到数学异常不回滚
    			rollbackFor=ArithmeticException.class,	//只回滚数学异常,指定更加精确
    			isolation=Isolation.DEFAULT,		//事物的隔离级别,数据库的默认
    			/*
    			 * DEFAULT  使用后端数据库默认的隔离级别(spring中的的选择项)
    			 * READ_UNCOMMITED 允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读
    			 * READ_COMMITTED 允许在并发事务已经提交后读取。可防止脏读,但幻读和 不可重复读仍可发生
    			 * REPEATABLE_READ  对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生。
    			 * SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。
    			 * 这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。
    			 */
    			propagation=Propagation.REQUIRES_NEW
    			/*Propagation.REQUIRED
    			 * 指当前方法必须在事物的环境下执行
    			 * 如果当前运行的方法,已经存在事物,就会加入到当前事物
    			 * Propagation.REQUIRES_NEW类似
    			 * 指当前方法必须在事物的环境下执行;
    			 * 如果当前运行的方法,已经存在事物,事物会挂起,始终开始一个新的事物
    			 * 执行完后,刚才挂起的事物才继续运行
    			 * 
    			 * 举例保存部门前要插入日志
    			 * 不管是否将部门保存成功,都需要写入日志,这个时候要用REQUIRES_NEW
    			 */
    			
    	)
    		
    	public void save(Dept dept){
    		//第一次调用
    		deptDao.save(dept);
    
    		// 模拟异常,此时整个service.save()执行成功的时候要回滚
    		int i=1/0;
    
    		//第二次调用
    		deptDao.save(dept);
    	}
    }
    

    对propagation=Propagation.REQUIRES_NEW/Propagation.REQUIRED的测试

    不管是否将部门保存成功,都需要写入日志,这个时候要用REQUIRES_NEW

    Propagation.REQUIRED

                       指定当前的方法必须在事务的环境下执行;

                       如果当前运行的方法,已经存在事务, 就会加入当前的事务;

             Propagation.REQUIRED_NEW

                       指定当前的方法必须在事务的环境下执行;

                       如果当前运行的方法,已经存在事务:  事务会挂起; 会始终开启一个新的事务,执行完后;  刚才挂起的事务才继续运行。

    创建logDao

    //测试,日志传播行为
    @Repository
    public class LogDao {
    	@Resource
    	private JdbcTemplate jdbcTemplate;
    	@Transactional(propagation=Propagation.REQUIRES_NEW)
    	public void save() {
    		jdbcTemplate.update("insert into t_log values('保存数据了')");
    	}
    }
    

    这个时候的DeptService如下

    @Service
    public class DeptService {
    	//接受容器注入的dao
    	@Resource
    	private DeptDao deptDao;
    	@Resource
    	private LogDao logDao;
    
    	//事物控制注解
    	@Transactional(
    			readOnly=false,	//读写事物
    			timeout=-1,		//事物的超时时间不限制
    			//noRollbackFor=ArithmeticException.class	//遇到数学异常不回滚
    			rollbackFor=ArithmeticException.class,	//只回滚数学异常,指定更加精确
    			isolation=Isolation.DEFAULT,		//事物的隔离级别,数据库的默认
    			propagation=Propagation.REQUIRED
    			)
    
    	public void save(Dept dept){
    		//保存日志
    		logDao.save();
    
    		// 模拟异常,此时整个service.save()执行成功的时候要回滚
    		int i=1/0;
    
    		//调用
    		deptDao.save(dept);
    	}
    }
    

     这个时候即出现数学异常日志的保存行为会正常的插入,而部门的保存会正常进行。

  • 相关阅读:
    省常中模拟 Test4
    省常中模拟 Test3 Day1
    省常中模拟 Test3 Day2
    省常中模拟 Test1 Day1
    树型动态规划练习总结
    noip2010提高组题解
    noip2003提高组题解
    noip2009提高组题解
    noip2004提高组题解
    noip2002提高组题解
  • 原文地址:https://www.cnblogs.com/helloworldcode/p/6371924.html
Copyright © 2011-2022 走看看