MYSQL事务之学习笔记

sunshine技术博客 sunshine技术博客

由于项目设计里面,牵扯到了金钱的转移,于是就要用到MYSQL的事务处理,来保证一组处理结果的正确性,用了事务,就不可避免的要牺牲一部分速度,来保证数据的正确性.

只有InnoDB支持事务

事务 ACID Atomicity(原子性)、Consistency(稳定性)、Isolation(隔离性)、Durability(可靠性)

1、事务的原子性

一组事务,要么成功;要么撤回。

2、稳定性

有非法数据(外键约束之类),事务撤回。

3、隔离性

事务独立运行,一个事务处理后的结果,影响了其他事务,那么其他事务会撤回,事务的100%隔离,需要牺牲速度.

4、可靠性

软、硬件崩溃后,InnoDB数据表驱动会利用日志文件重构修改,可靠性和高速度不可兼得,innodb_flush_log_at_trx_commit选项决定什么时候吧事务保存到日志里.

开启事务:START TRANSACTION 或 BEGIN

提交事务(关闭事务):COMMIT

放弃事务(关闭事务):ROLLBACK

折返点

SAVEPOINT adqoo_1

ROLLBACK TO SAVEPOINT adqoo_1

发生在折返点 adqoo_1 之前的事务被提交,之后的被忽略.

事务的终止

设置“自动提交”模式:SET AUTOCOMMIT = 0,每条SQL都是同一个事务的不同命令,之间由 COMMIT 或 ROLLBACK隔开,掉线后,没有 COMMIT 的事务都被放弃.

事务锁定模式

系统默认:不需要等待某事务结束,可直接查询到结果,但不能再进行修改、删除.

缺点:查询到的结果,可能是已经过期的.

优点:不需要等待某事务结束,可直接查询到结果.

需要用以下模式来设定锁定模式

1、SELECT …… LOCK IN SHARE MODE(共享锁)

查询到的数据,就是数据库在这一时刻的数据(其他已commit事务的结果,已经反应到这里了)

SELECT 必须等待,某个事务结束后才能执行

2、SELECT …… FOR UPDATE(排它锁)

例如 SELECT * FROM tablename WHERE id<200,那么id<200的数据,被查询到的数据,都将不能再进行修改、删除、SELECT …… LOCK IN SHARE MODE操作一直到此事务结束,共享锁 和 排它锁 的区别:在于是否阻断其他客户发出的 SELECT …… LOCK IN SHARE MODE命令

3、INSERT / UPDATE / DELETE

所有关联数据都会被锁定,加上排它锁

4、防插入锁

例如 SELECT * FROM tablename WHERE id>200,那么id>200的记录无法被插入.

5、死锁

自动识别死锁,先进来的进程被执行,后来的进程收到出错消息,并按ROLLBACK方式回滚innodb_lock_wait_timeout = n 来设置最长等待时间,默认是50秒.

事务隔离模式

SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL

READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE

1、不带SESSION、GLOBAL的SET命令:只对下一个事务有效

2、SET SESSION:为当前会话设置隔离模式

3、SET GLOBAL:为以后新建的所有MYSQL连接设置隔离模式(当前连接不包括在内)

隔离模式:READ UNCOMMITTED

不隔离SELECT,其他事务未完成的修改(未COMMIT),其结果也考虑在内,READ COMMITTED,把其他事务的 COMMIT 修改考虑在内,同一个事务中,同一 SELECT 可能返回不同结果

REPEATABLE READ(默认),不把其他事务的修改考虑在内,无论其他事务是否用COMMIT命令提交过,同一个事务中,同一 SELECT 返回同一结果(前提是本事务,不修改).

SERIALIZABLE,和REPEATABLE READ类似,给所有的SELECT都加上了共享锁.

出错处理,根据出错信息,执行相应的处理,最后看看PHP + MySQL事务操作的代码演示,实际LAMP应用中,一般PHP使用AdoDB操作MySQL,下面给出AdoDB相应的代码方便大家查阅,代码如下:

  1. <?php
  2. //...
  3. $adodb->startTrans();
  4. //实际,getOne所调用的查询也可以直接放到rowLock来进行,这里只是为了演示效果能更明显些。
  5. $adodb->rowLock('book','book_id=123');
  6. $bookNumber=$adodb->getOne("SELECTbook_numberFROMbookWHEREbook_id=123");
  7. $adodb->execute("UPDATEbookSETbook_number=book_number-1WHEREbook_id=123");
  8. //phpfensi.com
  9. $adodb->completeTrans();
  10. //...
  11. ?>

其中,rowLock的方法就是调用的FOR UPDATE来实现的行锁,你可能会想把“FOR UPDATE”直接写到$adodb->getOne()调用的那条SQL语句里面去实现行锁的功能,不错,那样确实可以,但是并不是所有的数据库都使用“FOR UPDATE”语法来实现行锁功能,比如Sybase使用“HOLDLOCK”的语法来实现行锁功能,所以为了你的数据库抽象层保持可移植性,我还是劝你用rowLock来实现行锁功能.

相关广告
  • MYSQL事务之学习笔记 MYSQL事务之学习笔记 MYSQL事务之学习笔记
相关阅读

MYSQL事务之学习笔记

2019/10/10 17:34:48 | 谷歌SEO算法 | SEO知识