事务的基础入门


  大家在不知道事务这个东西的时候,会不会在自己的某一次报错中“灵机一动”的想到这样一个问题。银行、微信、支付宝在
转账的过程中突然报错了,我的钱转过去了,而对方并没有收到我的钱。仔细想一想,那我是不是可以借着这个,来赢取白富美,
走向人生巅峰,我先定他一个小目标......,直到在很久以前的某一天,我知道了事务这个东西,额......

一、什么是事务

  事务是一个很广泛的词,各行各业对这个词都有不同的理解,而对于计算机术语而言,它则代表着Transaction - 就是逻辑上的
一组操作,组成这组操作的各个单元要么全部成功,要么全都失败。在知道了事务的概念后,我还是晕晕的,满足什么样的特性
才可以称的是事务呢?

二、事物的四个特性

* 原子性(A):不可分割  

 组成事务的所有逻辑上的操作,要不就全都执行,要不就一个都不要执行(生死与共)。

* 一致性(C):事务在执行前后,要保证数据的一致

  一致性可以简单的理解为2个人转账,转账前和转账后的两人金钱总和,不发生改变。这个栗子只是在描述最后的结果,而产生一致
性的原因,除了结果守恒以外还有些什么呢(数据库里是怎么保证一致性的)?存入数据库的数据,都是我们将现实里的东西,通过代码
的方式进行抽象化。将抽象化对象中,我们所需要的属性值,存入到数据库中(数据化)。为了方便辨别和使用,我们会给这个属性取
一个数据库里的名字(列名)。那么一个类的前后一致性一定是,这个类的所有根性都要前后一致,即 : 要保证实体完整性(主属性不
为空)、参照完整性(外键必须存在原表中)、用户自定义的完整性(自己为这个类定义的一些约束)。

* 隔离性(I):一个事务在执行的过程中,不应该受到其它事务的干扰

  隔离性依赖于加锁或者多版本控制,在执行了一条插入的SQL,如加上个100万。如果该事物没有提交,其他的事物是不能读到这条
执行结果的。

* 持久性(D):事务一旦结束,数据持久化到数据库

三、事务的一些问题

  如果不考虑事务的隔离性的,会发生一些什么样的问题呢?

* 脏读:         一个事务读取到另一个事务的未提交数据。

* 不可重复读:  一个事务读取到另一个事务提交的数据(主要是指update),会导致两次读取的结果不一致。

* 虚读(幻读): 一个事务读取到另一个事务提交的数据(主要是指insert),会导致两次读取结果不一致。

  以上的这些问题可能会导致许许多多的问题,那么它还有救么?我们可以通过设置不同的隔离级别,来解决脏读、
不可重复读等问题。

四、事物的隔离级别

  事务一空有四个隔离级别,分别是:

* READ_UNCOMMITED 读取未提交,它引发所有的隔离问题。

* READ_COMMITTED    读已提交,阻止脏读,可能发生不可重复读与虚读。

* REPEATABLE_READ  重复读 阻止脏读,不可重复读 可能发生虚读。

* SERIALIZABLE           串行化 解决所有问题 不允许两个事务,同时操作一个目标数据。(效率低下)

  而在常用的数据库中 ORACLE 的默认的是事务隔离级别是 READ_COMMITTED,MYSQL 默认的事务隔离级别 REPEATABLE_READ。

五、Spring对事务管理的简单使用

  Spring框架的一大亮点就是他对事物的支持非常友好,使用起来也很方便,Spring的事务管理有着四个优点:

* 提供一致的对于不同的事务管理的API

* 支持声明式事务管理

* 编程事务管理(使用较少)

* 优秀的整合与Spring的数据访问   

  Spring的事务管理主要是通过3个接口来提供支持的:

1、org.springframework.transaction.PlatformTransactionManager  

  这是一个事务管理器,可以来选择相关的平台(Jdbc、Hibernate、Jpa等),即:你要使用哪个平台的事务。

2、TransactionDefinition   

  它定义事务的一些相关信息,例如:隔离、传播、超时、只读。
    * 隔离:设置事物的隔离级别,如:ISOLATION_READ_COMMITTED 可以解决脏读,会产生不可重复读与虚读。
    * 传播:它解决的是两个被事务管理的方法互相调用问题。是程序内部维护的问题。如:PROPAGATION_REQUIRED(默认值)
两个操作处于同一个事务,如果之前没有事务,则新建一个事务。
    * 超时:默认值是-1,它使用的是数据库默认的超时时间。
    * 只读:它的值有两个true/false,如果选择true一般是在select操作时。

3、TransactionStatus

   它定义了事务状态信息,在事务运行过程中,得到某个时间点的状态。

(一)基于XML配置声明式事务

  在导入相关依赖之后还要在applicationContext.xml文件中添加aop与tx的名称空间。

<!-- 引入外部的properties文件,数据库连接配置文件-->
<context:property-placeholder location="classpath:db.properties" />

<!-- 创建c3p0连接池,连接数据库 -->
<bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>

<!-- service -->
<bean id="accountService" class="cn.lalala.service.AccountServiceImpl">
<!-- 引入Dao层依赖 -->
<property name="accountDao" ref="accountDao"></property>
</bean>

<!-- dao dao层要继承JdbcDaoSupport类-->
<bean id="accountDao" class="cn.lalala.dao.AccountDAOImpl">
<!-- 当注入dataSource后,底层会自动创建一个JdbcTemplate模板类,详情可以参看JdbcDaoSupport类的源码-->
<property name="dataSource" ref="c3p0DataSource" />
</bean>

<!-- 配置事务管理器,这里用的是jdbc的 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 要注入连接池,参数请看DataSourceTransactionManager的源码 -->
<property name="dataSource" ref="c3p0DataSource"></property>
</bean>

<!-- 配置通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 
name:    必须的 对哪些方法进行事务控制
isolation 可选 设置事务隔离级别 默认是DEFAULT 
propagation:    可选 设置事务传播 默认值 REQUIRED
timeout 可选 超时时间 默认值-1 
read-only 可选 默认值是false 如果不是只读,它可以对insert update delete操作,如果是只读不可以。
rollback-for 可选 可以设置一个异常,如果产生这个异常,触发事务回滚
no-rolback-for 可选 可以设置一个异常,如果产生这个异常,不会触发事务回滚
-->

<!-- 要被事务管理的方法 -->
<tx:method name="account" />    
</tx:attributes>
</tx:advice>

<!-- 配置切面 -->
<aop:config>
<!-- 配置切点 -->
<aop:pointcut expression="execution(* cn.lalala.service.IAccountService.account(..))" id="txPointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>

(二)基于注解配置事务

  在配置好事务管理器和开启注解式事务后,只需在被事务管理的方法或类(整个类下的所有方法)使用@Transactional注解。

<!-- 开启注解式事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

  注解式的配置和配置文件式的配置各有优缺点,注解式使用起来方便,但是不利于后期的维护,基于配置文件的则是配置
起来比较麻烦但是方便阅读,容易理解。


原文地址:https://www.cnblogs.com/0813lichenyu/p/8312515.html