Java_MySQL数据库事务

本文深入探讨了数据库事务的重要性和作用,通过转账案例解释了事务的原子性、一致性和隔离性。介绍了MySQL的自动和手动事务管理,以及如何设置和回滚事务。此外,还讲解了回滚点的概念及其在大量数据操作中的应用。同时,文章阐述了数据库事务的四个隔离级别,包括脏读、不可重复读和幻读问题,并说明了不同隔离级别对这些问题的解决策略。最后,讨论了如何查看和设置数据库事务的隔离级别。
摘要由CSDN通过智能技术生成

1. 介绍

数据库事务是指逻辑上的一组操作,肯定是两个及两个以上操作,作用是保证这一组操作全部成功或失败。

加入A转账1000给B,这个其实就是一组操作:

  • A的账户减去1000
  • B的账户加1000

有了事务控制之后,这个转账过程就有两个操作结果,而且将以上两个操作作为一组:

  • 转账成功:A的账户要减去1000,B的账户加1000
  • 转账失败:A,B的账户都不会发生变动

如果没有事务控制,那么可能会发生以下状况:
A 的账户减去1000,但由于后续的执行中发生了异常,这样B的账户无法加1000,从而导致出现数据一致性的微调,出现了脏数据。

  • 测试数据准备
create database if not exists finance;
use finance;
-- 创建账户表
create table finance_account(
    id int primary key auto_increment,
    name varchar(64),
    balance decimal(10,2)
);
-- 清空表数据
truncate table finance_account;
-- 增加测试账号
insert into finance_account values(null,'tony',200000.00),(null,'jcak',0.00);
-- 查看表
select * from finance_account;

数据准备

2. MySQL数据库事务管理

MySQL数据库事务管理默认情况下是自动事务管理,也是默认开启事务,自动提交事务。
每一条SQL在执行的时候都会自动开始和提交事务。

  • 查看和修改MySQL的事务管理
show variables like '%autocommit%';
-- 修改事务状态关闭自动提交,0-关闭,1-开启
set autocommit =0;

由于MySQL数据库的事务管理是自动开启,自动提交。当一组操作的某个操作执行发生异常的时候,这样会出现数据的不一致问题。
因此需要手动开启和提交事务。
语法:
手动开启事务:

start transaction;

手动提交事务:

commit;

手动回滚事务:执行过程中发生了异常需要回滚事务,即回退到开启事务之前的状态

rollback;

只有在开启事务/提交事务和开启事务/回滚事务之后,事务才会结束。
手动事务的使用:1.正常状态

start transaction ;
update finance_account set balance=balance-100000 where name='tony';
update finance_account set balance=balance+100000 where name='jack';
commit ;

正常状态
手动事务的使用:2.异常状态

start transaction ;
update finance_account set balance=balance-100000 where name='tony';
update finance_account set balance=balance+100000 where name='jack';
rollback ;

3. 回滚点

3.1 回滚点的概念

在一组操作中,某些操作成功后,后续的操作可能成功或失败,但是不管后面的成功或失败,前面操作已经成,可以在当前成功的位置设置一个回滚点,这样可以供后续失败的操作返回到该回滚点的位置,而不是返回操作之前的状态。

3.2 回滚点的设置和回滚

  • 设置回滚点 savepoint 回滚点名称;
  • 回滚回滚点 rollback to 回滚点名称;,此时事务没有结束,需要手动提交

3.3 回滚点的使用

1.不适用回滚点–展示

-- 不使用回滚点
start transaction ;
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance+100000 where name='jack';
-- rollback 会回到处理之前
rollback ;
  • 一定要写rollback,这样手动事务才会结束。再次强调:
    只有在开启事务/提交事务和开启事务/回滚事务之后,事务才会结束。即start transaction /commit 或 start transaction / rollback

运行前后的结果一样:
结果
2. 使用回滚点

start transaction ;
-- 假设这5步成功
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
-- 因此可以设置回滚点
savepoint sign;
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance+100000 where name='jack';
-- 假设以上6步发生异常,需要回滚,但是设置了回滚点,因此不需要回退到原状态,只需要回滚到回滚点
rollback to sign;

update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance-10000 where name='tony';
update finance_account set balance=balance+100000 where name='jack';
commit ;

使用回滚点

3.4 回滚点的使用场景

再插入大量(百万)数量的时候可以使用,假设插入500万条数据,此时将这个操作为整体,使用事务控制,在插入500万条数据是,前200万成功,此时可以设置一个回滚点,但是后面的300万插入时遇到了异常,此时就可以回退到200万数据设置的回滚点,这样就可以少插入200万条数据。

4. 数据库事务的特性(重要)

  • 原子性(Atomicity):指的是数据库事务作为一个不能分割的整体,事务中的操作要么发生,要么都不发生
  • 一致性(Consistency):值的是数据库事务前后的数据必须保持一致
  • 隔离性(Isolation):数据库事务的隔离性是指多个用户并发操作数据库,一个用户的事务不能被其他用户的事务干扰,多个并发事务之间需要隔离,简单来说,事务之间互不干扰,前提条件是:事务的隔离级别设置得当
  • 持久性(Durability):事务一旦提交,他对数据库中数据的变更是永久性的,即使接下来数据库发生了故障,也不会有任何影响,因为事务的提交会将数据写入数据库,无法撤回。

5. 数据库事务的隔离级别

隔离级别设置不当会引发那些问题

多个事务在操作的时候理想状态下,所有事务相互隔离,互不影响。但是由于并发操作,由于数据库事务的隔离级别设置不当,当多个用户访问同一个数据时候,会引发一些并发访问的问题。例如脏读,不可重复读,幻读。

5.1 脏读

指的是:一个事务读到了另一个事务中没有提交的数据

5.2 不可重复读

指的是:一个事务读到了另外一个事务中已经提交的数据。一个事务中两次读取的数据内容不一致,但是要求一个事务中多次读取的内容必须要一致。不可重复读的原因是update导致引发的问题

5.3 幻读

指的是:一个事务中两次读取的数据的数量不一致,要求一个事务中多次读取数据的数量必须一致,这种幻读问题是由于 insert或delete导致的。

5.4 数据库事务的隔离级别

可以通过设置事务的隔离级别来解决脏读、不可重复读和幻读。

级别隔离级别中文名字隔离级别英文名字脏读不可重复读幻读数据库的默认隔离级别
1读未提交read uncommitted
2读未提交read commited否(没有脏读问题)Oracle
3可重复读repeatable readMySQL
4串行化serializable

串行化:指的是一个事务在操作数据,另一个事务只能等待这个事务操作完成之后再进行其他的操作。
设置数据库事务的隔离级别是read commited 就可以解决脏读问题;设置数据库事务的隔离级别是 repeatable read 就可以解决不可重复读问题;设置数据库事务的隔离级别是 serializable 就可以解决幻读问题; 隔离级别越高,安全性越高,但是安全性越差,一般使用数据库的默认隔离级别即可。

5.5 数据库事务隔离级别的查看和设置

查看数据库隔离级别的设置
MySQL 8.0:

select  @@transaction_isolation;

MySQL查看隔离级别
设置语法:

set session transaction isolation level [X];
--X:read uncommitted,read commited ,repeatable read,serializable 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值