作者:廖祥俐
数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。
在事务获取数据库当前状态(比如通过读取或修改数据)之前,它必须保护自己不受其他事务对同一数据进行修改的影响,在此通过请求锁定数据块来达到此目的,同时,为了加快事务的处理,采用数据库索引减少io操作。
数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。
加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对象进行操作前,先向系统发出请求,对其加锁。加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前,其他的事务不能对此数据对象进行更新操作。
行级锁是一种排他锁,防止其他事务修改此行;在使用以下语句时,数据库会自动应用行级锁:
INSERT、UPDATE、DELETE、SELECT … FOR UPDATE [OF columns] [WAIT n | NOWAIT];
SELECT … FOR UPDATE语句允许用户一次锁定多条记录进行更新
使用COMMIT或ROLLBACK语句释放锁
悲观锁,指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
注:要使用悲观锁,必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交(在自动提交模式下,每个SQL语句都是一个独立的事务)。关闭了mysql的autocommit,需要手动控制事务的提交
悲观的缺陷是不论是表锁还是行锁,加锁的时间可能会很长,这样可能会长时间的限制其他用户的访问,也就是说悲观锁的并发访问性不好。
乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。
乐观锁一般有两种做法:
乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。
倒排索引通过各种数据结构的具体实现,是(值=>行位置)映射.
对于RDBMS(关系数据库管理系统)来说,主要有以下的作用:
索引通常会对数据增改操作性能产生负面影响:
此外,由于保存索引将占用磁盘空间,实际通过索引进行数据查询时,需要把索引数据load到内存中,在Mysql生成执行计划时,需要把索引维护相关的操作也放在同一个事务中,索引过多的情况下,执行计划会越复杂,导致最终执行变慢。
创建索引的指导原则:
索引的常见用法
在高并发情况下,各项服务可能会承受高并发的压力,在各项服务设计中,希望能够将压力进行分解,需要考虑的是如何分解压力,避免层层传递,尤其对于数据库层,需要把压力控制。
一般采用的方式如下:
通过均衡策略使得各台服务能够均衡负载
将不必要的请求第一时间进行过滤/丢弃,避免不必要的资源浪费;
业务层与数据层进行解耦,比如对于很多查询请求,如果每次都去数据层取数据,则将业务层的压力传导到数据层,一般会采用一层数据层的子库服务如redis/memcache进行扛高频压力
对于最终数据层的操作,可以采取消费队列的方式,用可控的消费者进行数据层的操作,即数据层操作的压力是相对恒定的。
在数据库操作中避免使用长事务,并且尽量少用事务。事务中避免长时间等待或调用,比如开启数据库事务后,做外部文件操作等
网易云大礼包:https://www.163yun.com/gift
本文来自网易实践者社区,经作者廖祥俐授权发布