美文网首页
说一说时间戳机制的妙用

说一说时间戳机制的妙用

作者: 天草二十六_简村人 | 来源:发表于2022-07-22 14:55 被阅读0次

一、时间戳是什么?

时间戳主要是标记数据的变动时间,同时它在实际的查询和操作等接口中,也有它的妙用。

  • 数据库的某条数据变动了,或修改或删除,都应该更新它的修改时间
  • 增量查询,每一次查询的时间都比上一次查询的时间要大,这样就不是查询全部数据
  • 增量同步,每一次同步数据后,记住本次同步时间,下一次同步的时候,同步数据的范围就是时间戳大于上一次同步时间

示例,在mysql数据库中,时间戳就是字段modified_date,每次变更的时候,就会更新该字段为now()。

`created_date` datetime DEFAULT NULL COMMENT '创建时间',
`modified_date` datetime DEFAULT NULL COMMENT '更新时间',

二、编程实现

  • mybatis

详请参考链接:https://www.cnblogs.com/myesn/p/mybatis-plus-auto-fill-field-value-and-soft-delete.html

/**
     * 创建时间
     */
    @TableField(value = "created_date", fill = FieldFill.INSERT)
    private Date createdDate;

    /**
     * 更新时间
     */
    @TableField(value = "modified_date", fill = FieldFill.INSERT_UPDATE)
    private Date modifiedDate;

需要再实现MetaObjectHandler

@Component
public class MybatisPlusMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createdDate", Date.class, DateUtil.date());
        this.strictInsertFill(metaObject, "modifiedDate", Date.class, DateUtil.date());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "modifiedDate", Date.class, DateUtil.date());
    }
}
  • jpa
    @CreatedDate
    @Column(name = "created_date", columnDefinition = "datetime DEFAULT NOW() COMMENT '创建时间'")
    private Date createdDate;

    @LastModifiedDate
    @CreatedDate
    @Column(name = "modified_date", columnDefinition = "datetime DEFAULT NOW() COMMENT '更新时间'")
    private Date modifiedDate;

值得注意的是,你如果有手动执行sql语句,也切记把修改时间更新为当前时间。

三、流程图

增量查询.png 增量同步的流程图.png

四、使用场景

3.1、增量查询

不同于分页查询,增量查询的条件是根据时间戳大于传入的时间,也就是只查询变化的数据,而分页查询想要查询出变化了的数据,必须逐页查询所有页码。

举个例子,经常去逛图书馆的你,想要知道最近有些什么新书上架,而非逛遍整个图书馆。图书查询系统,如果有书的上架时间,每次查询新书,就只需根据拿上一次查询时间和图书的上架时间比较。

  • 这种增量的方式,有个前提条件是客户端能够记住上一次的查询时间戳,在查询后,能够更新端侧的查询时间戳为最新,待上次增量的时候,传入时间戳参数。
SELECT * FROM xxx
        WHERE
             <![CDATA[
                 (created_date >= #{timestamp} OR modified_date >= #{timestamp} )
             ]]>

3.2、增量同步

mysql数据库是有事务的,elasticsearch不具备事务,往往我们会使用Mysql来保存、修改或删除数据,复杂查询则交给elasticsearch。其实也就是CQRS架构中,我们会需要同步mysql数据到elasticsearch。

  • 当mysql数据库的数据变更时,发布event事件,订阅者消费事件,把最新的数据保存到es里。
  • 利用xxl-job这种分布式的定时任务框架,定期对变更数据同步到elasticsearch里,做一个兜底补偿。
  • 和上一个场景--增量查询不同的是,这里的时间戳需要服务端来保存和更新,上一个场景中的时间戳一般都是由客户端来保存和更新。
    @XxlJob("orderSyncJobHandler")
    @Transactional(rollbackFor = Throwable.class)
    public ReturnT<String> syncES(String param) {
// 把同步时间保存在redis里
        final String redisKey = indexConfiguration.getKey();

//本次同步时间
        Date thisSyncDate = DateUtil.offsetMinute(new Date(), -1);

        try {
            List<Order> orderList;

            ValueOperations<String, String> operations = redisHandler.getStringValueOperations();

//上一次同步时间
            Date lastSyncDate;
            int offsetMonth = 24;

// 由xxl-job手动指定同步时间
            if (!StringUtils.isEmpty(param)) {
                // 指定时间范围,单位是月,也可以是日,小时,分。
                offsetMonth = Integer.parseInt(param);

                lastSyncDate = DateUtil.offsetMonth(new Date(), -1 * offsetMonth);
            } else {
                // 从redis里取上一次的增量时间点
                if (!StringUtils.isEmpty(operations.get(redisKey))) {
                    lastSyncDate = DateUtil.parse(operations.get(redisKey), DatePattern.NORM_DATETIME_PATTERN);
                } else {
                    // 如果redis的key为空,默认初始化最近24个月的数据
                    lastSyncDate = DateUtil.offsetMonth(new Date(), -1 * offsetMonth);
                }
            }

// 防止数据量过大,这里采用分页查询,使用的是一个do-while循环。
            Pageable pageRequest = PageRequest.of(0, 100, Sort.Direction.ASC, "modifiedAt");
            do {
                orderList = orderRepository.findByModifiedAtGreaterThanEqualAndModifiedAtLessThanEqual(
                        lastSyncDate,
                        thisSyncDate,
                        pageRequest);

// 同步最新数据到es
                for (Order order : orderList) {
                    orderIndexService.sendToESFromDB(order);
                }
                pageRequest = pageRequest.next();
            } while (!orderList.isEmpty());

// 更新本次的同步时间
            operations.set(redisKey, DateUtil.format(thisSyncDate, DatePattern.NORM_DATETIME_PATTERN));

            return new ReturnT<>("定时同步订单数据到ES成功");
        } catch (Exception e) {
            log.error("定时同步订单数据到ES失败", e);
        }
        return ReturnT.FAIL;
    }

相关文章

  • 说一说时间戳机制的妙用

    一、时间戳是什么? 时间戳主要是标记数据的变动时间,同时它在实际的查询和操作等接口中,也有它的妙用。 数据库的某条...

  • 机制的妙用

    美国经济学家埃里克·马斯金,曾因“机制设计理论”获得了2007年诺贝尔经济学奖。这个理论的核心是:为了达到特定的目...

  • pyspider爬虫爬携程全国酒店遇到的坑,时间戳不能作为唯一标

    时间戳格式化成字符串之后的结果:自己看结果 pyspider内置url去重机制,本想着,根据时间戳的唯一性来拼接u...

  • 时间的妙用

    时间若金 不可虚掷 少生一个俗念 让时间降生高尚的动机 少生一个固念 让时间诞生改错的机会 少生一个恶念 让时间萌...

  • 时间的妙用

    我身边的一位长者说过,有些事放一放,留给时间,自然会解决。这是经验之谈,没经过是说不出这样的话的。当时我不...

  • 解决CAS机制中ABA问题的AtomicStampedRefer

    AtomicStampedReference是一个带有时间戳的对象引用,能很好的解决CAS机制中的ABA问题,这篇...

  • 时间戳

    很多网站在发布版本之前,都会在请求地址加一个时间戳进行版本更新。这样是版本更新时避免之前用户浏览器的缓存影响。请求...

  • 时间戳

    一. 关于[NSDatedate] 的问题 NSDate*date=[NSDatedate]; NSLog(@"d...

  • 时间戳

    时间戳 ios 在webView中的网页中,时间戳使用时(js)格式要用/ 而不能是-如 应该使用2018/09...

  • 时间戳

    时间戳转换成距此刻多久

网友评论

      本文标题:说一说时间戳机制的妙用

      本文链接:https://www.haomeiwen.com/subject/yvdmirtx.html