Spring框架实现数据完整性(事务管理)

216 阅读3分钟

事务

1、特点:事务[Transaction]可用理解是一系列操作组成单元模块,这些操作要么全部成功(事务提交[Commit]),要么全部失败(事务回滚[Rollback])。
2、性质
a.原子性:单元模块中的操作是不可分割。
b.一致性:事务提交(所有操作正常执行)或者 事务回滚(所有操作都不执行)。
c.隔离性:每个事务都是独立单元 防止并发操作(事务所影响的数据在事务未完成之前被锁定)。
d.持久性:事务提交后实现数据的持久化 事务回滚数据恢复初始状态。
3、操作:mysq中(默认为自动提交事务——执行SQL脚本完成 自动提交事务)

/* 默认为自动提交事务 - 实际业务过程中不推荐*/
INSERT INTO book(a,b,c) VALUES (d,e,f)
/* 手动提交事务*/
BEGIN;
/* 事务提交*/
COMMIT;
/* 事务回滚*/
ROLLBACK;
/* 事务隔离性 锁定*/
BEGIN;

数据操作时会产生并发:不同的会话在同一时间操作同一数据,会影响数据完成性,产生“脏读”,“幻读”或“不可重复读”等现象。

关系数据库处理并发的方式——锁

说明 死锁——>两个会话互相因为各自资源的锁定而产生相互钳制。
1.甲会话操作A资源 -> A资源会被甲会话锁定
2.乙会话操作B资源 -> B资源会被乙会话锁定
3.甲会话操作B资源 -> B资源已被乙会话锁定 甲会话操作停滞等待 乙操作
4.乙会话操作A资源 -> A资源已被甲会话锁定 乙会话操作停滞等待 甲操作
系统检测死锁,会强制释放。

并发数据的三种表现形式(“脏读”,“幻读”或“不可重复读”)

1:Dirty reads--读脏数据。也就是说,比如事务A的未提交(还依然缓存)的数据被事务B读走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的。

2:non-repeatable reads--数据不可重复读。比如事务A中两处读取数据-total-的值。在第一读的时候,total是100,然后事务B就把total的数据改成200,事务A再读一次,结果就发现,total竟然就变成200了,造成事务A数据混乱。

3:phantom reads--幻象读数据,这个和non-repeatable reads相似,也是同一个事务中多次读不一致的问题。但是non-repeatable reads的不一致是因为他所要取的数据集被改变了(比如total的数据),但是phantom reads所要读的数据的不一致却不是他所要读的数据集改变,而是他的条件数据集改变。比如Select account.id where account.name like "ppgogo%",第一次读去了6个符合条件的id,第二次读取的时候,由于事务b把一个帐号的名字由"dd"改成"ppgogo1",结果取出来了7个数据。

事务解决方案

1)、配置

<!-- 事务引入 -->
	<!-- 注意:id="transactionManager" 固化命名 -->
	<bean id="transactionManager"  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 事务规则 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<!-- 方法名为add开头所有业务 添加事务管理 -->
			<tx:method name="add*" propagation="REQUIRED"/>
			<tx:method name="udp*" propagation="REQUIRED"/>
			<tx:method name="del*" propagation="REQUIRED"/>
			<!-- 查询业务 不影响数据更新 支持事务即可 不需要额外追加 -->
			<tx:method name="sel*" propagation="SUPPORTS"/>
		</tx:attributes>
	</tx:advice>
	<!-- 通过AOP 将事务管理"织入" 核心业务中  -->
	<aop:config>
		<aop:pointcut expression="execution(* com.up.service.impl.……ServiceImpl.*(..))" id="p1"/>
		<aop:advisor advice-ref="txAdvice" pointcut-ref="p1"/>
	</aop:config>

注意:spring回滚依据是异常 -> 如果业务自行处理异常,对外而言该业务没有异常。 ->业务方法强烈要求抛出异常

2)、注解(重构并优化)

配置拆解
<import resource="dao.xml"/>
<import resource="service.xml"/>

事务注解
@Transactional(propagation=Propagation.REQUIRED)
注意:启动自动代理事务
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<tx:annotation-driven transaction-manager="transactionManager"/>