如题,以前在社区回答过解决方案,今天在群里又看到有人问了。嗯,抗过疫情,生活继续分享~ 不多说,上 石马 ~
使用 ActiveRecordPlugin 扩展:
建一个类:
import com.jfinal.plugin.activerecord.Record; import com.jfinal.plugin.activerecord.Table; import com.jfinal.plugin.activerecord.dialect.MysqlDialect; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; /** * MysqlDialectByVersion扩展 * 注意 version 字段, 本扩展会自动 + 1 ,不需要在前端等其他地方版本号加1 * @author 杜福忠 */ public class MysqlDialectByVersion extends MysqlDialect { private String versionColName = "version"; public MysqlDialectByVersion() { } public MysqlDialectByVersion(String versionColName) { this.versionColName = versionColName; } public void forModelUpdate(Table table, Map<String, Object> attrs, Set<String> modifyFlag, StringBuilder sql, List<Object> paras) { Integer version = null; if (table.hasColumnLabel(versionColName)){ version = putVersion(attrs); modifyFlag.add(versionColName); } super.forModelUpdate(table, attrs, modifyFlag, sql, paras); appendSqlByVersion(sql, paras, version); } /** * Record 的 version 字段需要在业务中判断对象是否缺失版本号字段,只有对象里面存在版本号字段后才会触发拼接and条件 */ public void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql, List<Object> paras) { Integer version = null; Map<String, Object> attrs = record.getColumns(); if (attrs.containsKey(versionColName)) { version = putVersion(attrs); CPI.getModifyFlag(record).add(versionColName);//JF-V4.9.2+ } super.forDbUpdate(tableName, pKeys, ids, record, sql, paras); appendSqlByVersion(sql, paras, version); } private void appendSqlByVersion(StringBuilder sql, List<Object> paras, Integer version) { if (Objects.nonNull(version)) { sql.append(" and `").append(versionColName).append("` < ?"); paras.add(version); } } private Integer putVersion(Map<String, Object> attrs) { Object v = attrs.get(versionColName); Objects.requireNonNull(v, versionColName + "字段,不能为null"); Integer version = toInteger(v) + 1; attrs.put(versionColName, version); return version; } private Integer toInteger(Object v) { return v instanceof Integer ? (Integer) v : Integer.valueOf(v.toString()); } }
OK,我就写了MySQL的,其他数据库,应该可以模仿,配置使用:
ActiveRecordPlugin arp = new ActiveRecordPlugin(...); arp.setDialect(new MysqlDialectByVersion());
测试:
public static void main(String[] args) { ConfigActiveRecordKit.run();//这里是自己封装的数据库启动和Model映射方便业务测试 Account account = Account.dao.findById(2); account.set("remark", System.currentTimeMillis()); //debug断点打在这个位置,然后数据库去手动修改版本号,观察效果 boolean update = account.update(); System.out.println(update); Record a = new Record(); a.set("id", 2); //a.set("version", account.get("version")); a.set("remark", "Record"); if (! a.getColumns().containsKey("version")){ throw new NullPointerException("老铁!没有版本号字段啊"); } boolean ret = Db.update("account", a); System.out.println(ret); }
说明文档:
原理:利用SQL的update语句,where后面追加 and 条件去实现更新是否成功的判断。
当有Model时,数据库表里面需要有 version 字段int类型,会自动识别,注意字段设置默认值为0。
Record时,需要在业务代码里面判断是否存在version 字段。
判断成功方式:update方法 返回true为成功。
注意并不绝对是因为乐观锁导致的更新不成功,可能是主键值不存在了等情况,and条件嘛。
好了,有参考价值就点个赞呗~ 有特殊业务自行改造吧~