文章目录
事务【重点】
1.模拟转账
生活当中转账是转账方账户扣钱,收账方账户加钱。我们用数据库操作来模拟现实转账。
1.1数据库模似转账
CREATE TABLE account(
id INT,
money INT
)CHARSET = utf8;
#A账户转账给B账户1000元。
#A账户减1000元
UPDATE account SET MONEY = MOMEY-1000 WHERE id=1;
#B账户加1000元
UPDATE account SET MONEY = MONEY+1000 WHERE id=2;
- 上述代码完成了两个账户之间转账的操作。
1.2模似转账错误
#A账户转账给B账户1000元。
#A账户减1000元
UPDATE account SET MONEY = MONEY-1000 WHERE id=1;
#断电、异常、出错...
#B账户加1000元
UPDATE account SET MONEY = MONEY+1000 WHERE id=2;
- 上述代码在减操作后过程中出现了异常或加钱语句出锗,会发现,减钱仍旧是成功的,而加钱失败了!
- 注意:每条SQL语句都是一个独立的操作,一个操作执行完对数据库是永久性的影响。
2.事务的概念
- 事务是一个原子操作。是一个最小执行单元。可以甶一个或多个SQL语句组成
- 在同一个事务当中,所有的SQL语句都成功执行时,整 个事务成功,有一个SQL语句执行失败,整个事务都执行失败。
3.事务的边界
-
开始:连接到数据库,执行一条DML语句。上一个事务结束后,又输入了一条DML语句,即事务的开始
-
结束:
-
(1)提交:
a. 显示提交:commit ;
b. 隐式提交:一条创建、删除的语句,正常退出(客户端退出连接);
-
回滚:
a. 显示回滚:rollback ;
b. 隐式回滚:非正常退出(断电、宕机),执行了创建、删除的语句,但是失败了,会为这个无效的语句执行回滚。
-
4.事务的原理
- 数据库会为每一个客户端都维护一个空间独立的缓存区(回滚段)
- 一个事务中所有的增删改语句的执行结果都会缓存在回滚段中,只有当事务中所有SQL语句均正常结束(commit),才会将回滚段中的数据同步到数据库。否则无论因为哪种原因失败,整个事务将回滚 (rollback)
5.事务的特性
-
Atomicity(原子性)
表示一个事务内的所有操作是一个整体,要么全部成功,要么全部失败
-
Consistency(一致性)
表示一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前状态
-
Isolation (隔离性)
事务查看数据操作时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。
- 隔离级别(4个)
- 读未提交:read uncommitted
- 读已提交:read committed
- 可重复读:repeatable read
- 串行化:serializable
- 隔离级别(4个)
-
Durability (持久性)
持久性事务完成之后,它对于系统的影响是永久性的。
5.1并发事务带来的问题
相对于串行处理来说,并发事务处理能大大增加数据库资源的利用率,提高数据库系统的事务吞吐量,从而可以支持可以支持更多的用户。但并发事务处理也会带来一些问题,主要包括以下几种情况。
- 更新丢失(Lost Update):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题——最后的更新覆盖了其他事务所做的更新。例如,两个编辑人员制作了同一文档的电子副本。每个编辑人员独立地更改其副本,然后保存更改后的副本,这样就覆盖了原始文档。最后保存其更改保存其更改副本的编辑人员覆盖另一个编辑人员所做的修改。如果在一个编辑人员完成并提交事务之前,另一个编辑人员不能访问同一文件,则可避免此问题
- 脏读(Dirty Reads):一个事务正在对一条记录做修改,在这个事务并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”的数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做“脏读”。
- 不可重复读(Non-Repeatable Reads):一个事务在读取某些数据已经发生了改变、或某些记录已经被删除了!这种现象叫做“不可重复读”。
- 幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。
5.2隔离级别与一致性关系
1、 read uncommitted 读未提交
- 事务A和事务B,事务A未提交的数据,事务B可以读取到
- 这里读取到的数据叫做“脏数据”
- 这种隔离级别最低,这种级别一般是在理论上存在,数据库隔离级别一般都高于该级别
2、read committed 读已提交
- 事务A和事务B,事务A提交的数据,事务B才能读取到
- 这种隔离级别高于读未提交
- 换句话说,对方事务提交之后的数据,我当前事务才能读取到
- 这种级别可以避免“脏数据”
- 这种隔离级别会导致“不可重复读取”
- Oracle默认隔离级别
3、repeatable read 可重复读
- 事务A和事务B,事务A提交之后的数据,事务B读取不到
- 事务B是可重复读取数据
- 这种隔离级别高于读已提交
- 换句话说,对方提交之后的数据,我还是读取不到
- 这种隔离级别可以避免“不可重复读取”,达到可重复读取
- 比如1点和2点读到数据是同一个
- MySQL默认级别
- 虽然可以达到可重复读取,但是会导致“幻像读”
4、serializable 串行化
- 事务A和事务B,事务A在操作数据库时,事务B只能排队等待
- 这种隔离级别很少使用,吞吐量太低,用户体验差
- 这种级别可以避免“幻像读”,每一次读取的都是数据库中真实存在数据,事务A与事务B串行,而不并发
6.事务应用
应用环境:基于增删改语句的操作结果(均返回操作后受影响的行数),可通过程序逻辑手动控制事务提交或回滚
6.1事务完成转账
#A账户给B账户转账^
#1 .开启事务
START TRANSACTION; |setAutoCommit=0;#禁止自动提交 setAutoCommit=1;#开启自动提交
#2.事务内数据操作语句
UPDATE ACCOUNT SET MONEY = MONEY-1000 WHERE ID = 1 ;
UPDATE ACCOUNT SET MONEY = MONEY+1000 WHERE ID = 2;
#3.事务内语句都成功了,执行COMMIT;
COMMIT;
#4.事务内如果出现锗误,执行ROLLBACK;
ROLLBACK;
- 注意:开启事务后,执行的语句均属于当前事务,成功再执行COMMIT,失败要进行ROLLBACK