文章目录
1、事务基本概念
事务是指一组最小的逻辑操作单元,里面有多个操作组成。组成事务的每一部分必须要同时提交成功,如果有一个操作失败,整个操作就回滚。
2、事务的ACID特性
(1)原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
(2)一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
(3)隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
(4)持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
案例:
转账问题:包括减钱和加钱两个步骤,这是两个不同的SQL语句,默认的这是两个事务,但是这两个事务在提交的过程中,发生了异常,导致减钱成功,加钱失败,该怎么解决?
package com.westo.jdbc3;
import com.westo.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Demo {
public static void main(String[] args) throws SQLException {
Connection connection = JDBCUtils.getConnection();
String sql1="update demo2 set money=money-100 where name='张三'";
String sql2="update demo2 set money=money+100 where name='李四'";
PreparedStatement preparedStatement = connection.prepareStatement(sql1);
PreparedStatement preparedStatement1 = connection.prepareStatement(sql2);
preparedStatement.executeUpdate();
//模拟异常
System.out.println(1/0);
preparedStatement1.executeUpdate();
connection.close();
preparedStatement.close();
preparedStatement1.close();
}
}
所以,我们要把扣钱和加钱当做一个整体,放在一个事务中统一提交。
package com.westo.jdbc3;
import com.westo.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Demo1 {
private static Connection connection;
public static void main(String[] args){
try {
connection = JDBCUtils.getConnection();
//把数据的事务设置为手动提交
connection.setAutoCommit(false);
String sql1="update demo2 set money=money-100 where name='张三'";
String sql2="update demo2 set money=money+100 where name='李四'";
PreparedStatement preparedStatement = connection.prepareStatement(sql1);
PreparedStatement preparedStatement1 = connection.prepareStatement(sql2);
preparedStatement.executeUpdate();
//模拟异常
System.out.println(1/0);
preparedStatement1.executeUpdate();
} catch (Exception e) {
try {
//遇到异常回滚事务
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
try {
//不管有没有遇到异常 都提交事务
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
3、隔离级别
(1)为什么会有隔离级别?
我们知道隔离性是指一个事务执行的时候最好不要受到其他事务的影响,当我们不考虑隔离性时就会出现读问题。
(2)读问题
- 脏读:在一个事务中读取到另外一个事务没有提交的数据。
我们开启两个dos命令窗口来演示,首先要将事务的隔离级别设置为读未提交,因为MySQL默认的隔离级别是避免了这种事情的发生。
set session transaction isolation level read uncommitted;
我们可以看到,1号窗口改变数据之后,2号窗口去查询可以查到,但是当1号回滚之后,2号去查询发现查询不到了。
- 不可重复读:是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。
首先要将事务的隔离级别设置为读已提交
set session transaction isolation level read uncommitted;
我们可以看到,事务提交之前和之后,数据查询的结果是不同的,这就是不可重复度。
- 虚度(幻读):在一个事务中,两次查询的结果不一致(针对insert操作),无法演示出来,MSQL已经默认避免了。
(3)隔离级别
- read uncommitted:读未提交,上面的三个问题都会出现。
- read committed:读已提交,可以避免脏读的发生 Oracle 默认级别。
- repeatable read:可重复读,可以避免脏读和不可重复读的发生 MySQL 默认级别。
- serializable:串行化,可以避免所有的问题,但是效率比较慢。
四种隔离级别的效率
read uncommitted>read committed>repeatable read>serializable
四种隔离级别的安全性
read uncommitted<read committed<repeatable read<serializable