首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

利用Trait特性给模型增加乐观锁功能

悲观锁和乐观锁

业务逻辑的实现过程中,往往需要保证数据访问的排他性。如在金融系统的日终结算处理中,我们希望针对某个时间点的数据进行处理,而不希望在结算进行过程中(可能是几秒种,也可能是几个小时),数据再发生变化。此时,我们就需要通过一些机制来保证这些数据在某个操作过程中不会被外界修改,这样的机制,在这里,也就是所谓的 “ 锁 ” ,即给我们选定的目标数据上锁,使其无法被其他程序修改。 通常有两种锁机制:即通常所说的 “ 悲观锁( Pessimistic Locking ) ”和 “ 乐观锁( Optimistic Locking ) ” 。

悲观锁( Pessimistic Locking )

悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。 通常是使用子句来实现悲观锁机制。

ThinkPHP5支持悲观锁机制,要启用悲观锁功能,可以通过使用锁定方法,例如:

就会自动在生成的SQL语句最后加上或者(Oracle数据库)。

方法还支持传入字符串,以实现特殊的锁机制。

乐观锁( Optimistic Locking )

相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。 如一个金融系统,当某个操作员读取用户的数据,并在读出的用户数据的基础上进行修改时(如更改用户帐户余额),如果采用悲观锁机制,也就意味着整个操作过程中(从操作员读出数据、开始修改直至提交修改结果的全过程,甚至还包括操作员中途去煮咖啡的时间),数据库记录始终处于加锁状态,可以想见,如果面对几百上千个并发,这样的情况将导致怎样的后果。乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本( )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个字段来实现。

ThinkPHP版本中并没有内置乐观锁功能,因此需要自己实现,本文就来利用特性实现乐观锁的功能。

乐观锁的实现

要实现乐观锁功能,主要涉及三个地方:

记录乐观锁:第一次写入数据的时候自动记录字段,当然也可以使用数据库默认值功能。

读取乐观锁:每次读取数据的时候都要单独记录下当前的数据值。

检测乐观锁:每次更新数据的时候要重新检测下最新数据的数据值,如果记录的版本号和最新的不一致,表示数据需要更新,否则把当前记录的版本号加1后更新到数据库。

而ThinkPHP的模型方法会统一调用方法,因此我们可以通过重写该方法来实现乐观锁的检测乐观锁功能。而每次查询后都会调用模型的方法,因此可以重写该方法添加读取乐观锁功能。

继承方式实现

我们可以创建一个公共的模型继承系统的类,当你的模型需要使用乐观锁功能的话就单独继承。

对需要使用乐观锁的模型,可以使用

利用特性实现

但由于PHP不支持多继承,因此并不建议使用模型继承功能来扩展功能。我们可以利用特性来更方便的引入后开启乐观锁功能。

因为机制的问题,我们对上面的代码进行了一些必要的调整。

对需要使用乐观锁的模型,可以使用

值得注意的是,版本目前已经内置了一个的实现。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190102G08K2S00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券