spring 事物之一----基本概论

什么是事物

    事务是逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败。

    简单举例,假设有用户A,B的账户各有余额100元,A给B转100元,转钱的结果:第一种结果转账成功,A账户的余额为0元,B账户的余额为200元;第二种结果转账失败,A账户的余额为100元,B账户的余额为100元;事物就是用来保证在转账的过程中不会出现A账户的余额为100元,B账户的余额为200元。或是A账户的余额为0元,B账户的余额为100元。

事务特性(ACID)

原子性 (Atomicity) :事务的不可分割性
    A给B转账100元,A-100成功,B+100成功;A-100失败,B+100失败;两个操作必须保持一致,不可再分。

一致性 (Consistency):事务的执行的前后数据的完整性保持一致
    A,B账户各100元,A给B转账100元,不管成功或者失败,A,B账户合计都为200元;此为强一致性; 题外话(最终一致性,有兴趣的话可以看看分布式事物),可以在某个时间窗口账户共计不为200元,但是最终结果为200元。

隔离性 (Isolation) :一个事务执行的过程中,不应该受到其他事务的干扰
    A给B转账100元过程中,叫做事物1,有个操作查询A余额,叫做事物2,事物2查询A余额的只会0元或者100元,也就是说只能查询到事物1执行事物之前或者之后的状态,不会查询到事情1执行过程中的中间状态。

持久性 (Durability) :事务一旦结束,数据就持久到数据库
    A,B账户各100元,A给B转账100元,A-100成功,B+100成功;A的账户变成0元,B的账户变成200元,最终会在数据库做数据持久化。

事物隔离级别

如果不考虑事物隔离性,多个事物在执行情况下将会出现如下安全性问题:

1.脏读 : 一个事务读到了另一个事务的未提交的数据 。
    事物1做update操作未提交,事物2做select操作,此时如果事物1回滚,那么事物2就读取了事物1操作后的结果。导致脏读。

2.不可重复读 : 一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致.。
    事物1第一次做select操作,此时事物2做update操作并提交,事物1第二次做select操作,发现和第一次查询的结果不一样。

3.虚幻读 : 一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致。
    事物1做update操作将账户的余额全部改为0,并进行第一次select操作,发现余额都为0,此时事物2插入一条余额为100元的记录,事物1做第二次操作,发现账户还有大于0的数据,有点虚幻的感觉,明明已经全部余额改为0了。

 **那么问题来了,如何来解决上述情况呢,其实很简单我们通过设置事务隔离级别**

事务隔离级别(5种)
DEFAULT
默认的隔离级别,使用数据库默认的事务隔离级别.

未提交读(Read Uncommitted)
最低的隔离级别,如果一个事务已开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务读此行数据。脏读,不可重复读,虚读都有可能发生 。

已提交读(Read Committed)
读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行,避免脏读。但不可重复读和虚读有可能发生。

可重复读(Repeatable Read)
读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务,相当于程序select…for update动作,可避免脏读和不可重复读,但虚读有可能发生。

串行化读(Serializable)
事务串行执行,不能并发执行。相当于每次执行之前先锁全表,虽可避免以上所有读问题,但性能低下。

Mysql 默认:可重复读
Oracle 默认:读已提交

事务的传播行为

PROPAGATION_REQUIRED 支持当前事务,如果不存在 就新建一个(默认)
PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常

事务的管理方式

spring支持编程式事务管理和声明式事务管理两种方式。
1.编程式事务管理使用TransactionTemplate或者直接使用底层PlatformTransactionManager。

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(jdbcTemplate.getDataSource());
TransactionStatus status = transactionManager.getTransaction(def);
		try {
			String insertSql = this.getInsertSql(newItems);
			List<Object[]> batchArgs = this.getInsertValueList(newItems);
			jdbcTemplate.batchUpdate(insertSql, batchArgs);
		} catch (Exception e) {
				// 事务回滚,一条条执行
				transactionManager.rollback(status);
				throw e;
		}
		transactionManager.commit(status);

2.声明式事务管理也有两种常用的方:

一种是基于tx和aop名字空间的xml配置文件

<!-- 1.声明式事务,基于tx和aop名字空间的xml配置文件 -->
    <bean id="web_transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<tx:advice id="web_txAdvice" transaction-manager="web_transactionManager">
		<tx:attributes>
		   <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="BusinessException.class"/>
		    <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="BusinessException.class" />
		    <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="BusinessException.class"/>
		    <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
     		<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
      		<tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
      		<tx:method name="query*" propagation="SUPPORTS" read-only="true"/>
		</tx:attributes>
	</tx:advice>
    <aop:config>
        <aop:pointcut id="interceptorPointCuts"
                      expression="execution(* com.kook.web.base.dao.*.*(..))" />
        <aop:advisor advice-ref="web_txAdvice"
                     pointcut-ref="interceptorPointCuts" />
    </aop:config>

一种就是基于@Transactional注解。

<!--2.声明式事务,基于@Transactional注解-->
    <tx:annotation-driven transaction-manager="txManager" />
     <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         <property name="dataSource" ref="dataSource" />
     </bean>

@Transactional注解

@Transactional属性

属性 类型 描述
value String 指定使用的事务管理器,可选的
propagation enum: Propagation 可选的事务传播行为设置(7种)
isolation enum: Isolation 可选的事务隔离级别设置(5种)
readOnly boolean 读写或只读事务,默认读写
timeout int 事务超时时间设置(单位秒)
rollbackFor Class对象数组,继承自Throwable 导致事务回滚的异常类数组
rollbackForClassName 类名数组,继承自Throwable 导致事务回滚的异常类名字数组
noRollbackFor Class对象数组,继承自Throwable 不会导致事务回滚的异常类数组
noRollbackForClassName 类名数组,必须继承自Throwable 不会导致事务回滚的异常类名字数组

@Transactional用法
1.@Transactional 可以用于接口、接口方法、类以及类方法上,一般情况不要在接口和接口方法上使用该注解
2.@Transactional 注解只能被应用到 public 方法上,如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,注解将会被忽略,也不会抛出任何异常。
3.默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为

猜你喜欢

转载自blog.csdn.net/liangruiwei_kook/article/details/84061646
今日推荐