一、总 结
事务是一个最小的不可再分的工作单元。 一个事务对应一套完整的业务逻辑。事务管理机制的作用 —— 通过保证一系列数据操作过程的完整性,来保障数据的安全性。使用事务的前提条件 —— 数据库管理系统必须使用支持事务的存储引擎。MySQL中默认采用InnoDB存储引擎,默认采用【自动提交模式】来管理事务。事务机制的经典使用场景 —— 处理“银行账户之间的转账操作” 。事务只和DML语句有关,只有DML语句的出现才存在事务管理。开启事务管理的标志 —— DML语句的执行。结束事务管理的标志 —— TCL语句的执行。事务管理的四大特性 —— ACID : 【原子性、一致性、隔离性、持久性】事务之间由低到高的四个隔离级别 —— 【读未提交、读已提交、可重复读、串行化读】可以把一系列要执行的操作称为事务。而事务管理就是管理这些操作要么完全执行,要么完全不执行。反映在SQL中就是,事务只和DML语句有关。通常,一个完整的业务需要通过执行批量的DML语句之后,进行统一提交事务,才能达到效果。
二、解 析
(一)银行转账业务的分析
银行转账过程是一个完整的业务,最小的单元,不可再分,也就是说银行转账业务是一个完整的事务。
1) t_act 账户表中的数据如下: 2)需求:账户“1001”要 转账给 “1002”账户。 该一系列“转账”操作,应当会导致数据库表中的相关数据发生修改。假设转账金额是500元。 就应该执行下列两条DML语句:
update t_act set balance = 1000.0 where actno = ‘act-001’;
update t_act set balance = 500.0 where actno = ‘act-002’;
3)分析:- 以上两条DML语句必须同时成功或者同时失败,因为它为最小业务单元,不可拆分;- 当第一条DML语句执行成功之后,并不能立马将底层数据库中的第一个账户的数据修改,应该只是将操作记录了一下,这个记录是在内存中完成的。- 当第二条DML语句执行成功之后,底层数据库文件中的数据需要完成同步。- 若第二条DML语句执行失败,将清空所有的历史操作记录4)技术(机制): 要完成以上功能,那必须借助mysql数据库的“事务“机制 transaction。在mysql中并不是所有的数据存储引擎都支持事务管理的,只有 Innodb数据存储支持事务管理。且默认采用自动提交事务方式。(即执行DML语句时,默认自动提交事务。)在mysql中,,常用的3种存储引擎? 1)myISam (不支持事务) 2)InnoDB (MySql数据库默认使用是InnoDB存储引擎。该存储引擎支持事务。) 3)memory (不支持事务)2. )一个完整的业务需要批量的DML语句(insert、update、delete)共同完成。 比如:银行账户转账 业务 从A账户向B账户转账10000 , 需要执行两条update语句: update t_act set balance = balance – 10000 where actno = ‘act-001’; update t_act set balance = balance + 10000 where actno = ‘act-002’; 以上两条DML语句必须同时成功,或者同时失败,不允许出现一条成功,一条失败。 要想保证以上的两条DML语句同时成功或者同时失败,那么就需要使用数据库的“事务机制”。 思考:假设所有的业务都能使用1条DML语句搞定,还需要事务机制吗? 该情况不需要使用到事务。 但实际开发中,通常一事务【业务】需要多条DML语句共同联合完成。 事务只和DML语句有关系;当执行DML语句时,其实就是开启了一个事务。 或者说 只有DML语句(insert/ delete/ update)中才存在事务。 因为它们这三个语句都是和数据库表当中的“数据”相关的。 以上所描述的批量DML语句共有多少DML语句,这个和业务逻辑有关系。 业务逻辑不同,则DML语句的个数不同。4. )事务可以保证多个操作的原子性。即,事务的存在就是为了保证数据的完整性,安全性。* 事务可以保证多个操作的原子性:要么全部成功,要么全部失败。 对于数据库来说,事务保证批量的DML要么全部成功,要么全部失败5. )【TCL】语句是和事务相关的语句 ** rollback 或commit 的执行,标志着事务的结束。 4.事务管理?可以把一系列要执行的操作称为事务。而事务管理就是管理这些操作要么完全执行,要么完全不执行。 经典例子: A要给B转钱,首先A账户钱减少了,但由于数据库突然断电,导致无法给B账户加钱。 然后由于丢失数据,B不承认收到A的钱; 在这里事务就是确保加钱和减钱两个都完全执行或完全不执行,如果加钱失败,那么不会发生减钱。
0)-手动开启事务管理的命令start transaction 这行命令作用是: 【start transaction命令的作用】: 在mysql开启了“自动提交”模式的状态下,关闭了事务的自动提交机制,对接下来要执行的DML语句进行手动开启事务管理。 手动开启事务管理之后,从此mysql不再将DML语句执行出来的结果立即更新到表中。而是会记录到事务的日志中。只有开发者手动地进行commit提交成功之后,mysql才会将DML执行结果同步到数据库的表中。 1)-事务开启的标志 任何一条DML语句执行,都标志事务的开启。 2)-事务结束的标志 commit 或 rollback的执行,都标志着事务的结束。1)事务提交 操作 语法:commit ———— 事务成功的结束。 会将所有的DML语句操作记录 和 底层硬盘文件中数据进行一次同步。2)事务回滚 操作 语法:rollback ———— 事务失败的结束。 会将所有的DML语句操作记录全部清空。 回滚会清掉开始事务管理之后写到事务日志中的内容,即恢复到开启事务管理之前。注意:回退操作只是回退”写”的内容,对于普通的读表select语句不能回退。3)-事务管理的意义 保证数据操作的完整性,安全性。4)-注意事项在事务进行过程中,未结束之前,DML语句是不会修改底层数据库文件中的数据。只是将历史操作在内存中记录一下。只有在事务结束,而且是成功结束(提交)的时候,才会修改底层硬盘文件中的数据。 只能回滚 insert、delete和update语句,不能回滚select语句(回滚select没有任何意义)。 对于create、drop、alter这些语句也无法回滚。当 commit 或 rollback 语句执行后,事务会自动关闭(将来的更改会隐含提交)。
(二)事务管理的四大特性
1.原子性(Atomicity)
事务的整个操作是一个整体,不可以分割,要么全部成功,要么全部失败。 事务是最小的工作单元,不可再分。 只有两种结果:成功 或 失败2.一致性(Consistency)
指的是事务操作的前后,数据表中的数据没有变化。 事务必须保证多条DML语句同时成功或者同时失败。
3.隔离性(Isolation)
事务之间的操作是相互隔离不受影响的。 事务A与事务B之间具有隔离。一个事务不会影响其他的事务运行。
4.持久性(Durability)
数据一旦提交,不可改变,永久的改变数据表数据 持久性说的是最终数据必须持久化到硬盘文件中,事务才算成功的结束。 只有事务成功提交的情况下,才有持久性。 在事务完成后,该事务对数据库所做的更改将持久化地保存在数据库中,事务才算成功的结束。且不会 被回滚。
(三)事务管理的提交模式
自动提交模式的状态用于决定新事务 如何启动 以及 何时启动。 自动提交模式的开启或关闭,可以通过服务器变量AUTOCOMMIT来控制。
1-启用 自动提交模式
如果自动提交模式被启用,则单条DML语句将缺省地开始一个新的事务。 如果该语句执行成功,事务将自动提交,并永久地保存该语句的执行结果。 如果语句执行失败,事务将自动回滚,并取消该语句的执行结果。 在自动提交模式下,仍可使用start transaction语句来显式地启动事务。这时,一个事务仍可包含多条语句,直到这些语句被统一提交或回滚。
2-禁用 自动提交模式
如果禁用自动提交,事务可以跨越多条语句。 在这种情况下,事务可以用COMMIT和ROLLBACK语句来显式地提交或回滚。
三、MySql中的事务管理
(一)MySQL中事务采用自动提交模式
默认情况下,mysql的事务管理采用的是自动提交模式:DML语句的只要执行一条DML,就开启了事务,并提交这次事务;于是执行结果会立马同步到到数据表中。
0.查询事务管理状态
show variables like 'autocommit';
查询结果 —— ON值,代表自动提交。
查询结果 —— OFF值,代表 不是自动提交。 需要手动执行 commit;
1.关闭自动提交事务
(1)使用命令
在自动提交模式开启的情况下,关闭事务的自动提交,手动开启事务。step1: start transaction; // 该SQL命令含义:关闭了事务的自动提交机制,手动开启事务管理。step2: 执行若干条DML语句。step3: commit; // 进行事务的提交start transaction命令的作用: 在mysql开启了“自动提交”模式的状态下,关闭了事务的自动提交机制,对接下来要执行的DML语句进行手动开启事务管理。 手动开启事务管理之后,从此mysql不再将DML语句执行出来的结果立即写到表中,而是会记录到事务的日志中。只有开发者手动地进行commit提交成功之后,mysql才会将DML执行结果同步到数据库的表中。
(2)修改变量值
MySql中事务的自动提交模式。该方式只对当前会话有效 (将off值改为on,则为”开启”)
set autocommit=off;
或
set autocommit=0;
或
set session autocommit = off
关闭后自动提交事务之后,则需要commit来执行每一条语句,相当于手动开启了事务管理。
不过注意的是set autocommit针对的是会话变量,所以这个设置只在此次会话连接中生效。
2.开启自动提交事务
set autocommit=on;
或
set autocommit=1;
(二)事务间的隔离性
1.引发的相关问题
隔离性是事务管理的四大特性之一,事务之间存在隔离级别。事务的隔离级别决定了事务之间可见的级别。
理论上隔离级别包括4个: 低 ——高因事务之间的隔离性引发的相关问题当多个客户端并发地访问同一个表时,可能出现下面的一致性问题:
(1)脏读取
一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交,这就出现了脏读取(Dirty Read)。
(2)不可重复读
在同一个事务中,同一个读操作对同一个数据的前后两次读取产生了不同的结果,这就是不可重复读(Non-repeatable Read)。
(3)幻像读
幻像读(Phantom Read)是指在同一个事务中以前没有的行,由于其他事务的提交而出现的新行数据。
2.事务的隔离级别
InnoDB 存储引擎支持这四种事务的隔离级别。用以控制事务所做的修改,并将修改通告至其它并发的事务: 1-read uncommitted 读未提交 2- read committed 读已提交 3- repeatable read 可重复读 4- serializable 串行化(序列化)
(1)read uncommitted
对方事务A还没有提交,我们当前事务B可以读取到对方未提交的数据。 这里读到的数据,叫“脏数据”或 “脏读 Dirty Read” 读未提交存在脏读(Dirty Read)现象:表示读到了脏的数据。 1) 事务A和和事务B,事务A未提交的数据,事务B可以读取。(允许一个事务可以看到其他事务未提交的修改。) 2) 这里读取到的数据可以叫做“脏数据”或“脏读 Dirty Read” 3) 读未提交隔离级别最低,这种级别一般叧在理论上存在,数据库默认隔离级别一般都高于该隔离级别;
(2)read committed
1) 事务A和事务B,事务A提交的数据,事务B才可读取到;(允许一个事务只能看到其他事务已经提交的修改,未提交的修改是不可见的。) 2) 该隔离级别高于“读未提交”级别,解决了: 脏读现象。 3) 换句话说:对方事务提交之后的数据,当前事务才可读取到。 4) 该隔离级别可以避免脏数据; 5) 该隔离级别能够导致“不可重复读取” 6) Oracle数据库管理系统默认隔离级别为“读已提交” (Oracle数据库支持 READ COMMITTED 和 SERIALIZABLE这两种事务隔离级别。)
(3)repeatable read
1) 事务A和事务B,事务A提交之后的数据,事务B还是读取不到。事务B只能读取到,事务B开启事务时刻表中的数据。2) 事务B是可重复读到数据的。(确保如果在一个事务中执行两次相同的SELECT语句,都能得到相同的结果,不管其他事务是否提交这些修改。 (银行总账))3) 这种隔离级别高于“读已提交”。4) 换句话说,对方提交之后的数据,还是读取不到。5) 这种隔离级别可以避免“脏读和不可重复读”,达到“重复读取”;6) MySQL数据库管理系统默认隔离级别为:可重复读7) 这种隔离级别解决了:不可重复读问题,达到了“重复读取”。 该隔离级别存在的问题是:读取到的数据是幻象。
(4)serializable
序列化读/串行化读 1 ) 事务A和事务B,事务A在操作数据库表中数据的时候,事务B叧能排队等待;(将一个事务与其他事务完 全地隔离。 ) 2) 这种事务隔离级别一般很少使用,吞吐量太低,用户体验不好;效率低。需要事务排队。 3) 事务A和事务B不再并发;避免了“幻想读”,每一次读取都是数据库表中真实的记录。
3.事务隔离级别的作用范围
会话级(session):只对当前会话有效 全局级(global) : 对所有会话有效
(1.1)查当前会话隔离级别
select @@tx_isolation;
或
select @@session.tx_isolation;
(1.2)查看全局隔离级别
select @@global.tx_isolation;
(2.1)设置会话隔离级别
set transaction isolation level 隔离级别类型 ;
或
set session transaction isolation level 隔离级别类型 ;
(2.2)设置全局隔离级别
set global transaction isolation level 隔离级别类型;
4-设置服务器缺省隔离级别
(1)静态设置:修改配置
关闭服务器,修改my.ini配置文件在 my.ini 文件中的[mysqld]下面添加:
transaction-isolation = 隔离级别类型
(2)动态设置:使用命令
在运行的服务器中通过命令方式,动态设置
set [global/session] transaction isolation level 隔离级别类型;
四、JDBC中的事务
1-JDBC中的事务默认采用自动提交机制 即 ,只要执行任意一条DML语句,JDBC则会自动提交一次事务。 但是在实际的业务当中,通常都是使用N条DML语句共同联合才能完成的。必须保证他们这些DML语句在同一个事物中同时成功或者同时失败。典型的案例:银行转账业务
2-代码演示 “银行转账”业务 分析:采用JDBC中默认的自动提交事务机制,会对该业务实现过程中产生的影响。以及给出解决方案。代码编号:**《Jdbc_Transaction/演示银行转账业务》** 3-事务+【行级锁】的使用 1)悲观锁/行级锁 事务必须排队执行。被选中锁住的数据不允许被并发修改。 使用方法:select语句后面添加for update即可。如:使用场景: 在实际开发中,在查询某张表数据时,为了保障数据的真实性,可以使用【行级锁】 (使用方法:在select语句之后添加for update)将需要的这些数据进行锁住。于是,别的线程开启的事务将无法对这些数据进行修改。 select ename,job,sal from emp where job = ‘manager’ for update;这行语句的意思:工作岗位是manager的这些员工数据被锁定。(行级锁) 当前事务未结束时,这些数据被锁住了。其他的事务无法对这些被锁住的数据进行修改操作。2)乐观锁 支持并发,事务也无需排队。但是会多一个版本号的概念。 多线程并发时,也可以对某条数据进行修改。 执行原理:
假设:开启事务1时,读取到数据的版本号是1.1。同时开启事务2,读取到数据的版本号也是1.1。 事务1先对数据进行了修改,修改之后发现版本号依旧是1.1,和它最初读取到的版本号一致(说明没有其他的事务对数据进行了修改)。于是提交事务修改数据。版本号将会变更为1.2。 事务2再进行修改数据,修改之后准备提交时,发现数据的版本号是1.2。和它最初读取到的版本号不一致(说明有其他的事务对数据进行了修改)。于是会执行回滚操作。
| ename | job | sal | version || —– | ——- | —- | ——- || james | manager | 8000 | 1.1 |
3)代码演示
结合Debug工具查看效果
涉及到两个程序1-演示程序开启一个事务.java2-该程序演示修改被锁定的记录.java
《Jdbc_Transaction/事务+行级锁的使用》
五、MyBatis中的事务
九.其他锁机制在事务操作一个表时,如果使用索引来取值,那么会锁定到对应行; 如果没有使用索引来取值,那么会锁定整个表。锁定之后其他连接无法操作指定行或表。回滚点
作用:回滚点可以指定rollback回退的位置。
> 比如:现在打了100条命令,发现第81打错了,如果回滚到打了81命令之前一点而不是回滚到开启事务之前就可以节省下很多时间。创建回滚点: savepoint 回滚点名;
回滚到回滚点: rollback to 回滚点名;
注意事项:回滚点在事务管理关闭(rollback或commit之后)之后失效,**不能在事务之外使用回滚点。
单机事务
分布式事务 即数据库不是一个。是数据库集群。分布方式的。 一个数据库不够北京的数据库 转到 南京的数据库。保证这两数据库的事务都成功,才能成功。
最新评论