mysql 事务管理
文章目录
什么是事务
简单的来说,事务是一组业务操作,这些业务操作要么全部执行成功,要么全部执行不成功。
事务的特性
事务具有四个特性
- 原子性:事务是一个不可分割的基本单位,事务的业务操作要么全部成功,要么全部不成功
- 一致性:事务执行前后数据的完整性必须一致
- 隔离性:多个事务,事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
- 持久性:持久性是指一个事务一旦被提交,它对数据库中数据的改变就是 永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
参考链接:https://blog.csdn.net/qq_20042935/article/details/88944340
mysql 中常见事务操作
开启事务
start TRANSACTION;
# or
BEGIN;
提交事务
commit
回滚
rollback
关闭自动提交事务
SET autocommit = 0;
提交事务演示事例
现有一个数据库表,其中的数据如下:
为了更好的呈现出实验效果,我又在终端连接到了mysql数据库
所以说现在一共有两个连接,一个是mysqlworkbench,一个是终端。
我在终端开启事务并向表中插入一条语句,然后在终端查看表中的数据
注意:我没有提交事务
可以看到,在终端中显示插入数据成功。
下面我们看一下mysqlworkbench中的表情况:
可以看到,workbench中并没有新插入的行,这是由于没有提交事务造成的。
我们再在终端提交事务,然后再次查看workbench中的数据。
发现插入成功,这说明一旦开启事务,需要手动commit,不然sql语句是不会生效的。
我们也可以设置关闭自动提交事务来避免每次都要手动开启事务,这样我们每次写完sql语句都需要手动commit才能使sql语句生效。
这里我设置关闭自动提交事务,然后执行一条更新语句,之后查询数据发现更新成功。
下面我们看下workbench中的情况。
发现并没有更新成功,之后我们commit。
发现更新成功。所以说我们需要手动提交才能生效。
事务隔离问题
脏读: 一个事务读到另一个事务未提交的数据
不可重复读: 一个事务读到另一个事务已提交的数据(update)
虚读(幻读): 一个事务读到另一个事务已提交的数据(insert)
mysql 事务隔离级别
read uncommitted(读未提交): 3个问题都没解决
read committed(读已提交):解决脏读
repeatable read(可重复读):解决脏读,不可重复读
serializable(串行化):都解决,单事务处理模式
注意:隔离级别越高,则性能越差
解决脏读
在这里说一下查看数据库的隔离级别:
select @@transaction_isolation
设置数据库的隔离级别:
set session transaction isolation level XXX;
首先我们先把两个数据库会话的隔离级别调成read uncommited;
之后我们在终端插入一条数据,然后查询数据,终端插入成功(并未进行commit)
然后我们查看workbench中的数据
发现也能显示插入的数据,然而终端并没有执行commit操作,我们将这种情况称为脏读。
接下来我在终端运行rollback操作。
发现,workbench也发生了变化。
我们将workbench 中的隔离级别改成read commited。
然后重复上面操作。
发现没有出现脏读的情况,说明read commited确实解决了脏读问题。
解决不可重复读
在workbech中隔离级别为 read committed 下,我们做如下实验:
在终端中更新一条数据,然后提交。
然后在workbench中开启事务,查询数据:
没有发现问题。
然后再在终端中重复上述步骤。
然后再次在workbench查询数据
发现workbech中的数据也发生了更新。在一个事务中重复读数据发现出现了不同的结果,说明还是受到了其他事务的影响,这违背了事务的隔离性,我们称这个问题为不可重复读。
解决这个问题我们可以设置workbench中的隔离级别为repeatable read。
设置workbench中的隔离级别为repeatable read之后,我们再次重复上面的实验。
第一次更新
查看workbech数据中的情况
第二次更新
workbench中的情况
我们发现没有发生变化,repeatable read 解决了不可重复读问题。
解决幻读
现在workbench中隔离级别为 repeatable read。
我们先在workbench中开启事务查看数据
一共10条数据
然后我们再在终端开启事务,向数据表中添加一条记录并提交。
此时,查看workbench中的数据
还是原来的10条数据
但是我们再workbench中执行更新操作,却发现影响了11条数据。
我们再将workbench中的事务提交,然后再查看数据
发现新插入的最后一条数据的sage也发生了更改,这就是幻读。
我们将workbench和终端中的隔离级别设为serializable
我们将最新一条的数据删掉,这样原表中还是10条数据。
然后重复上面的步骤
我们先在workbench中开启事务,查询数据,然后在终端插入一条数据。
终端在执行insert当中卡住了,之后又报错了。
原来serializable在同一时间仅允许一个事务执行,别的事务会被锁住,当此事务提交之后别的事务才会被执行。
一般在工作中,会将隔离级别设为repeatable read,因为serializable效率低下。
java 执行mysql事务操作的基本格式
ABCD 一个事务
Connection conn = null
try
{
// 1. 获得连接
conn = ...;
// 2.开启事务
conn.setAutoCommit(false);
A
B
C
D
//3.提交事务
conn.commit();
}catch(){
//4.回滚事务
conn.rollback();
}
java 执行mysql事务操作的基本格式----savepoint
AB(必须),CD(可选)
Connection conn = null;
//保存点,记录当前操作位置,之后可以回滚到指定位置(可以回滚一部分)
Savepoint savepoint = null;
try
{
// 1. 获得连接
conn = ...;
// 2.开启事务
conn.setAutoCommit(false);
A
B
savepoint = conn.setSavepoint();
C
D
//3.提交事务
conn.commit();
}catch()
{
if(savepoint!=null) //CD异常
{
conn.rollback(savepoint); // 回滚到CD之前
conn.commit(); // 提交AB
}
else
{
conn.rollback(); // 回滚AB
}
}
上一篇: 事务隔离级别