浅谈Mybatis乐观锁插件

背景:对于数据库的同一条记录,假如有两个人同时对数据进行了修改,然后最终同步到数据库的时候,因为存在着并发,产生的结果是不可预料的。最简单的解决方式就是通过给表的记录加一个version字段,记录在修改的时候需要比较一下version是否匹配,如果匹配就更新,不匹配就直接失败。更新成功则把version+1,也就是所谓的乐观锁。当然这样的逻辑最好能做到对开发人员透明,本插件就是来做这件事情的。

1. 使用方式:在mybatis配置文件中加入如下配置,就完成了。

<plugins>
  <plugin interceptor="com.chrhc.mybatis.locker.interceptor.OptimisticLocker"/>
</plugins>

2. 对插件配置的说明:

上面对插件的配置默认数据库的乐观锁列对应的Java属性为version。这里可以自定义属性命,例如:

<plugins>
  <plugin interceptor="com.chrhc.mybatis.locker.interceptor.OptimisticLocker">
    <property name="versionColumn" value="xxx"/><!--数据库的列名-->
    <property name="versionField" value="xxx"/> <!--java字段名-->
  </plugin>
</plugins>

3. 效果:

之前:update user set name = ?, password = ? where id = ?

之后:update user set name = ?, password = ?, version = version+1 where id = ? and version = ?

4. 对version的值的说明:

1、当PreparedStatement获取到version值之后,插件内部会自动自增1。

2、乐观锁的整个控制过程对用户而言是透明的,这和Hibernate的乐观锁很相似,用户不需要关心乐观锁的值。

5.插件原理描述:

插件通过拦截mybatis执行的update语句,在原有sql语句基础之上增加乐观锁标记,比如,原始sql为:
update user set name = ?, password = ? where id = ?,

那么用户不需要修改sql语句,在插件的帮助之下,会自动将上面的sql语句改写成为:
update user set name = ?, password = ?, version = version + 1 where id = ? and version = ?,

形式,用户也不用关心version前后值的问题,所有的动作对用户来说是透明的,由插件自己完成这些功能。

6.默认约定:

1、本插件拦截的update语句的Statement都是PreparedStatement,仅针对这种方式的sql有效;

2、mapper.xml的<update>标签必须要与接口Mapper的方法对应上,也就是使用mybatis推荐的方式,但是多个接口可以对应一个mapper.xml的<update>标签;

3、本插件不会对sql的结果做任何操作,sql本身应该返回什么就是什么;

4、插件默认拦截所有update语句,如果用户对某个update不希望有乐观锁控制,那么在对应的mapper接口方法上面增加@VersionLocker(false)或者@VersionLocker(value = false),这样插件就不会对这个update做任何操作,等同于没有本插件;

5、本插件目前暂时不支持批量更新的乐观锁,原因是由于批量更新在实际开发中应用场景不多,另外批量更新乐观锁开发难度比较大;

6、Mapper接口的参数类型必须和传入的实际类型保持一致,这是由于在JDK版本在JDK8以下没有任何方法能获取接口的参数列表名称,因此,插件内部是使用参数类型和参数作为映射来匹配方法签名的;

github地址:https://github.com/xjs1919/locker

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 浅谈Mybatis乐观锁插件

    背景:对于数据库的同一条记录,假如有两个人同时对数据进行了修改,然后最终同步到数据库的时候,因为存在着并发,产生的结果是不可预料的.最简单的解决方式就是通过给表的记录加一个version字段,记录在修改的时候需要比较一下version是否匹配,如果匹配就更新,不匹配就直接失败.更新成功则把version+1,也就是所谓的乐观锁.当然这样的逻辑最好能做到对开发人员透明,本插件就是来做这件事情的. 1. 使用方式:在mybatis配置文件中加入如下配置,就完成了. <plugins> <pl

  • 浅谈mybatis 乐观锁实现,解决并发问题

    情景展示: 银行两操作员同时操作同一账户就是典型的例子. 比如A.B操作员同时读取一余额为1000元的账户,A操作员为该账户增加100元,B操作员同时为该账户扣除50元,A先提交,B后提交.最后实际账户余额为1000-50=950元,但本该为1000+100-50=1050.这就是典型的并发问题. 乐观锁机制在一定程度上解决了这个问题.乐观锁,大多是基于数据版本(Version)记录机制实现.何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 "

  • 浅谈myBatis中的插件机制

    插件的配置与使用 在mybatis-config.xml配置文件中配置plugin结点,比如配置一个自定义的日志插件LogInterceptor和一个开源的分页插件PageInterceptor: <plugins> <plugin interceptor="com.crx.plugindemo.LogInterceptor"></plugin> <plugin interceptor="com.github.pagehelper.P

  • 浅谈Yii乐观锁的使用及原理

    本文介绍了Yii乐观锁的使用及原理,自己做个学习笔记,也分享给大家,希望对大家有用处 原理: 数据表中使用一个int类型的字段来存储版本号,即该行记录的版本号.更新数据时,对比版本号是否一致 sql查询代码如下(伪代码) update `test_ver` set `name`="lili" and `ver`=2 where `id`=1 and `ver`=1 即在更新时的where查询条件中,带上之前查询记录时得到的版本号,如果其他线程已经修改了该记录,则版本号势必不会一致,则更

  • 浅谈Mybatis分页插件,自定义分页的坑

    场景:PageHelper 的默认分页方案是 select count(0) from (你的sql) table_count 由于查询数据比较大时,导致分页查询效率低下. 优化:使用自定义的count查询.. 废话不多说,对应代码如下: 这个时候会使用自定义的 count sql进行统计查询. 然后一般分页默认使用 PageHelper.startPage(); 作者优化:如果获取的数量大于实际数量,则进行pageNum优化. 所以 最好建议重载 startPage. 不进行优化!!! 要不然

  • 浅谈mybatis中的#和$的区别 以及防止sql注入的方法

    mybatis中的#和$的区别 1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号.如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id". 2. $将传入的数据直接显示生成在sql中.如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id,  如果传入的

  • 浅谈mybatis中的#和$的区别

    1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号.如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id". 2. $将传入的数据直接显示生成在sql中.如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为ord

  • 浅谈Mybatis版本升级踩坑及背后原理分析

    1.背景 某一天的晚上,系统服务正在进行常规需求的上线,因为发布时,提示统一的pom版本需要升级,于是从 1.3.9.6 升级至 1.4.2.1. 当服务开始上线后,开始陆续出现了一些更新系统交互日志方面的报警,属于系统辅助流程,报警下图所示, 具体系统数据已脱敏,内容是Mybatis相关的报警,在进行类型转换的时候,产生了强转错误. 更新开票请求返回日志, id:{#######}, response:{{"code":XXX,"data":{"call

  • 浅谈Mybatis #和$区别以及原理

    总结: 1.#可以防止Sql 注入,它会将所有传入的参数作为一个字符串来处理. 2.$ 则将传入的参数拼接到Sql上去执行,一般用于表名和字段名参数,$ 所对应的参数应该由服务器端提供,前端可以用参数进行选择,避免 Sql 注入的风险 为什么? 为什么# 和 $ 的作用不同,Mybatis 对他们做了哪些惨无人道的处理,我们看一下下面的例子,并追踪一下源码总结. 示例代码: 创建一个 tb_class 表(具体字段不做解释). 创建一个 ClassDao.java 并使用注解的方式 ,table

  • 浅谈MyBatis循环Map(高级用法)

    今天遇到一个比较特殊的业务,需要对传入的Map数据在映射文件中进行遍历,在之前的学习中,我们也知道MyBatis有默认对集合的操作list和array,但是没有默认的map,所有不能直接写collection="map",如果这么处理,它会当成是根据map.get("map")获取传递value只,==大部分情况下是一个map中是不会有"map"这个key的,于是就是报错==.如果你想用map标识来获取参数map,就需要保证传入的Map参数有@P

随机推荐