事务
概念
事务是指逻辑上的一组操作,组成这个操作的各个单元,要么都成功,要么就都不成功。
例如我们在进行转账的时候,假如是从A账户转账到B账户
包含两个操作
操作1: 从A账户扣钱 update account set money = money - num where name = A;
操作2:给B账户加钱 update account set money = money + num where name = B;
对于以上两个操作,那么就要保证原子性,要么这两个操作都成功,要么这两个操作都失败。
基本使用
JDBC的事务操作,有三个API配合使用控制事务
// 表示设置关闭事务自动提交功能,假如不写,默认是自动提交
connection.setAutoCommit(false);
// 手动提交事务
connection.commit();
// 手动回滚事务
connection.rollback();
案例:
/** * * @param fromName 转账发起人 * @param toName 转账受益人 * @param salary 薪水 * @return */
public Boolean transfer(String fromName, String toName, BigDecimal salary){
try {
// 两次操作使用事务来控制有一个前提,这个前提是两次操作必须是使用的同一个connection对象(微服务:分布式事务)
// 开启一个事务
connection.setAutoCommit(false);
// 扣钱
PreparedStatement statement1 = connection.prepareStatement("update account set money = money - ? where name = ?");
statement1.setBigDecimal(1,salary);
statement1.setString(2,fromName);
int affectedRows = statement1.executeUpdate();
if (affectedRows == 0 ) {
System.out.println("扣钱失败!!");
return false;
}
int i = 1 / 0;
// 加钱
PreparedStatement statement2 = connection.prepareStatement("update account set money = money + ? where name = ?");
statement2.setBigDecimal(1,salary);
statement2.setString(2,toName);
statement2.executeUpdate();
// 进行事务提交,事务提交了之后,这两次操作才会对数据库里面的数据发生改变,产生影响
connection.commit();
return true;
} catch (SQLException e) {
e.printStackTrace();
// 这个表示事务回滚
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
return false;
}
事务的四个特性(ACID)
原子性
意思就是说,我们事务中的操作都是一个整体的单元,这一系列被事务包裹的操作在执行的时候,要么都成功,要么就都不成功。
一致性
事务的一致性是指:事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
例如我们的转账案例中,事务的一致性是指,两个账户的钱的总和在转账之前与转账之后保持一致。
隔离性(*)
事务的隔离性是指:我们多个用户操作数据库的时候,那么这个时候数据库会为我们的每一个用户开启一个事务,那么这些事务之间应该是隔离的,互不影响的。
持久性
事务的持久性是指事务操作对于数据库里面的数据的变化应该是永久的,一旦改变,不可逆转。
事务的隔离级别
-
Serializable 序列化,这是最高等级的隔离级别,它是指一个事务对数据库的操作,必须在另外一个事务完成之后才能操作
不存在多个事务同时对数据库进行并发访问的情况
-
Repeatable READ 可重复读
一个事务开启之后,可以重复读取数据,前后读取到的数据始终是一致的
-
Read Committed 读已提交 指一个事物可能读取到另外一个事物已经提交的数据
-
Read uncommitted 读未提交 指一个事物可以读取到另外一个事务还没有提交的数据(最弱的隔离级别)
隔离级别产生的几种问题
脏读
指一个事务读取了另外一个事务未提交的数据
不可重复读
是指在同一个事务中,读取到的数据前后不一致
在事务提交之前,另外一个事务中读取到了一次数据,在事务提交之后,又读取了一次数据,两次读取的数据不一致
虚幻读
是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致
在mysql的innoDB引擎里面,默认使用MVCC思想解决了虚幻读的问题,所以在Mysql里面不存在虚幻读的问题。
**Mysql默认的隔离级别是:repeatable read **
Serializable这个隔离级别的效果展示
结论:说明我们在使用串行化这个隔离级别的时候,sql语句并不会并发执行,要排队一条一条执行,这样也就不会有并发的问题,但是
效率很低。
那我们一般使用什么隔离级别呢?我们一般使用默认的隔离级别:Repeatable read