事务
事务指的是逻辑上的一组操作,组成这个操作的各个单元,要么都成功,要么都不成功
例如A给B转账,这个业务包含两个步骤
- 给A的账户扣钱
- 给B的账户加钱
组成这个业务的这两个步骤,要么就都成功,要么就都不成功。
事务的使用
事务相关的API
//开启事务 connection.setAutoCommit(false); //具体执行步骤 //提交事务 connection.commit(); //回滚事务 connection.rollback();
转账的案例的具体实现:
public static Boolean transfer(String fromName, String toName, Integer money) { //获取连接 Connection connection = JDBCUtils.getConnection(); //开启事务 try { connection.setAutoCommit(false); } catch (SQLException e) { e.printStackTrace(); } try { //执行步骤 //给from的扣钱 PreparedStatement preparedStatement = connection.prepareStatement("update account set money = money-? " + "where " + "name = ?"); preparedStatement.setInt(1, money); preparedStatement.setString(2, fromName); //执行 int affectRows = preparedStatement.executeUpdate(); if (affectRows != 1) { System.out.println("扣钱失败!!!"); return false; } //给toName加钱 preparedStatement.setInt(1, (-money)); preparedStatement.setString(2, toName); int affectRows1 = preparedStatement.executeUpdate(); if (affectRows1 != 1) { System.out.println("加钱失败!!!"); return false; } else { //执行到这里说明扣钱和加钱都成功了,提交事务 connection.commit(); return true; } } catch (Exception e) { //如果出现异常,就要回滚事务 try { connection.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } System.out.println("回滚成功"); } return false; }
事务的四个特性
ACID
- 原子性(A)
事务是不可分割的工作单位,事务中的操作要么都发生,要么都不发生 - 一致性©
一致性指的是事务必须使数据库的一个一致性状态到另一个一致性状态;保证数据的整体一致性 - 隔离性(I)
事务与事务之间应该互不影响 - 持久性(D)
事务一旦提交,对数据库的改变是永久性的
事务的隔离级别
事务与事务之间有不同的隔离级别,对事务间的隔离有不同的结果
如果是多线程并发访问共同数据的时候,会存在以下问题:
- 脏读
脏读是指一个事务读取到了另一个事务还没有提交的数据 - 不可重复读
同一份数据在同一个事务中读取的结果前后不一致。实际上是一个事务读取到了另一个事务已经提交的数据 - 虚幻读
在同一个事务中,有些记录有时候能读到,有时候读不到,常见于执行插入和删除操作的时候
MySQL中有以下隔离级别
- read uncommitted 读未提交
- read committed 读已提交
- repeatable read 可重复读(MySQL默认的隔离级别)
- serializable 串行化
在cmd中查看数据库的隔离级别的方法
-- 查看数据库的隔离级别 select @@tx_isolation; -- 修改数据库的隔离级别 set global transaction isolation level xxx; -- 修改完了之后需要重新建立连接
读未提交
read uncommitted:指一个事务可以读取到另一个事务未提交的数据
存在如下问题:脏读、不可重复读、虚幻读
读已提交
read committed:指一个事务只能读取到另一个事务已提交的数据
存在的问题:不可重复读、虚幻读
可重复读
repeatable read 可重复读(MySQL默认的隔离级别):相当于一个事务只会读取到事务开启时的数据,无论其他事务做什么操作,都不会更改;
MySQL的存储引擎InnoDB解决了虚幻读的问题
串行化
serializable 串行化:让事务串行执行,相当于单线程,不能并发
一个事务必须等待其他事务执行,这样没有安全隐患
存在的问题:效率低
脏读 | 不可重复读 | 虚幻读 | |
read uncommitted | √ | √ | √ |
read committed | X | √ | √ |
repeatable read | X | X | X |
serializable | X | X | X |
安全性越高,效率越低