zoukankan      html  css  js  c++  java
  • java学习day35-数据库事务

    事务

    数据库中执行sql语句的最小工作单元, 不能拆分,执行同一业务的sql语句可以保证全部成功或全部失败

    为什么使用事务?

    如果不使用事务,客户端会自动提交,多次操作数据库做某一件事的时候(如:转账)会出现部分成功部分失败,则数据会出现异常.使用事务,把多次操作数据库的sql合并到一次提交中,这样就能保证同时成功或失败

    事务的ACID特性 (面试)

    • Atomicity: 原子性 事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。
    • Consistency: 一致性 事务执行后,数据库状态与其它业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账户金额之和在事务前后应该是保持不变的。
    • Isolation: 隔离性,隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。也就是说,在事中务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。
    • Durability: 持久性,一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。

    使用事务的过程

    1. 开启事务
    2. 执行多次sql (在内存中执行)
    3. 手动提交或(回滚/中断)

    开启事务的三种方式

    1. set autocommit=0;关闭自动提交

      查看客户端自定提交的状态:

      show variables like '%autocommit%';
      

      关闭自动提交 仅对当前窗口生效

      set autocommit=0;
      

      打开自动提交

      set autocommit=1;
      
    2. start transaction; (开始事务)

    3. begin (开始事务)

    案例 验证转账流程:

    1. 创建表

      create table person(
          id int primary key auto_increment,
          name varchar(10),
          money int
      );
      
    2. 插入数据

      insert into person values
      (null, '超人', 200),
      (null, '蝙蝠侠', 10000);
      
    3. 关闭自动提交 (3种方式都可以)

      -- start transaction;
      -- begin;
      set autocommit=0;
      
    4. 转账

      update person set money=500 where id=1; -- (+300)
      update person set money=9700 where id=2; -- (-300)
      
    5. 打开新窗口 验证是否转账成功?数据没变 因为两次操作都是在内存中操作 并未提交

    6. 手动提交

      commit;
      

    数据回滚

    只能在事务中使用

    执行rollback会将数据回滚到上次提交的点

    rollback;
    

    使用quit是中断事务, 和rollback效果一样

    设置回滚点

    只能在事务中使用

    1. 保存回滚点: savepoint s1; s1是回滚点的名字
    2. 回滚到指定的回滚点: rollback to s1;

    验证回滚点:

    1. 先将回滚点500改成600
    2. 保存回滚点 s1
    3. 将超人从600改成700
    4. 回滚到s1 如果超人的钱 为600则说明成功!

    总结

    1. show variables like '%autocommit%'; 查看自动提交状态
    2. set autocommit=0/1; 关闭或开启自动提交, 0是关闭, 1是开启
    3. start transaction; 开始事务
    4. begin (开始事务)
    5. rollback 回滚在上次提交的点,只能在事务中使用
    6. quit 中断事务,只能在事务中使用
    7. savepoint s1; 自定义一个回滚点, 名字为s1,只能在事务中使用
    8. rollback to s1; 回滚带名字为s1的回滚点,只能在事务中使用
    9. commit; 提交事务,只能在事务中使用

    扩展-事务并发读问题

    多个事务对相同的数据同时进行操作,这叫做事务并发。

    在事务并发时,如果没有采取必要的隔离措施,可能会导致各种并发问题,破坏数据的完整性等。这些问题中,其中有三类是读问题,分别是:脏读、不可重复读、幻读。

    1. 脏读(dirty read):在一个事务中,读取到另一个事务未提交更新的数据,即读取到了脏数据;

      例如:A给B转账100元但未提交事务,在B查询后,A做了回滚操作,那么B查询到了A未提交的数据,就称之为脏读。

      提示:需要将数据库的事务隔离级别设置为最低,才能够看到脏读现象
      事务1:开启事务; A - 100 = 900; B + 100 = 1100; (没有提交事务)
      事务2:开启事务; 查询B账户的金额 1100, 这个过程叫做脏读, 1100就是一个脏数据
      
    2. 不可重复读(unrepeatable read):对同一记录的两次读取结果不一致,因为在两次查询期间,有另一事务对该记录做了修改(是针对修改操作)

      例如:在事务1中,前后两次查询A账户的金额,在两次查询之间,另一事物2对A账户的金额做了修改(并且也提交了事务),此种情况可能会导致事务1中,前后两次查询的结果不一致。这就是不可重复读。

      事务1:开启事务---
          第一次读取A账户的金额:1000
          第二次读取A账户的金额:900
      事务2:开启事务---
          A账户 - 100 = 900;
          提交事务---
      
    3. 幻读(虚读)(phantom read):对同一张表的两次查询结果不一致,因为在两次查询期间,有另一事务进行了插入或者是删除操作(是针对插入或删除操作);

      事务1:开启事务---
          select * from acc where id=3;//不存在id为3的记录
          insert into acc value(3,'C',2000);
          select * from acc where id=3;//存在id为3的记录
      事务2:开启事务---
          insert into acc value(3,'C',2000);
          提交事务---
      

    注意:mysql默认的是不允许出现脏读和不可重复读,所以在下面演示之前需要设置mysql允许出现脏读、不可重复读等。

    set tx_isolation='read-uncommitted'; -- 设置mysql的事务隔离级别
    

    扩展-事务隔离级别

    事务隔离级别分四个等级,在相同数据环境下,对数据执行相同的操作,设置不同的隔离级别,可能导致不同的结果。不同事务隔离级别能够解决的数据并发问题的能力也是不同的。

    查询当前事务隔离级别:

    select @@tx_isolation;
    

    设置隔离级别:

    set tx_isolation='级别参数';
    

    级别参数可取值4中, 如下:

    1. READ UNCOMMITTED(读未提交数据)

      安全性最差,可能出现任何事务并发问题(比如脏读、不可以重复读、幻读等)

      但性能最好(不使用!!)

    2. READ COMMITTED(读已提交数据)(Oracle默认)

      安全性较差

      性能较好

      可以防止脏读,但不能防止不可重复读,也不能防止幻读;

    3. REPEATABLE READ(可重复读)(MySQL默认)

      安全性较高

      性能较差

      可以防止脏读不可重复读,但不能防止幻读问题;

    4. SERIALIZABLE(串行化)

      安全性最高,不会出现任何并发问题,因为它对同一数据的访问是串行的,非并发访问;

      性能最差;(不使用!!)

      MySQL的默认隔离级别为REPEATABLE READ,即可以防止脏读和不可重复读

    隔离级别总结

    MySQL查询当前的事务隔离级别

    select @@tx_isolation;
    
    1. set tx_isolation='read-uncommitted'; 

      安全性最差,容易出现脏读不可重复读幻读,但性能最高

    2. set tx_isolation='read-committed';

      安全性一般,可防止脏读,不能防止不可重复读幻读

    3. set tx_isolation='repeatable-read';

      安全性较好,可防止脏读不可重复读,但不能防止幻读

    4. set tx_isolation='serialiable';

      安全性最好,可以防止一切事务并发问题,但是性能最差。

    JDBC设置事务隔离界别

    JDBC中通过Connection提供的方法设置事务隔离级别:

    Connection.setTransactionIsolation(int level)
    

    leve参数可选值如下:

    Connection.TRANSACTION_READ_UNCOMMITTED 1(读未提交数据)
    Connection.TRANSACTION_READ_COMMITTED 2(读已提交数据)
    Connection.TRANSACTION_REPEATABLE_READ 4(可重复读)
    Connection.TRANSACTION_SERIALIZABLE 8(串行化)
    Connection.TRANSACTION_NONE 0(不使用事务)
    
    

    提示:在开发中,一般情况下不需要修改事务隔离级别

  • 相关阅读:
    Java 添加条码、二维码到Word文档
    我的博客园博客开通了
    新浪博客发博文老是提示系统繁忙、请稍后再试解决方法
    阿里云服务器https改造全过程
    网站从HTTP移动到HTTPS
    Apache ab性能测试结果分析
    Memcached与Redis的区别和选择
    binlog2sql使用介绍
    Mysql查看连接数(连接总数、活跃数、最大并发数)
    测试流程规范--测试准入、准出、停止标准、bug优先级定义
  • 原文地址:https://www.cnblogs.com/liqbk/p/13159311.html
Copyright © 2011-2022 走看看