`

mysql事物

 
阅读更多

事物(基于 innodb 引擎的数据库,对于 myisam 引擎数据库就不支持事务)

1、事务是指逻辑上的一组操作,组成这组操作的各个单元,要不全成功要不全失败。

例如:A-B 转账,对应的如下 sql 语句

update from account set money=money-100 where name='a';

update from account set money=money+100 where name='b';

数据库默认事务是自动提交的, 也就是发一条 sql 它就执行一条。如果想多条 sql 放在一个事务中执行,则需要使用事务进行处理。当我们开启一个事务,并且没有提交,mysql 会自动回滚事务。或者我们使用 rollback 命令手动回滚事务。

 

2、数据库开启事务命令:

start transcation 开启事务

rollback 回滚事务

commit 提交事务

上面这个实验是 a 向 b 转账 100 元,那么就有两条更新的 sql 语句需要执行,所以我们需要将这两个 sql 作为一个事务进行操作,要么更新都成功,要么更新都失败。在开始的时候我们将 mysql 的自动提交关闭。connnectino.setAutoCommit(false); 我们将手动控制事务的提交行为。在执行更新操作的时候有可能出现意外情况,导致交易终止,所以我们将捕获可能出现的异常,在处理异常的时候为了保证数据库的一致性,我们必须将上面的事务操作进行回滚,取消双方的交易。connectino.rollback(); 如果没有意外情况,那么程序继续执行,最后我们将事务一起提交。connection.commit(); 现在假设有这样一种情况,即使中间出现了意外情况,那么我们也不想将事务中的所有 sql 语句都回滚,我们可以在想要保留的操作后面增加一个还原点。connection.setSavepoint(),用一个 Savepoint 对象接收,在异常情况出现以后,我们进行回滚操作的时候将回滚到我们的还原点上。然后提交数据。connection.rollback(savepoin); 这样就形成了还原点以前的更新操作可以执行。注意,我们通常在 rollback 以后进行一下 commit 操作,这样是为了避免一些想要执行的操作丢失的问题。

 

二、事物的四大特性(ACID

1、原子性(Atomicity

事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

2、一致性(Consistency

事务前后数据的完整性必须保持一致。

3、隔离性(Isolation

多个用户并发访问数据库时,一个用户的事务不能被其它用户的事物所干扰,多个并发事务之间的数据要相互隔离。

4、持久性(Durability

一个事务一旦被提交,它对数据库中的数据改变就是永久性的。

 

事务的隔离级别:

多个线程开启各自的事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个线程在获取数据时的准确性。如果事务不考虑隔离性会引发以下问题:

(1)脏读:

指一个事务读取了另外一个事务未提交的数据。比如 A 向 B 购买商品,如果 B 的事务隔离级别为最低的 read uncommitted,那么当 A 执行了 update account set money=money+100 where name='B';以后并没有提交数据的时候,B 进行了 select money from account where name='B';查询账户的操作,由于 B 的事物隔离级别最低,所以导致了脏读,读取到了 A 没有提交的数据,当 A 执行了 rollback 回滚命令以后,B 再查询账户,就发现先前增加的 100 元消失了。为了避免脏读,我们可以将事务的隔离级别设置为:read committed。

(2)不可重复读:

在一个事务内读取到了表中的某一行数据,多次读取结果不同。不可重复读和脏读的区别是:脏读是读取前一事务未提交的数据,不可重复读是重新读取了前一个事务已提交的数据。比如还是刚才的情景,当 B 将自己的事务隔离级别设置了 read committed 时,可以避免脏读,也就是别人没有提交的数据是读不到的。但是如果 A 将数据提交了,执行了 commit 命令后,B 在这个当前事务内再次查询账户的时候,就发现账户多了 100 元,这种情况看似是符合逻辑的,但是我们这里说到的不可重复读是指在这个当前事务内,不可以发生两次读取操作结果不一致的可能性,我们要保证在一个事务中,我们多次从数据库获取的数据应该是一致的,这样才能保证我们进行数据操作的可靠性。为了避免这个为题,我们可以将数据库的事务隔离级别设置为:repeatable read,这样就保证了在一个事务中,每次读取到数据都是一致的。

(3)虚读 ( 幻读 )

在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。和不可重复读的区别是:不可重复读是读取到了别人对表中的某一条记录进行了修改,导致前后读取的数据不一致。 虚读是前后读取到表中的记录总数不一样,读取到了其它事务插入的数据。比如现在有 A 和 B 两个应用程序,他们并发访问了数据库中的某一张表,假设表中有 3 条记录,B 执行查询操作, 第一次查询表得到了 3 条记录。此时 A 对表进行了修改,增加了一条记录,当 B 再次查询表的时候,发现多了一条数据。这种情况就造成了 B 的虚读。但是虚读是不一定每次都发生的,这种情况是不确定的。为了避免虚读,我们可以将事物隔离级别设置为 serializable 如果设置成了这种级别,那么数据库就变成了单线程访问的数据库,导致性能降低很多。

 

为了解决以上没有考虑三个隔离性可能引发的问题,数据库定义了四种隔离级别:set transaction isolation level (设置事务隔离级别) select @@tx_isolation (查询当前事务隔离级别)

 

(1)Serializable:可避免脏读、不可重复读、虚读情况的发生。

(2)Repeatable read:可避免脏读、不可重复读情况的发生。(可重复读,是 mysql 默认的事务隔离级别)

(3)Read committed:可避免脏读情况发生。(读取已提交的数据)

(4)Read uncommitted:最低级别,以上情况均无法保证。(读取到了未提交的数据)

 

当我们将数据库的隔离级别设置为:Serializable 的时候,虽然可以避免所有并发访问的问题,但是 Serializable 采用的是单线程来解决并发访问的问题,也就是说在某一段时间内,只能有一个用户对数据库进行操作,导致其它用户阻塞。导致数据库的访问性能很差。

 

三、锁 (共享锁、排它锁、悲观锁、乐观锁、行级锁、表级锁)

1、共享锁

如果当前事务隔离级别是最高级别:serializable,那么当做查询操作时数据库会为程序分配一个共享锁。共享锁和共享锁之间是不冲突的,如果一个程序加了共享锁,另外一个程序数据库也可以为其分配一个共享锁。特点:共享锁和共享锁之间不冲突,共享锁和排它锁是冲突的。

2、排它锁

如果对数据库进行更新操作,数据库会为它的每个记录加一把排它锁,假如现在 A 程序的事务隔离级别为 serializable,A 对数据库进行查询操作,也就是数据库为表中的记录增加了一个共享锁,当 B 程序并发访问数据库时,B 对数据库进行更新操作,此时数据库就为表中的每个记录增加了一个排它锁,由于共享锁和排它锁是冲突的,数据库就无法为表记录再加排它锁,所以导致了 B 程序的阻塞。这也就是为什么隔离级别是 serizlizable 时,就会将数据库访问性质为单线程,其原理就是采用了锁机制。当 A 的共享锁释放时,数据库才会为表记录再分配排它锁。如果 B 也是进行查询操作,那么此时就能成功查询,因为共享锁和共享锁不冲突。

 

更新丢失问题:

场景:老公去在 ATM 上取钱,老婆在柜台存钱,假设这个账户中有 1000 元。老公首先执行查询操作,查询到账户余额为 1000 此时程序将 1000 拿到内存中,老公取了 200 元,程序就执行了更新操作将账户余额改为 800,但是当老公的程序没有 commit 的时候,老婆查询账户,此时账户余额还是 1000 元,老婆存入 200 元,程序执行了更新操作将账户余额改为 1200,然后老公将更新语句提交,接着老婆也将更新语句提交。最后导致的结果就是该账户的余额为 1200,这就是更新丢失的问题。引发更新丢失的根源就是查询上,因为双方都是根据从数据库查询到的数据再对数据库中的数据进行更新的。解决更新丢失有三个方案:(1) 将事务隔离级别设置为最高,采用死锁策略。(2) 采用悲观锁,悲观锁不是数据库中真正的锁,是人们看待事务的态度。(3) 采用乐观锁,乐观锁也不是数据库中真正的锁。

如果我们采用的是第一个方案时,老公进行查询操作,数据库为表增加了共享锁,老婆进行查询操作时数据库也增加了一个共享锁。但是当老公进行更新数据库操作时,由于老婆拿着共享锁,导致老公不能增加排它锁,老婆进行更新操作时,因为老公拿着共享锁,导致老婆也拿不到排它锁,这就发生了死锁现象,你等我,我等你。在 mysql 中,处理死锁的方案是释放掉一方的锁。这样就保证了一方更新成功,但是这种性能极低,因为数据库频繁在解决死锁问题。

3、悲观锁(更新多,查询少时用)

如果我们采用的是第二个方案时,即采用悲观锁。就是我们在操作数据库时采用悲观的态度,认为别人会在此时并发访问数据库。我们在查询语句中 select * from account where name='aaa' for update; 等于加了排它锁。当老公查询余额的时候,select money from account where name='aaa' for update; 增加了排它锁,老婆查询账户余额的时候, select money from account where name='aaa' for update;也要求对数据库加排它锁,因为老公已经拿到了排它锁,导致老婆不能加锁,所以老婆只有等待老公执行完毕,释放掉锁以后才能继续操作。

4、乐观锁(更新少,查询多时用)

如果我们采用的是第三个方案时,即采用乐观锁,就是我们在操作数据库的时候会认为没有其它用户并发访问,但是乐观锁也不是完全乐观的,乐观锁是采用版本号的方式进行控制的。在数据库表中有一列版本号。从数据库中查询的时候,将版本号也查询过来,在进行更新操作的时候,将版本号加1,查询条件的版本号还是查询过来的版本号。比如,老公执行查询操作的时候,select money,version from account where name='aaa'; 假设此时查询到的版本号为 0,老公在进行更新操作的时候 update account set money=money+100,version=version+1 where name='aaa' and version=0; 未提交时老婆来查询,查询到的版本号依然是 0,老婆也执行更新操作 update account set money=money+100,version=version+1 where name='aaa' and version=0; 现在老公提交了事务,老婆再提交事务的时候发现版本号为 0 的记录没有了,所以就避免了数据丢失的问题。不过这种情况也导致了多个用户更新操作时,只有一个用户的更新被执行。

5、行级锁(为某一条记录加锁)

如果想对数据库中的某条记录加行级锁,那么 where 条件后面必须为索引列。否则 for update 加的都是表级锁。行级锁就是只对要访问的当前行加锁,其他用户访问其它行记录的时候可以访问。 select * from account where id=1 for update;

6、表级锁(为一张表加锁)

在查询语句后增加 for update 时,where 条件后不是索引列,那么此时都是表级锁。select * from account where name='aaa' for update;

分享到:
评论

相关推荐

    MySQL事物实现原理之组提交(group commit).pdf

    MySQL的事务处理机制是数据库管理系统的重要组成部分,它确保了数据的一致性、原子性、隔离性和持久性(即ACID属性)。在MySQL中,事务的实现依赖于其强大的事务日志系统,而组提交(group commit)技术则是提高事务...

    nodejs + mysql 事务处理问题

    nodejs + mysql 事物处理问题 呵呵 看了就知道 记得npm install啊 需要的东西啊 本想免费 苦于没积分 ,需要的的同学,给点分吧

    swoolemsyqlproxy一个基于mysql协议swoole开发的mysql数据库连接池

    支持读写分离 支持数据库连接池,能够有效解决PHP带来... 支持SQL92标准 遵守Mysql原生协议,跨语言,跨平台的通用中间件代理。 支持多个数据库连接,多个数据库,多个用户,灵活搭配。...支持mysql事物 采用协程调度

    Java面试题mysql数据库和jvm知识面试题用于技能提升和面试提升

    ### MySQL事物 事务是数据库中保证数据一致性的基础。ACID特性(原子性、一致性、隔离性和持久性)是事务的核心。掌握如何在MySQL中开始和结束事务,理解事务的四种隔离级别(读未提交、读已提交、可重复读、串行化...

    MySQL-acid-mvcc以及=事物隔离级别

    MySQL事务ACID和MVCC机制 MySQL事务是指一组操作的集合,作为一个单元执行, garantying atomicity、consistency、isolation 和 durability 四个基本特性。其中ACID是指Atomicity、一致性、Isolation 和 ...

    VB6连接MySQL数据库实例含驱动和源代码

    在VB6(Visual Basic 6)中连接MySQL数据库是一项基础且重要的技能,尤其对于初学者而言。本实例将提供一个完整的解决方案,包括所需的驱动程序和源代码,帮助开发者理解如何在VB6环境中与MySQL数据库进行交互。 ...

    面试mysql 之索引 锁 事物

    ### MySQL索引、锁与事务详解 #### 一、索引 **索引定义与作用:** 索引是一种数据结构,用于加速数据检索的过程。它通过建立数据表中某些列的值与行的位置之间的映射关系,使得数据库系统能够快速定位到所需的...

    一个关于mysql 事务管理的介绍

    MySQL 事务管理是数据库操作的重要组成部分,特别是在处理关键数据和多步骤操作时,确保数据的一致性和完整性至关重要。事务提供了原子性、一致性、隔离性和持久性的保障,这四个特性通常被简称为ACID属性。 原子性...

    mysql5.5.28.zip

    然而,为了实现快速、健壮和易用的目的,MySQL必须牺牲一部分灵活而强大的功能,如子查询、存储过程与触发器、外键、事物处理等。因而,MySQL在某些应用中缺乏灵活性,但这也使它对数据的处理速度较其它数据库服务器...

    Mysql中的事务是什么如何使用

    MySQL中的事务是数据库管理系统中的一种重要机制,它用于确保数据一致性与可靠性。事务是一系列数据库操作的集合,这些操作被视为单个逻辑工作单元,要么全部成功执行,要么全部不执行。这种所有操作“全有或全无”...

    基于JDBC同步Oracle到MySQL

    分别有:数据源配置、数据表结构转换、字段更新、数据迁移、根据oracle SQL的UPDATE DELETE 事物执行记录转为Mysql可执行SQL,同步执行到MySql数据库,此项目为个人兴趣爱好练手项目,项目问题欢迎留言,共同进步...

    SpringBoot+Mybatis+Atomikos+Mysql+Oracle 多数据源分布式事物后台搭建

    SpringBoot+Mybatis+Atomikos+Mysql+Oracle 多数据源分布式事物后台搭建 完整demo包,直接下下来解压,数据库配成自己的库,表自己的表,修改下脚本直接跑,网上大把资料,没一个能直接用的,这里花了点时间稍做...

    MySQL锁模型与事物

    MySQL数据库在并发环境下为了保证数据的一致性和完整性,采用了多种锁模型和事务处理机制。本文将深入探讨MySQL的锁机制及其事务管理,帮助你更好地理解数据库的并发控制。 首先,我们要了解MySQL中的两种主要锁...

    Mysql基础语法及脚本.zip

    Mysql基础语法及脚本,非常适合新人学习,里面有2个Demo及脚本,第一个适合...事物,回滚,视图等,写给一个完全不会mysql的人学习看的,所有都标记了中文注释,应该比较好理解,建议用Notepad++等文本编辑器打开,格式会好看点

    MySQL软件的安装

    非关系型数据库(NoSQL)指的是分布式的、非关系型的、不保证遵循 ACID(事物的操作)原则的数据存储系统。NoSQL 数据库利用 key-value 可以大量的获取大量的非结构化数据,并且数据的获取效率很高,但用它查询结构...

    MySQL数据库项目式教程完整版课件全书电子讲义教材课件(完整).pptx

    * 信息(Information):是现实世界事物的存在方式或运动状态的反映,它通过多种形式展现,如文字、数码、符号、图形、声音等。 * 数据(Data):是对客观事件进行记录并可以鉴别的符号,是数据库中存储的基本对象,...

    C#链接MySql最全帮助类,DbHelperMySQL.cs

    已完成所有数据库操作方法的封装,如:添加、修改、查询、删除、事物查询、存储过程等十几个方法,可供直接使用,使C#开发人员快速开发。 适合C#、.net等后端开发人员,级初级开发人员,快速开发中小型项目,无需...

    mysql的存储过程、游标 、事务实例详解

    MySQL的存储过程、游标和事务是数据库管理中非常重要的概念,它们在处理大量数据和实现复杂的业务逻辑时起着关键作用。以下是对这些概念的详细解释和实例分析。 **存储过程**: 存储过程是一组预编译的SQL语句,以...

    MySQL学习笔记、学习文档

    alter语句.txt ...SQL-Transaction事物一起执行.txt sq和oracle的区别.txt sysobjects中type字段值意思txt W3School例句.txt 按照中文首字母排序.txt 笔记.txt 查询字段是否有默认值约束.bxt 触发器学习.bxt

    mysql-5.5.50-winx64.zip

    例如,它支持并行复制,这意味着在一个主服务器上执行的多个事物可以同时在多个从服务器上并行处理,大大提高了数据同步的速度。此外,优化了查询缓存,使得经常查询的数据能更快地被返回,减轻了数据库服务器的负担...

Global site tag (gtag.js) - Google Analytics