注解方式实现声明式事务管理

使用注解实现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);
	}
}

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

 

posted @ 2017-02-06 22:01  晓乎  阅读(634)  评论(0编辑  收藏  举报
总访问: counter for blog 次