文章目录

  • 1.事务
  • 1.1事务的概念
  • 1.2jdbc事务的操作
  • 1.3事务的四大特性(ACID)
  • 1.4并发访问问题----由隔离性引起
  • 1.5MySQL数据库共定义了四种隔离级别
  • 2编程式事务控制相关对象
  • 2.1PlatformTransactionManager
  • 2.2TransactionDefinition
  • 2.3TransactionStatus
  • 3.声明式事务控制
  • 3.1什么是声明式事务控制
  • 3.2声明式事务控制的实现
  • 3.2.1基于xml相关配置
  • 3.2.2基于注解的配置
  • 3.2.2.1注解配置声明式事务控制解析
  • 3.2.2.2声明式事务控制的配置要点


1.事务

1.1事务的概念

事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功。

1.2jdbc事务的操作

默认是自动事务:

执行sql语句:executeUpdate() ---- 每执行一次executeUpdate方法 代表 事务自动提交

通过jdbc的API手动事务:

开启事务:conn.setAutoComnmit(false);

提交事务:conn.commit();

回滚事务:conn.rollback();

注意:控制事务的connnection必须是同一个

1.3事务的四大特性(ACID)

1.3.1、原子性(Atomicity)
  原子性是指事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败。比如在同一个事务中的SQL语句,要么全部执行成功,要么全部执行失败

1.3.2、一致性(Consistency)
   官网上事务一致性的概念是:事务必须使数据库从一个一致性状态变换到另外一个一致性状态。以转账为例子,A向B转账,假设转账之前这两个用户的钱加起来总共是2000,那么A向B转账之后,不管这两个账户怎么转,A用户的钱和B用户的钱加起来的总额还是2000,这个就是事务的一致性。

1.3.3、隔离性(Isolation)
  事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

1.3.4、持久性(Durability)
  持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

1.4并发访问问题----由隔离性引起

1)脏读:B事务读取到了A事务尚未提交的数据
这是非常危险的,假设A向B转帐100元,对应sql语句如下所示
1.update account set money=money+100 where name=‘B’;
 2.update account set money=money-100 where name=‘A’;
当第1条sql执行完,第2条还没执行(A未提交时),如果此时B查询自己的帐户,就会发现自己多了100元钱。如果A等B走后再回滚,B就会损失100元。

2)不可重复读:一个事务中 两次读取的数据的内容不一致
例如:例如银行想查询A帐户余额,第一次查询A帐户为200元,此时A向帐户内存了100元并提交了,银行接着又进行了一次查询,此时A帐户为300元了。银行两次查询不一致,可能就会很困惑,不知道哪次查询是准的。

3)幻读/虚读: 虚读(幻读)是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。
  如丙存款100元未提交,这时银行做报表统计account表中所有用户的总额为500元,然后丙提交了,这时银行再统计发现帐户为600元了,造成虚读同样会使银行不知所措,到底以哪个为准。

1.5MySQL数据库共定义了四种隔离级别

Serializable(串行化):可避免脏读、不可重复读、虚读情况的发生。
Repeatable read(可重复读):可避免脏读、不可重复读情况的发生。
Read committed(读已提交):可避免脏读情况发生。
Read uncommitted(读未提交):最低级别,以上情况均无法保证。
相关内容见:

2编程式事务控制相关对象

2.1PlatformTransactionManager

PlatformTransactionManager接口是spring的事务管理器,它里面提供了常用的操作事务的方法

方法

说明

TransactionStatus getTransaction(TransactionDefination)

获取事务的状态信息

void commit(TransactionStatus status)

提交事务

void rollback(TransactionStatus status)

回滚事务

注意:
PlatformTransactionManager 是接口类型,不同的Dao层技术则有不同的实现类

2.2TransactionDefinition

TransactionDefinition是事务的定义信息对象,里面有如下方法:

方法

说明

int getIsolationLevel()

获得事务的隔离级别

int getPropogationBehavior()

获得事务的传播行为

int getTimeout()

获得超时时间

Boolean isReadonly()

是否只读

  • ISOLATION_DEFAULT
  • ISOLATION_READ_UNCOMMITTED (脏读)
  • ISOLATION_READ_COMMITTED(不可重复读)
  • ISOLATION_REPEATABLE_READ(幻读)
  • ISOLATION_SERIALIZABLE(串行化:可避免脏读、不可重复读、幻读 )
    2.事务传播行为
  • REQUIRED:A调B,如果A当前没有事务,B就新建一个事务,如果A已经存在一个事务,B加入A的事务。一般的选择(默认)
  • SUOPORTYS:支持当前事务,如果当前没有事务,就以非事务的方式执行
  • MANDATORY:使用当前事务,如果没事务就抛出异常
  • REQUERS_NEW:新建事务,如果在当前事务中,把当前事务挂起
  • NOT_SUPPORTED:以非事务的方式执行操作,如果当前;存在事务,就把当前事务挂起
  • NEVER:以非事务方式运行,如果当前存在事务,抛出异常
  • NESTED:如果当前存在事务则在嵌套事务内执行,如果当前没有事务,则执行REQUIRED类似的操作
  • 超时时间:默认值是-1,没有时间限制。如果有,以秒为单位进行设置
  • 是否只读:建议查询是设为只读

2.3TransactionStatus

TransactionStatus接口提供的是事务具体的运行状态,方法介绍如下

方法

说明

boolean hasSavepoint()

是否存储回滚点

boolean isCompleted()

事务是否完成

boolean isNewTransaction()

是否是新事务

boolean isRollbackOnly()

事务是否回滚

3.声明式事务控制

3.1什么是声明式事务控制

Spring的声明式事务控制顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明,用在Spring配置文件中声明式的处理事务来代替代码式的处理事务
声明式事务处理的作用

  • 事务管理不侵入开发的组件。具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为业务管理属于系统层面的服务,而不是业务逻辑的一部分,如果想改变事务管理策划的话,也只需要在定义文件中重新配置即可
  • 在不需要事务管理的时候,只有在设定文件修改y一下,即可移去事务管理业务,无需改变代码重新编译,这样维护起来及其方便
    注意:Spring声明式事务控制底层就是AOP

3.2声明式事务控制的实现

声明式事务控制明确事项

  • 谁是切点?
  • 谁是通知?
  • 谁是切面?

声明式事务控制的配置要点

  • 平台事务管理器的配置
  • 事务通知的配置
  • 事务aop织入的配置

3.2.1基于xml相关配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context"
      xmlns:aop="http://www.springframework.org/schema/aop"
      xmlns:tx="http://www.springframework.org/schema/tx"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop   http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx.xsd">
   <context:property-placeholder location="jdbc.properties"></context:property-placeholder>
  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
      <property name="driverClass" value="${driver}"></property>
      <property name="jdbcUrl" value="${url}"></property>
      <property name="user" value="${name}"></property>
      <property name="password" value="${password}"></property>
  </bean>
   <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
       <property name="dataSource" ref="dataSource"></property>
   </bean>
   <bean id="accountDao" class="com.blb.DaoImpl.AccountDaoImpl">
       <property name="jdbcTemplate" ref="jdbcTemplate"></property>
   </bean>
   <!-- 目标对象 内部方法就是切点 -->
   <bean id="userServer" class="com.blb.ServerImpl.UserServerImpl">
       <property name="accountDao" ref="accountDao"></property>
   </bean>
   <!-- 配置平台事务管理器-->
   <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>
           <tx:method name="*"/>
       </tx:attributes>
   </tx:advice>
   <!-- 配置事务织入-->
   <aop:config>
       <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.blb.ServerImpl.UserServerImpl.exchange())"></aop:advisor>
   </aop:config>
</beans>

其中,< tx:method >切点方法是事务参数的配置,例如

<tx:attributes>
           <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>
       </tx:attributes>
   </tx:advice>

name:切点名称
isolation:事务的隔离级别
propogation:事务的传播行为
timeout:超时时间
read-only:是否只读

3.2.2基于注解的配置

3.2.2.1注解配置声明式事务控制解析
  1. 使用@Transactional在需要进行事务控制的类或方法上修饰,注解可用的属性同xml配置方式,例如:隔离级别,传播行为等
  2. 直接使用在类上,那么该类下的所有方法都使用同一套注解配置项参数
  3. 使用在方法上,那么该类可以采用不同是=的事务参数配置
  4. xml配置文件中要开启事务的注解驱动
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
3.2.2.2声明式事务控制的配置要点
  • 平台事务管理器配置(xml方式)
  • 事务通知的配置(@transactional注解配置)
  • 事务注解驱动的配置< tx:annotation-driven/ >