事物

什么是事物

Transaction 其实是一组操作,里面包含了很多的单一的逻辑。只要有一个逻辑没有执行成功,那么这个事物就是失败的,这个时候所有的数据回滚到最初始的状态(回滚)

事物有什么作用

处理一组逻辑,如果其中一个逻辑不成功就是失败。
例子:银行转账,当A转账给B,突然断电,转账失败,数据回滚最初的状态

事物怎么用

1、事物不是针对的数据库,而是只针对数据库连接的对象(connection),如果再开一个对象,默认是自动提交的
2、事物会自动提交的

使用命令行方式演示事物

  • 开启事务
    start transaction
  • 提交或者回滚事物
    commit:提交事物
    rollback:回滚事物
  1. 关闭自动提交的功能

命令:show variables like ‘%commit%’
查询含有commit字符串的所有变量名称(variables变量的意思)
命令:set autocommit = off
关闭自动提交事物的功能(auto自动commit提交,off关闭)
事物 和 数据库连接池 和 DBUtils

  1. 演示事物

只有当commit才提交数据,数据库表中的数据才会改变,如果不提交,表中数据是不会变的。
原来表中数据zhangsan:1000 lishi:1100,zhangsan减去100,张三的数据在命令行中查的话是改变了,但是数据库中没变,可以使用数据库工具查看。只有commit提交之后才会改变

事物 和 数据库连接池 和 DBUtils

使用代码的方式演示事物

代码里面的事物,主要针对连接来的(Connection con)
事物,只会针对于 增 删 改 操作,查询不会修改数据,用不到事物

  1. 通过con.setAutoCommit(false); 来关闭自动提交事物的设置
  2. 通过con.commit(); 提交事物
  3. 通过con.rollback(); 回滚事物
@Test
    public void textTransaction(){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            //默认是自动提交事物的
            conn = JDBCUtil.getConn();
            //关闭自动提交事物的功能
            conn.setAutoCommit(false);
            String sql = "update account set money = money - ? where id = ?";
            ps = conn.prepareStatement(sql);

            //给ID为1的用户减少 100 块钱
            ps.setInt(1,100);
            ps.setInt(2,1);
            ps.executeUpdate();

            int a = 10 / 0;

            //给ID为2的用户增加 100 块钱
            ps.setInt(1,-100);
            ps.setInt(2,2);
            ps.executeUpdate();

            conn.commit();
        } catch (SQLException e) {
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            JDBCUtil.closeResource(conn,ps,rs);
        }
    }

事物的特性ACID【面试】

  • 原子性

指的是,事物中包含的逻辑,不可分割

  • 一致性

指的是,事物执行的前后,数据的一致性

  • 隔离性

指的是,事物在执行期间,不受其他事物的影响

  • 持久性

指的是,事物执行完毕之后,数据应该持久的保存在磁盘上

事物的安全问题和隔离级别【面试】

安全问题

不考虑事物的隔离级别的设置,那么会出现 读问题,和 写问题

List item

读问题

  1. 脏读:指的是,一个事物读取到另一个事物还未提交的数据
  2. 不可重复读:一个事物读到了另一个事物提交的数据,导致两次查询前后数据不一致
  3. 幻读:一个事物读到了另一个事物已经提交的插入的数据,导致多次查询的结果不一致

写问题(丢失更新)

: 丢失更新
事物 和 数据库连接池 和 DBUtils

丢失更新解决办法

  • 悲观锁

可以在查询的时候,加入 for update

事物 和 数据库连接池 和 DBUtils

  • 乐观锁

要求程序员自己控制。

事物 和 数据库连接池 和 DBUtils

隔离级别

  • 读未提交(Read Uncommitted)

引发“脏读”
指的是,一个事物读到另一个事物还未提交的数据,引发“脏读”,读取到的是数据库内存上的数据,而并非是真正磁盘上的数据

例子:

  1. 开启一个命令行窗口A, 开始事务,然后查询表中记录。 设置当前窗口的事务隔离> 级别为 读未提交 命令如下:

      //查询当前事物的隔离级别
     select @@tx_isolation;   
     //设置当前窗口 事物 隔离级别为 read uncommitted
     set session transaction isolation level read uncommitted;
    
  2. 另外在打开一个窗口B, 也开启事务, 然后执行 sql 语句, 但是不提交

  3. 在A窗口重新执行查询, 会看到B窗口没有提交的数据。

  • 读已提交(Read committed )

解决脏读,引发不可重复读
与前面的读未提交刚好相反,这个隔离级别是 ,只能读取到其他事务已经提交的数据,那些没有提交的数据是读不出来的。
但是这会造成一个问题是:前后读取到的结果不一样。 发生了不可重复!!!, 所谓的不可重复读,就是不能执行多次读取,否则出现结果不一 。

例子1:

  1. 开启一个命令行窗口A, 设置A窗口的隔离级别为 读已提交,开始事务,然后查询表中记录。 设置当前窗口的事务隔离级别为 读已提交 命令如下:

       set session transaction isolation level read committed;
    
  2. 另外在打开一个窗口B, 也开启事务, 然后执行 sql 语句, 但是不提交

  3. 在A窗口重新执行查询, 是不会看到B窗口刚才执行sql 语句的结果,因为它还没有提交。

例子2:

  1. 设置A窗口的隔离级别为 读已提交
  2. A B 两个窗口都开启事务, 在B窗口执行更新操作。
  3. 在A窗口执行的查询结果不一致。 一次是在B窗口提交事务之前,一次是在B窗口提交事务之后。
  • 重复读(Repeatable Read)

解决脏读,不可重复读。 不能解决幻读
Repeatable Read 【重复读】 - MySql 默认的隔离级别就是这个。
该隔离级别, 可以让事务在自己的会话中重复读取数据,并且不会出现结果不一样的状况,即使其他事务已经提交了,也依然还是显示以前的数据。
事物与事物之间是分开的,互不影响。

例子:

  1. 开启一个命令行窗口A, 开始事务,然后查询表中记录。 设置当前窗口的事务隔离级别为 重复读 命令如下:

      set session transaction isolation level repeatable read;
    
  2. 另外在打开一个窗口B, 也开启事务, 然后执行 sql 语句, 但是不提交

  3. 在A窗口重新执行查询, 是不会看到B窗口刚才执行sql 语句的结果,因为它还没有提交。

  4. 在B窗口执行提交。

  5. 在A窗口中执行查看, 这时候查询结果,和以前的查询结果一致。不会发生改变。

  • 可串行化(Serializable)

解决 脏读、不可重复读、幻读
如果有一个连接的隔离级别设置为了串行化 ,那么谁先打开了事务, 谁就有了先执行的权利, 谁后打开事务,谁就只能等着,等前面的那个事务,提交或者回滚后,才能执行。 但是这种隔离级别一般比较少用。 容易造成性能上的问题。 效率比较低。

Serializable 可以防止上面的所有问题,但是都使用该隔离级别也会有些问题。 比如造成并发的性能问题。 其他的事务必须得等当前正在操作表的事务先提交,才能接着往下,否则只能一直在等着。

分类 Value
按效率划分,从高到低 读未提交 > 读已提交 > 可重复读 > 可串行化
按拦截度划分,从高到低 可串行化 > 可重复读 > 读已提交 > 读未提交

数据库连接池

DBUtils

相关文章:

  • 2022-01-19
  • 2021-12-19
  • 2021-09-08
  • 2021-11-29
  • 2022-01-01
  • 2021-09-08
  • 2021-08-03
  • 2021-04-07
猜你喜欢
  • 2021-06-06
  • 2021-12-15
  • 2021-08-01
  • 2018-07-13
  • 2021-09-08
  • 2021-05-14
  • 2021-12-18
相关资源
相似解决方案