Spring之事务控制

一,概述

1.1编程式事务控制

1)自己手动实现事务控制,就叫做编程式事务控制.

Jdbc代码:Connection.setAutoCommit(false);//设置手动控制事务

Hibernate代码:Session.beginTransaction();//开启一个事务

2)细粒度的事务控制:可以对指定的方法/指定方法的某几行代码添加事务控制.这种事务控制比较灵活,但开发起来比较繁琐,每次都要开启/提交/回滚.

1.2声明式事务控制

1)Spring提供了对事务的管理,这个就叫做声明式事务管理.

2)Spring提供了对事务控制的实现.开发者如果想使用Spring的声明式事务管理,只需要在配置文件中配置即可;不想使用时直接在配置文件中移除即可.Spring最大程度的实现了对事务控制的解耦.

3)Spring的声明式事务管理,核心实现就是基于AOP.

4)粗粒度的事务控制:只能给整个方法应用事务,不能对方法的某几行代码应用事务.(因为AOP拦截的是方法)

5)Spring声明式事务管理器类:

Jdbc-->DataSourceTransactionManager

Hibernate-->HibernateTransactionManager.

二,声明式事务管理

2.1准备工作

a)jar包准备:spring-core5个jar包,spring-aop4个jar包,spring-jdbc4个jar包.

2.2XML方式实现

a)Dept.java(setter和getter方法省略)

public class Dept {

	public Dept(){
		
	}
	
	private int deptId;
	private String deptName;
}

b)DeptDao.java

package com.bighuan.a_tx;

import org.springframework.jdbc.core.JdbcTemplate;
/**
 * dao实现,使用Spring对JDBC支持的功能
 * @author bighuan
 *
 */
public class DeptDao {
	//容器注入JdbcTemplate对象
	private JdbcTemplate jdbcTemplate;
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	
	public void save(Dept dept){
		String sql="insert into t_dept(deptName) values(?)";
		jdbcTemplate.update(sql, dept.getDeptName());
	}
}
c)DeptService.java

package com.bighuan.a_tx;
/**
 * service层实现,调用dao
 * @author bighuan
 *
 */
public class DeptService {
	//容器注入DeptDao对象
	private DeptDao deptDao;
	public void setDeptDao(DeptDao deptDao) {
		this.deptDao = deptDao;
	}
	
	public void save(Dept dept){
		//第一次调用
		deptDao.save(dept);
		//int i=1/0; //出现异常,整个Service.save(..)执行成功的要回滚
		deptDao.save(dept);//第二次调用
	}
}
d)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/tx
        http://www.springframework.org/schema/tx/spring-tx.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">

	<!-- 1,数据源对象:C3P0连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/hib_demo"></property>
		<property name="user" value="root"></property>
		<property name="password" value="abc"></property>
		<property name="initialPoolSize" value="3"></property>
		<property name="maxPoolSize" value="10"></property>
		<property name="maxStatements" value="100"></property>
		<property name="acquireIncrement" value="2"></property>
	</bean>

	<!--2,JdbcTemplate工具类实例 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<!-- 3,DeptDao实例 -->
	<bean id="deptDao" class="com.bighuan.a_tx.DeptDao">
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>

	<!-- 4,DeptService实例 -->
	<bean id="deptService" class="com.bighuan.a_tx.DeptService">
		<property name="deptDao" ref="deptDao"></property>
	</bean>

	<!-- ****Spring声明式事务管理配置**** -->
	<!-- 5.1配置事务管理器类 -->
	<bean id="txManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<!-- 5.2配置事务增强(如何管理事务?) -->
	<tx:advice id="txAdvice" transaction-manager="txManager">
		<tx:attributes>
		    <tx:method name="save*" read-only="false" />
			<tx:method name="*find*" read-only="true"/>
			<tx:method name="*get*" read-only="true"/>
			<tx:method name="*" read-only="false"/>
		</tx:attributes>
	</tx:advice>

	<!-- 5.3AOP配置:拦截哪些方法(切入点表达式)+应用上面的事务增强配置 -->
	<aop:config>
		<aop:pointcut expression="execution(* com.bighuan.a_tx.DeptService.*(..))" id="pt"/>
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
	</aop:config>
</beans>
e)测试:

public class App {
	
	private ApplicationContext ac=new ClassPathXmlApplicationContext("com/bighuan/a_tx/bean.xml");

	@Test
	public void testApp() throws Exception {
		Dept dept=new Dept();
		dept.setDeptName("test:开发部");
		
		DeptService service=(DeptService) ac.getBean("deptService");
		
		service.save(dept);
	}
}
第一次:将DeptService.java中的错误代码注释掉,执行测试代码,发现数据插入了两条数据.

第二次:不注释掉代码,执行测试代码,不能插入数据;如果不使用事务控制的话,只能插入一条数据.

2.3注解方式实现

a)DeptDao.java

@Repository
public class DeptDao {
	//容器注入JdbcTemplate对象
	@Resource
	private JdbcTemplate jdbcTemplate;
	
	public void save(Dept dept){
		String sql="insert into t_dept(deptName) values(?)";
		jdbcTemplate.update(sql, dept.getDeptName());
	}
}
b)DeptService.java

@Service
public class DeptService {
	//容器注入DeptDao对象
	@Resource
	private DeptDao deptDao;
	
	@Resource
	private LogDao logDao;
	
	@Transactional(readOnly=false,//读写事务
			timeout=-1,//-1表示事务的超时时间不限制,最终由数据库底层来决定
			//noRollbackFor=ArithmeticException.class,//遇到数学异常不回滚
			propagation=Propagation.REQUIRED
			)
	public void save(Dept dept){
		logDao.insertLog();
		//第一次调用
		deptDao.save(dept);
		
		int i=1/0; //出现异常,整个Service.save(..)执行成功的要回滚
		
		deptDao.save(dept);//第二次调用
	}
}
c)LogDao.java

@Repository
public class LogDao {
	
	@Resource
	private JdbcTemplate jdbcTemplate;

	@Transactional(propagation=Propagation.REQUIRED)
	//@Transactional(propagation=Propagation.REQUIRES_NEW)
	public void insertLog(){
		jdbcTemplate.update("insert into log_ values('往dept表插入数据...')");
	}
}
d)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/tx
        http://www.springframework.org/schema/tx/spring-tx.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">

	<!-- 1,数据源对象:C3P0连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/hib_demo"></property>
		<property name="user" value="root"></property>
		<property name="password" value="abc"></property>
		<property name="initialPoolSize" value="3"></property>
		<property name="maxPoolSize" value="10"></property>
		<property name="maxStatements" value="100"></property>
		<property name="acquireIncrement" value="2"></property>
	</bean>


	<!--2,JdbcTemplate工具类实例 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 3,事务管理器类 -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 开启注解扫描 -->
	<context:component-scan base-package="com.bighuan.b_anno"></context:component-scan>
	
	<!-- 注解方式实现事务:指定注解方式实现事务 -->
	<tx:annotation-driven transaction-manager="txManager"/>
</beans>
注解方式相对于XML方式就简单的多.注解方式一定要开启注解扫描及声明注解方式实现事务.

e)测试:

public class App {
	
	private ApplicationContext ac=new ClassPathXmlApplicationContext("com/bighuan/b_anno/bean.xml");

	@Test
	public void testApp() throws Exception {
		Dept dept=new Dept();
		dept.setDeptName("test:开发部");
		
		DeptService service=(DeptService) ac.getBean("deptService");
		
		service.save(dept);
	}
}
测试思路与上面一样.

f)propagation=Propagation.REQUIRED与propagation=Propagation.REQUIRES_NEW的区别

前者表示:如果当前运行的方法,已经存在事务, 就会加入当前的事务.
后者表示:指定当前的方法必须在事务的环境下执行;如果当前运行的方法,已经存在事务,事务会挂起; 会始终开启一个新的事务,执行完后;刚才挂起的事务才继续运行.








猜你喜欢

转载自blog.csdn.net/bighuan/article/details/71429875