事务
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"/>