• 事务的基础入门



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

    一、什么是事务

      事务是一个很广泛的词,各行各业对这个词都有不同的理解,而对于计算机术语而言,它则代表着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"/>

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


  • 相关阅读:
    9、Spring Boot 2.x 集成 Thymeleaf
    【专题】Spring Boot 2.x 面试题
    8、Spring Boot 2.x 服务器部署
    7、Spring Boot 2.x 集成 Redis
    6、Spring Boot 2.x 集成 MyBatis
    5、Spring Boot 2.x 启动原理解析
    4、Spring Boot 2.x 自动配置原理
    3、Spring Boot 2.x 核心技术
    2、Spring Boot 2.x 快速入门
    centOS下安装JDK1.8.60,glassfish4.1.1以及MySQL
  • 原文地址:https://www.cnblogs.com/0813lichenyu/p/8312515.html
Copyright © 2020-2023  润新知