1.使用c语言的七个步骤
①定义程序的目标
②设计程序
③编写代码
④编译
⑤运行程序
⑥测试和调试程序
⑦维护和修改程序
磨刀不误砍柴工,应该养成先规划再动手写代码的习惯,用纸和笔记录下程序的目标和设计框架,这样会在编写代码的过程中更得心应手、条理清晰
2.事务的四大特性
原子性、一致性、隔离性、持久性
★原⼦性: 事务是最⼩的执⾏单位,不允许分割。事务的原⼦性确保动作要么全部完成,要么全不执行;
★一致性: 执⾏事务前后,数据保持⼀致,多个事务对同⼀个数据读取的结果是相同的;
★隔离性: 并发访问数据库时,⼀个⽤户的事务不被其他事务所⼲扰,各并发事务之间数据库是独⽴的;
★持久性: ⼀个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发⽣故障也不应该对其有任何影响。
★实现保证:
MySQL的存储引擎InnoDB使用重做日志保证一致性与持久性,回滚日志保证原子性,使用各种锁来保证隔离性。
3.事务隔离级别
★读未提交:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
★读已提交:允许读取并发事务已经提交的数据,可以阻⽌脏读,但是幻读或不可重复读仍有可能发⽣。
★可重复读:同⼀字段的多次读取结果都是⼀致的,除⾮数据是被本身事务⾃⼰所修改,可以阻⽌脏读和不可重复读,会有幻读。
★串行化:最⾼的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执⾏,这样事务之间就完全不可能产⽣⼲扰。
4.默认隔离级别-RR
默认隔离级别:可重复读
同⼀字段的多次读取结果都是⼀致的,除⾮数据是被本身事务⾃⼰所修改;
可重复读是有可能出现幻读的,如果要保证绝对的安全只能
★把隔离级别设置成SERIALIZABLE;这样所有事务都只能顺序执行,自然不会因为并发有什么影响了,但是性能会下降许多。
★第二种方式,使用MVCC解决快照读幻读问题(如简单select),读取的不是最新的数据。维护一个字段作为version,这样可以控制到每次只能有一个人更新一个版本。
★ 第三种方式,如果需要读最新的数据,可以通过GapLock+Next-KeyLock可以解决当前读幻读问题
5.RR和RC使用场景
事务隔离级别RC(read commit)和RR(repeatable read)两种事务隔离级别基于多版本并发控制MVCC(multi-version concurrency control)来实现。
6.行锁,表锁,意向锁
InnoDB⽀持⾏级锁(row-level locking)和表级锁,默认为⾏级锁
InnoDB按照不同的分类的锁:
共享/排它锁(Shared and Exclusive Locks):行级别锁,
意向锁(Intention Locks),表级别锁
间隙锁(Gap Locks),锁定一个区间
记录锁(Record Locks),锁定一个行记录
★表级锁:(串行化)
Mysql中锁定粒度最大的一种锁,对当前操作的整张表加锁,实现简单 ,资源消耗也比较少,加锁快,不会出现死锁 。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM和 InnoDB引擎都支持表级锁。
★行级锁:(RR、RC)
Mysql中锁定粒度最小的一种锁,只针对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。
InnoDB支持的行级锁,包括如下几种:
★记录锁(Record Lock): 对索引项加锁,锁定符合条件的行。其他事务不能修改和删除加锁项;
★间隙锁(Gap Lock): 对索引项之间的“间隙”加锁,锁定记录的范围,不包含索引项本身,其他事务不能在锁范围内插入数据。
★Next-key Lock: 锁定索引项本身和索引范围。即Record Lock和Gap Lock的结合。可解决幻读问题。
InnoDB 支持多粒度锁(multiple granularity locking),它允许行级锁与表级锁共存,而意向锁就是其中的一种表锁。
★共享锁( shared lock, S )锁允许持有锁读取行的事务。加锁时将自己和子节点全加S锁,父节点直到表头全加IS锁
★排他锁( exclusive lock, X )锁允许持有锁修改行的事务。 加锁时将自己和子节点全加X锁,父节点直到表头全加IX锁
★意向共享锁(intention shared lock, IS):事务有意向对表中的某些行加共享锁(S锁)
★意向排他锁(intention exclusive lock, IX):事务有意向对表中的某些行加排他锁(X锁)
7.MVCC多版本并发控制
MVCC是一种多版本并发控制机制,通过事务的可见性看到自己预期的数据,能降低其系统开销.(RC和RR级别工作)
InnoDB的MVCC,是通过在每行记录后面保存系统版本号(可以理解为事务的ID),每开始一个新的事务,系统版本号就会自动递增,事务开始时刻的系统版本号会作为事务的ID。这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的,防止幻读的产生。
①MVCC手段只适用于Msyql隔离级别中的读已提交(Read committed)和可重复读(Repeatable Read)
②Read uncimmitted由于存在脏读,即能读到未提交事务的数据行,所以不适用MVCC.
③简单的select快照度不会加锁,删改及select for update等需要当前读的场景会加锁
原因是MVCC的创建版本和删除版本只要在事务提交后才会产生。客观上,mysql使用的是乐观锁的一整实现方式,就是每行都有版本号,保存时根据版本号决定是否成功。Innodb的MVCC使用到的快照存储在Undo日志中,该日志通过回滚指针把一个数据行所有快照连接起来。
★版本链
在InnoDB引擎表中,它的聚簇索引记录中有两个必要的隐藏列:
★trx_id
这个id用来存储的每次对某条聚簇索引记录进行修改的时候的事务id。
★roll_pointer
每次对哪条聚簇索引记录有修改的时候,都会把老版本写入undo日志中。这个roll_pointer就是存了一个指针,它指向这条聚簇索引记录的上一个版本的位置,通过它来获得上一个版本的记录信息。(注意插入操作的undo日志没有这个属性,因为它没有老版本)
每次修改都会在版本链中记录。SELECT可以去版本链中拿记录,这就实现了读-写,写-读的并发执行,提升了系统的性能。
好好生活★