• 事务实战感悟


    在JavaEE的三层架构体系(UI层、业务层、数据访问层次)中,事务体现在数据访问层。本文试图从分布式、Spring、Mybatis、JDBC、数据库、锁六个角度来看写。数据库为MySql,存储引擎为Innodb。

    从数据库看事务:

    事务的四个特性:

    Automicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)。

    通俗的讲:就是一个或一组SQL语句组成的单元(原子性)在执行的时候,和其它正在执行的SQL语句是无关的(隔离性),并且多个用户查询的执行结果是一样的(一致性),这种结果是永久的,即使数据库崩溃或者数据存储介质被破坏,系统也能恢复到最后一次成功执行的结果(永久性)。

    事务的生命周期:

    一般的,事务都是自动提交(注意上面已经提到是MySql数据库存储引擎为Innodb)。关闭自动提交语句:SET AUTOCOMMIT=0(慎用)。或是手动开始一个事务需要使用命令:BEGIN或START TRANSACTION。注意的是BEGIN或START TRANSACTION会禁用自动提交,直到使用COMMIT或ROLLBACK结束事务为止。

    另外DDL(数据定义语言)、DCL(数据控制语言)的事务是隐性提交的,相当于在执行此类语句前,已经进行了一个COMMIT。

    事务的隔离级别

    关于事务的隔离性,在并发操作中可能出现三种问题:脏读、不可重复读、幻读。

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

    不可重复读:一个事务的两次读取结果不一致(被update)。

    幻读:一个事务的两次读取结果不一致(被insert或delete)。

    数据库提供了四种隔离级别:

    Read uncommitted(读未提交)、Read committed(读已提交)、Repeated read(可重复读)、Serializable(串行化)。隔离级别依次升高,执行效率依次降低。

    下图展示的四种隔离级别对三种问题的解决情况。其中绿色字体为默认的隔离级别:

    从锁看事务:

    表级锁、页级锁、行级锁

    我们已经知道了数据库的事务,而数据库的事务实际上是通过锁来实现的。从锁定的范围来讲一般都三种锁:表级锁、页级锁、行级锁。表现如下:

    个人理解mysql是提倡行级锁的,而行级锁的实现很大程度依赖于索引。当操作无法利用索引时,Innodb会放弃使用行级锁而改用表级锁。需要特别说明的是主键是自带索引属性的。

    共享锁(S)、排他锁(X)、意向共享锁(IS)和意向排他锁(IX)

    从锁定模式的分类来讲有四种:共享锁(S)、排他锁(X)、意向共享锁(IS)和意向排他锁(IX)。表现如下:

     

    共享锁(S)

    排他锁(X)

    意向共享锁(IS)

    意向排他锁(IX)

    共享锁(S)

    兼容

    冲突

    兼容

    冲突

    排他锁(X)

    冲突

    冲突

    冲突

    冲突

    意向共享锁(IS)

    兼容

    冲突

    兼容

    兼容

    意向排他锁(IX)

    冲突

    冲突

    兼容

    兼容

    乐观所和悲观锁

    在并发访问数据库的时候,有两种技术方案:悲观锁(悲观并发控制),乐观锁(乐观并发控制)。

    悲观锁就是使用数据库提供的锁机制。另外可以发现,在使用了悲观锁的情况下,发生了锁表依然可以查询出数据,这是因为MySql采用了多版本并发控制机制(MVCC)。

    乐观锁不会使用数据库提供的锁机制。而是采用记录数据版本的方式。实现数据版本有两种办法:第一是使用版本号;第二是使用时间戳。

    从JDBC看事务

    jdbc开发步骤:注册驱动、获取链接、创建对象、执行SQL。如果完全的按照以上的开发步骤,不做特别设置。

    默认的:

    事务的提交方式使用的则是自动提交。

    事务的隔离级别则是可重复读。

    并且用的是悲观锁机制。

    如果要修改为手动提交:con.setAutoCommit(false);

    如果要修改事务的隔离级别:

    con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);

    其中,JDBC定义了五种事务隔离级别。

    TRANSACTION_NONE                              驱动不支持事务

    TRANSACTION_READ_UNCOMMITTED       允许脏读、不可重复读和幻读

    TRANSACITON_READ_COMMITTED                允许不可重复读和幻读;不支持脏读

    TRANSACTION_REPEATABLE_READ                不允许脏读、不可重复读和幻读

    TRANSACTION_SERIALIZABLE                 不允许脏读、不可重复读和幻

    如果要使用乐观锁,则需要自己进行实现。

    从Mybatis看事务

    Mybatis是支持定制化SQL、以及高级映射的持久层框架。其中,Mybatis中提供的JdbcTransaction和纯粹的Jdbc事务几乎没有差距,只能说仅仅扩张了支持连接池的connection。

    另外,Mybatis提供的ManagedTransaction(托管事务)仅是提醒用户,在其它环境中把事务托管给其它框架,比如托管给Spring。

    从Spring看事务

    Spring事务的本质可以理解为就是对数据库事务的支持,但是Spring让事务管理变得有效和简单。

    Spring支持事务的隔离级别(isolation=)。

    Spring定义了自己的事务传播属性(propagation=)。即同时存在多个事务时,Spring应该如何处理这些事务的行为。见下表:

    PROPAGATION_REQUIRED

    支持当前事务。如果当前没有事务,就新建一个事务(默认)

    PROPAGATION_NESTED

    支持当前事务。如果当前没有事务,就新建一个事务。内部事务回滚不会对外部事务造成影响。

    PROPAGATION_SUPPORTS

    支持当前事务。如果当前没有事务,就以非事务方式运行

    PROPAGATION_MANDATORY

    支持当前事务。如果当前没有事务,就抛出异常。

    PROPAGATION_NOT_SUPPORTED

    以非事务方式运行。如果当前存在事务,就把当前事务挂起。

    PROPAGATION_NEVER

    以非事务方式运行。如果当前存在事务,就抛出异常。

    PROPAGATION_REQUIRES_NEW

    新建事务。如果当前已有事务,就把当前事务挂起。

    Spring支持编程式事务管理和声明式事务管理两种方式。编程式事务允许在代码中精确定义事务的边界,而声明式事务(基于AOP)有助于将操作与事务规则进行解耦。推荐使用声明式事务注解方式。

  • 相关阅读:
    Linux 循环遍历文件目录
    批量修改文件名
    PostgreSQL 常用的命令
    批量修改文件格式到UTF-8
    wireshark:no interface can be used for capturing in this system with the current configuration
    使用画图方法显示排序算法,使用策略模式
    F#
    Linux下utf-8 BOM 的检查和删除 (65279错误解决办法)
    java.lang.NoClassDefFoundError: org/aspectj/weaver/tools/PointcutPrimitive
    unbuntu 14安装 golang
  • 原文地址:https://www.cnblogs.com/shuaixianbohou/p/7020298.html
Copyright © 2020-2023  润新知