Spring入门5:事务控制

14 篇文章 0 订阅

1.事务

事务:
事务是一组操作的执行单元,相对于数据库操作来讲,事务管理是一组SQL指令.
且,事务的一致性要求这个事务内的操作必须全部执行成功,如果在此过程出现异常,如其中的一条SQL执行失败,那么这组事务(这组操作)就会回滚.

事务特性:
Atomic(原子性):事务是不可再分的一组操作.(要么都成功,要么都失败)
COnsistent(一致性):数据不应被破坏
Isolate(隔离性):用户与用户间的操作是互不影响的

Durable(持久性):事务执行成功后,数据持久化

2.Spring声明式事务管理

控制事务的方式:
方式1:编程式事务管理
JDBC:
Connection con;//对象
con.setAutoCommite(false);//设置手动提交事务

Hibernate:
session.beginTransaction();//开启事务
session.getTransaction.commit()//提交事务

编程式事务的特点:
1.优点:可以精确地控制事务
2.缺点:每次都要手写事务代码,代码冗余

方式2:声明式事务控制
Spring框架提供声明式事务管理控制.
Spring提供事务的切面类,只需通过事务配置,就可以利用Aop功能,给指定的方法添加事务.
事务切面类:(Spring提供)
Jdbc事务控制:DataSourceTransactionManager
Hibernate事务控制:HibernateTransactionManager

特点:
1.Spring声明式事务管理,一定要用AOP编程
2.Aop连接的是方法(而不是方法中的某几行代码)
3.粗粒度的事务控制(事务控制不精确)
优点:
1.事务控制只需配置即可,对程序的结构没有影响
2.Spring的解耦体现
让事务与业务代码脱离

3.提高开发效率(无需手写事务代码)


*******案例**********
*****1.Jdbc声明式事务管理,set方法注入对象********
	// 各接口略
	//1.dao类
	public class UserDao implements IUserDao{//dao类
		// 注入JdbcTemplate
		private JdbcTemplate jdbcTemplate;
		public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
			this.jdbcTemplate = jdbcTemplate;
		}

		public void save() {
			jdbcTemplate.update("insert into t_user(name)values('test')");
		}
	}
	
	//2.service类
	public class UserService implements IUserService {//service类
		// 注入Dao;  注意:如果当期加入容器的service是代理对象,这里一定要用接口!
		private IUserDao userDao;
		public void setUserDao(IUserDao userDao) {
			this.userDao = userDao;
		}
		//... 开启事务
		@Override
		public void save() {
			userDao.save();
			int i=1/0;
			userDao.save();
		}
	}
	<!-- 配置 -->
	<!-- 1. 创建DataSource -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
			<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
			<property name="jdbcUrl" value="jdbc:mysql:///day33"></property>
			<property name="user" value="root"></property>
			<property name="password" value="root"></property>
			<property name="initialPoolSize" value="3"></property>
			<property name="maxPoolSize" value="6"></property>
	</bean>
	
	<!-- 2. 创建JdbcTemplate, 注入DataDataSource -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 3. 创建dao实例,注入JdbcTemplate -->
	<bean id="userDao" class="cn.itcast.a_tx_jdbc.UserDao">
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>
	
	<!-- 4. 创建Service实例, 注入dao -->
	<bean id="userService" class="cn.itcast.a_tx_jdbc.UserService">
		<property name="userDao" ref="userDao"></property>
	</bean>
	
	<!-- 
		5. Spring声明式事务管理配置
	 -->
	 <!-- 5.1 配置事务管理器类 (切面类) -->
	 <!-- (里面实现了事务的重复代码!) -->
	 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	 	<property name="dataSource" ref="dataSource"></property>
	 </bean>
	 
	 <!-- 5.2 配置事务通知, 指定事务管理器类-->
	 <!-- 拦截到方法后,对不同名称的方法,如何进行事务控制,如只读、读写? -->
	 <!-- save* 以save开头的方法,进行的事务管理的方式,如读写 -->
	 <!--  *    放到最后; 上面所有的方法都不满足的时候,应用的事务管理方式,如只读!-->
	 <tx:advice id="txAdvice" transaction-manager="txManager">
	 	<tx:attributes>
	 		<tx:method name="save*" read-only="false" />
	 		<tx:method name="update*" read-only="false"/>
	 		<tx:method name="delete*" read-only="false"/>
	 		<tx:method name="*" read-only="true"/>
	 	</tx:attributes>
	 </tx:advice>
	 
	 <!-- 5.3 Aop配置 = 切入点表达式 + 应用通知 -->
	 <!-- 通过切入点表达式,对指定的方法生成代理对象且进行拦截; 拦截到后应用事务通知;在由事务通知应用事务管理器事务的实现! -->
	 <aop:config>
	 	 <aop:pointcut expression="execution(* cn.itcast.a_tx_jdbc.*Service.*(..))" id="pt"/>
	 	 <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
	 </aop:config>

*结果/现象

/*service类中的save()方法包含:
userDao.save();
int i=1/0;
userDao.save();
第一条语句执行成功,但数据并未持久化;
第二条语句执行失败,程序异常,因为是在事务中发生的异常,所以所有事务内的操作全部回滚.即第一条语句的执行结果无效.
第三条语句不执行.

*/


*****2.Jdbc声明式事务管理,注解注入对象********
	// 接口略
	@Repository   // 对象加入ioc容器
	public class UserDao implements IUserDao{
		
		// 自动从容器找名称是"jdbcTemplate"对应的bean!
		@Resource
		private JdbcTemplate jdbcTemplate;

		public void save() {
			jdbcTemplate.update("insert into t_user(name)values('test')");
		}
	}
	
	// 模拟插入日志的操作
	@Service
	public class LogService {

		@Resource
		private JdbcTemplate jdbcTemplate;
		
		// REQUIRES_NEW 表示无论执行当前save方法有没有事务环境,都会开启一个独立的事务!
		@Transactional(propagation=Propagation.REQUIRES_NEW)
		public void save(){
			jdbcTemplate.update("insert into t_log values('提示:正在执行保存!')");
		}
	}
	
	@Service
	public class UserService implements IUserService {
		
		@Resource
		private IUserDao userDao;
		
		@Resource
		private LogService logService;
		
		// 给当前方法应用是事务!
		@Transactional(
				readOnly=false,					// 读写的事务; 对数据有修改的时候必须使用这个属性!
				isolation=Isolation.DEFAULT,  	// 数据库默认的隔离级别!
				//noRollbackFor=ArithmeticException.class,   // 遇到指定的异常不回滚!
				timeout=-1,						// 事务的超时时间(S), -1 表示事务不设置超时时间!
				propagation=Propagation.REQUIRED  // 默认值,表示当前方法必须在事务环境运行!
		)
		public void save() {
			// 先插入日志
			logService.save();
			
			int i =1/0;
			
			// 执行业务处理
			userDao.save();
		}
	}
	<!-- 1. 创建DataSource -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql:///day33"></property>
		<property name="user" value="root"></property>
		<property name="password" value="root"></property>
		<property name="initialPoolSize" value="3"></property>
		<property name="maxPoolSize" value="6"></property>
	</bean>
	
	<!-- 2. 创建JdbcTemplate, 注入DataDataSource -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 3. 开启注解扫描 -->
	<context:component-scan base-package="cn.itcast.b_tx_jdbc_anno"></context:component-scan>
	
	 <!-- 4. Spring声明式事务管理, 注解方式实现 -->
	 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	 	<property name="dataSource" ref="dataSource"></property>
	 </bean>
	 
	 <!-- 开启事务的注解扫描 -->
	 <tx:annotation-driven transaction-manager="txManager"/>
	 
	 /*    //测试,结果/现象
	 	public void save() {
			// 先插入日志
			logService.save();//次条语句是在一个事务内
			
			int i =1/0;//程序异常
			
			// 执行业务处理
			userDao.save();//次条语句在另一事务内
			
			//所以,第一条语句的执行结果不会回滚;而第二条语句不执行.
		}
	 */

3. 事务细节

a. 引用事务名称空间
org.springframework.jdbc.datasource.DataSourceTransactionManager
org.springframework.orm.hibernate3.HibernateTransactionManager

b.使用@Transactional注解
@Transactional定义到方法上,表示当前执行的方法应用事务!
@Transactional定义到类上,表示当前类的所有方法应用事务!
@Transactional定义到父上,表示执行父类的方法时候应用事务!

c.事务属性:
propagation属性:
Never   当前业务方法不能再事务内执行!否则报错!
即不应用事务!

SUPPORTS  当前执行方法有事务则支持!没有事务也可以运行!
适合查询操作!

REQUIRED 当前方法必须在事务环境运行!
如果当前方法已经在事务环境运行,那么当前方法就不开启一个新的事务!             
如果当前方法没有再事务环境中运行,那么会开启一个新的事务!

REQUIRESNEW    当前方法必须在事务环境运行!
无论当前方法是否在事务环境中运行,当前方法都会开启一个新的事务!
 
readOnly=false, // 读写的事务; 对数据有修改的时候必须使用这个属性!
isolation=Isolation.DEFAULT,   // 数据库默认的隔离级别!
//noRollbackFor=ArithmeticException.class,   // 遇到指定的异常不回滚!

timeout=-1,// 事务的超时时间(S), -1 表示事务不设置超时时间!


*若有不足或错误,请多多指教,谢谢!*

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值