用tk.mybaits实现指定字段更新

这篇具有很好参考价值的文章主要介绍了用tk.mybaits实现指定字段更新。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

​ 去年年底的因为业务需要需要在使用tk.mybaits框架的系统中实现指定字段的更新,可是tk.mybaits框架本身并不支持这个功能,我翻遍了CSDN和其他相关的技术相关的网站都没有找到相关的解决方法。于是我通过几天的翻阅相关资料和摸索后终于实现了这个功能。最近事情不是很多,想到又想到了去年解决的这个问题,于是有了这篇文章。分享一下当时的解决方法,为有同样需求的小伙伴抛砖引玉。

​ 这个问题如果系统使用的是Mybatis-Plus框架的话,实现只更新指定的字段是一件很简单的事情。只需要写以下代码即可:

UpdateWrapper updateWrapper = new UpdateWrapper();
updateWrapper.eq("id", 1);
updateWrapper.set("status",  1);
updateWrapper.set("nickname",  "张三");
baseMapper.update(null, updateWrapper);

但是如果系统使用的是tk.mybaits则默认不支持这个功能,有一种迂回的解决的办法是现查询出对应的数据,在set需要更新的字段,再更新整条数据。但是这样终究不是很好,在并发情况下也很容易出现问题。至于tk.mybaits指定字段更新的方案,我在网上找了很久都没有找到相关的解决方法。随后我通过分析tk.mybaits在github的源码和issue回答找到些许线索。最终实现了这个功能。具体结局方案如下:

先定义一个名为UpdateAppointColumnMapper接口

/**
 * @author: jie
 * @create: 2022/11/15 10:55
 * @description: 通用Mapper接口,更新指定字段,实现
 */
@tk.mybatis.mapper.annotation.RegisterMapper
public interface UpdateAppointColumnMapper<T> {

    /**
     * 根据Example条件更新实体`record`包含的不是null的属性值
     *
     * @param record
     * @param example
     * @return
     */
    @UpdateProvider(type = UpdateByExampleAppointColumnProvider.class, method = "dynamicSQL")
    int updateByExampleAppointColumn(@Param("record") T record, @Param("example") Object example,@Param("updateColumns") List<String> updateColumns);


//
//    @UpdateProvider(type = UpdateByExampleAppointColumnExampleProvider2.class, method = "updateByExampleAppointColumn")
//    int updateByExampleAppointColumn2(@Param("record") T record, @Param("example") Object example,@Param("updateColumns") List<String> updateColumns);


    /**
     * 根据Example条件更新实体`record`包含的不是null的属性值
     *
     * @param record
     * @param example
     * @return
     */
    @UpdateProvider(type = UpdateByExampleAppointColumnProvider.class, method = "dynamicSQL")
    int updateByExampleAppointColumnForMap(@Param("record") Map record, @Param("example") Object example, @Param("updateColumns") List<String> updateColumns);

}

再定义一个名为UpdateByExampleAppointColumnProvider的Provider(核心代码)

/**
 * @author: jie
 * @create: 2022/11/16 19:00
 * @description:
 */
public class UpdateByExampleAppointColumnProvider extends MapperTemplate {

    public static final String UPDATE_PROPERTIES = "updateColumns";

    public UpdateByExampleAppointColumnProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper);
    }

    /**
     * 根据Example更新非null字段
     *
     * @param ms
     * @return
     */
    public String updateByExampleAppointColumn(MappedStatement ms) {
        Class<?> entityClass = getEntityClass(ms);
        ParameterMap paramterType = ms.getParameterMap();

        Configuration configuration = ms.getConfiguration();
        MetaObject metaObject = MetaObjectUtil.forObject(ms);
        SqlSource sqlSource = ms.getSqlSource();
        //BoundSql boundSql = sqlSource.getBoundSql(entityClass);
        StringBuilder sql = new StringBuilder();
        if (isCheckExampleEntityClass()) {
            sql.append(SqlHelper.exampleCheck(entityClass));
        }
        //安全更新,Example 必须包含条件
        if (getConfig().isSafeUpdate()) {
            sql.append(SqlHelper.exampleHasAtLeastOneCriteriaCheck("example"));
        }
        sql.append(SqlHelper.updateTable(entityClass, tableName(entityClass), "record"));
        //sql.append(sqlUtil.updateSetAppointColumns(entityClass, Arrays.asList("before_value")));
        sql.append(this.updateSetColumnsForce(entityClass, "record", true, isNotEmpty()));
        sql.append(SqlHelper.updateByExampleWhereClause());
        //sql.append(SqlHelper.wherePKColumns(entityClass, "record", true));
        return sql.toString();
    }


    public String updateByExampleAppointColumnForMap(MappedStatement ms){
        return updateByExampleAppointColumn(ms);
    }



    /**
     * update set列
     *
     * @param entityClass
     * @param entityName  实体映射名
     * @param notNull     是否判断!=null
     * @param notEmpty    是否判断String类型!=''
     * @return
     */
    public String updateSetColumnsForce(Class<?> entityClass, String entityName, boolean notNull, boolean notEmpty) {
        StringBuilder sql = new StringBuilder();
        sql.append("<set>");
        //获取全部列
        Set<EntityColumn> columnSet = EntityHelper.getColumns(entityClass);
        //对乐观锁的支持
        EntityColumn versionColumn = null;
        //当某个列有主键策略时,不需要考虑他的属性是否为空,因为如果为空,一定会根据主键策略给他生成一个值
        for (EntityColumn column : columnSet) {
            if (column.getEntityField().isAnnotationPresent(Version.class)) {
                if (versionColumn != null) {
                    throw new VersionException(entityClass.getCanonicalName() + " 中包含多个带有 @Version 注解的字段,一个类中只能存在一个带有 @Version 注解的字段!");
                }
                versionColumn = column;
            }
            if (!column.isId() && column.isUpdatable()) {
                if (column == versionColumn) {
                    Version version = versionColumn.getEntityField().getAnnotation(Version.class);
                    String versionClass = version.nextVersion().getCanonicalName();
                    //version = ${@tk.mybatis.mapper.version@nextVersionClass("versionClass", version)}
                    sql.append(column.getColumn())
                            .append(" = ${@tk.mybatis.mapper.version.VersionUtil@nextVersion(")
                            .append("@").append(versionClass).append("@class, ")
                            .append(column.getProperty()).append(")},");
                } else if (notNull) {
                    sql.append(this.getIfNotNull(entityName, column, column.getColumnEqualsHolder(entityName) + ",", notEmpty));
                } else {
                    sql.append(column.getColumnEqualsHolder(entityName) + ",");
                }
            }
        }
        sql.append("</set>");
        return sql.toString();
    }

    /**
     * 判断自动!=null的条件结构
     *
     * @param entityName
     * @param column
     * @param contents
     * @param empty
     * @return
     */
    public String getIfNotNull(String entityName, EntityColumn column, String contents, boolean empty) {
        StringBuilder sql = new StringBuilder();
        sql.append("<choose>");

        //指定的字段会被强制更新
        sql.append("<when test=\"");
        sql.append(UPDATE_PROPERTIES).append(" != null and ").append(UPDATE_PROPERTIES).append(".contains('");
        sql.append(column.getProperty());
        sql.append("')\">");
        sql.append(contents);
        sql.append("</when>");

        sql.append("<otherwise></otherwise>");
        sql.append("</choose>");
        return sql.toString();
    }
}

需要实现指定字段更新的Mapper需要继承UpdateAppointColumnMapper,我是直接定义了一个名为BaseMapper的基类,让基类直接继承

public interface BaseMapper<T> extends Mapper<T>,UpdateAppointColumnMapper<T> {}

一个数据仓储的基类

public abstract class AbstractBaseRepository<T> {

    @Autowired
    protected IBaseMapper<T> baseMapper;

    /**
     *   更新指定字段
     *
     * @param  record 更新对象
     * @param example 更新条件
     * @param updateColumns 需要更新的字段
     * @return
     */
    public void updateByExampleAppointColumn(T record, Example example, List<String> updateColumns, LoginInfo loginInfo){
        record.setUpdateUser(loginInfo.getUserId());
        this.baseMapper.updateByExampleAppointColumn(record, example, updateColumns);
    }

    /**
     *  根据Map更新指定字段
     *
     * @param map map 更新Map
     * @param example 更新条件
     * @return void
     */
    public void updateByExampleAppointColumn(Map<String, Object> map, Example example, LoginInfo loginInfo){
        if(MapUtils.isEmpty(map)){
            throw new BusinessException("更新的字段必填");
        }
        List<String> updateColumns = map.keySet().stream().collect(Collectors.toList());
        map.put("updateUser", loginInfo.getUserId());
        this.baseMapper.updateByExampleAppointColumnForMap(map, example, updateColumns);
    }

    /**
     *  根据Map更新指定字段
     *
     * @param lambdaUpdateWrapper lambdaUpdateWrapper
     * @param example 更新条件
     * @return void
     */
    public void updateByExampleAppointColumn(LambdaUpdateWrapper lambdaUpdateWrapper, Example example, LoginInfo loginInfo){
        Map<String, Object> map = lambdaUpdateWrapper.build();
        this.updateByExampleAppointColumn(map, example, loginInfo);
    }
}

LambdaUpdateWrapper:

/**
 * @author: jie
 * @create: 2022/11/17 14:18
 * @description:
 */
public class LambdaUpdateWrapper {
    private Map<String, Object> updateMap;

    public static LambdaUpdateWrapper create() {
        return new LambdaUpdateWrapper();
    }

    public <T, R> LambdaUpdateWrapper set(ColumnFunction<T, R> column, Object value) {
        return set(FieldUtil.name(column), value);
    }

    public LambdaUpdateWrapper set(String columnName, Object value) {
        this.updateMap.put(columnName, value);
        return this;
    }

    public Map<String, Object> build() {
        return this.updateMap;
    }

}

实例代码:文章来源地址https://www.toymoban.com/news/detail-439499.html

(1)使用实体对象更新

public void updateByExampleAppointColumnEntityTest(){
//更新的对象
Event event = Event.builder().beforeValue("1").afterValue("2").description(null).build();
//需要更新的字段
List<String> updateColumns = Arrays.asList("beforeValue","afterValue","description");
//指定更新条件
Example example = Example.builder(Event.class)
.andWhere(WeekendSqls.custom()
.andEqualTo("bizId", "123")
.andEqualTo("active", CommonYesNoEnum.YES.getCode())).build();
updateByExampleAppointColumn(event, example, updateColumns);
}

(2)使用 MAP 更新

public void updateByExampleAppointColumnMapTest(){
//更新的MAP
Map<String, Object> map = new HashMap<>();
map.put("beforeValue","1");
map.put("afterValue","2");
map.put("description",null);
//指定更新条件
Example example = Example.builder(Event.class)
.andWhere(WeekendSqls.custom()
.andEqualTo("bizId", "123")
.andEqualTo("active", CommonYesNoEnum.YES.getCode())).build();
updateByExampleAppointColumnForMap(map, example);
}

(3) 使用 LambdaUpdateWrapper 更新

oid updateByExampleAppointColumnLambdaUpdateWrapperTest() {
//更新的MAP
LambdaUpdateWrapper lambdaUpdateWrapper = LambdaUpdateWrapper.create()
.set(Event::getBeforeValue, "1")
.set(Event::getAfterValue, "1")
.set(Event::getDescription, null);
//指定更新条件
Example example = Example.builder(Event.class)
.andWhere(WeekendSqls.custom()
.andEqualTo("bizId", "123")
.andEqualTo("active", CommonYesNoEnum.YES.getCode())).build();
eventRepository.updateByExampleAppointColumn(lambdaUpdateWrapper, example);
}

到了这里,关于用tk.mybaits实现指定字段更新的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java通用实现List<自定义对象>中指定字段和指定排序方式

    Person类: 工具类: 结果:

    2024年02月04日
    浏览(44)
  • 如何优化因为高亮造成的大文本(大字段)检索缓慢问题

    首先还是说一下背景,工作中用到了 elasticsearch 的检索以及高亮展示,但是索引中的 content 字段是读取的大文本内容,所以后果就是索引的单个字段很大,造成单独检索请求的时候速度还可以,但是加入高亮之后检索请求的耗时就非常的慢了。所以本文从 更换高亮器类型 的

    2024年02月11日
    浏览(36)
  • Debezium系列之:把value中指定字段的键值对放到key中,进一步实现key中只保留指定字段的值

    需要把value中的指定的键值对放到key中 例如需要把产品代号cdc_code和产品名称product放到key中#

    2024年02月09日
    浏览(40)
  • Oracle实现把B表某一字段更新到A表

    目录 1. 使用SQL命令UPDATE语句 2. 使用MERGE语句 3. 使用TRIGGER触发器 4.使用游标CURSOR和循环 如何实现把B表中某一字段值更新到A表?其实可以通过多种方法完成,下面是其中的四种常见方法及其实现方式。 可以使用UPDATE语句将B表中某一字段的值更新到A表的对应字段中。具体实现

    2024年02月08日
    浏览(32)
  • tk-mybatis使用介绍,springboot整合tk-mybatis、PageHelper实现分页查询

    Mybatis-Plus极大简化了我们的开发,作为mybatis的增强版,Mybatis-Plus确实帮我们减少了很多SQL语句的编写,通过其提供的API,可以方便地完成增删查改操作。但是,其实除了Mybatis-Plus以外,还有一个技术tk-mybatis可以达到同样的效果,只不过随着MP的兴起,tk-mybatis已经被渐渐淡忘

    2024年02月12日
    浏览(37)
  • Access数据库操作踩坑记:数据溢出,设置1字段为Null是因为类型转换失败

    从过了2008年以后,就没有操作过Access数据库了,本以为应该是就此告别这它了。之后有本地存储肯定是sqlite。没想到最近项目上又碰到了Access操作。类型贼少,还不和大伙一致。总是那么搞特殊。这不,一操作就踩坑。还不知道具体错在哪里。胸闷...... 1 数据溢出 多半是由

    2024年02月04日
    浏览(72)
  • 二百二十四、Kettle——曲线实现从Hive插入更新到ClickHouse(分区字段是month或year)

    对于以month、year为分区字段的数据,不是像day字段分区那样每天增量插入更新即可,而是要以部分字段查询、部分字段更新,但是ClickHouse数据库并不适合更新操作,直接使用Kettle的插入更新控件会导致问题,必须曲线实现这个功能 对于这类表,每天执行任务时scene_name、dev

    2024年02月21日
    浏览(37)
  • hive表新增字段,指定新增字段位置,删除字段

    背景:项目中,客户使用hive内表,由于逻辑变更,原hive表结构需要调整,新增字段。 一、新增字段 遇到hive表新增字段,以往建表都是建外表,直接drop后,重新创建。由于这次全部使用内表创建的,所以使用add column功能新增字段。 但是发现,如果已经存在记录的情况下覆

    2024年02月09日
    浏览(47)
  • python 基于modbus_tk库实现modbusTCP 主站和从站[非常详细]

    最近做了一个modbus tcp 传输浮点数的项目,参考了一些CSDN大佬的文章,这里做一个 整合和记录 。 摘自详解Modbus通信协议—清晰易懂 一主多从 的通信协议:Modbus 通信中 只有主机可以发送请求 。其他从设备接收主机发送的数据来进行响应——处理信息和使用 Modbus 将其数据发

    2024年02月03日
    浏览(47)
  • Oracle数据库在指定字段后新增字段

    记录一下数据库中为表增加字段,且在指定字段后新增; mysql数据库的话比较简单通过一下sql语句即可实现: 而Oracle数据库不支持上述语法,添加字段只能显示到最后一位,所以如果非要添加字段到指定字段后的话可以通过新建数据表并修改表明实现,如下面语句所示:

    2024年02月15日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包