如题,以前在社区回答过解决方案,今天在群里又看到有人问了。嗯,抗过疫情,生活继续分享~ 不多说,上 石马 ~
使用 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条件嘛。
好了,有参考价值就点个赞呗~ 有特殊业务自行改造吧~
