网站首页 > 精选教程 正文
最近在公司开发的项目是对账系统,其中就包括每日(T+1)对账。 每日对账就是对前一日期产生的数据核对。 举个具体的例子就是: 在第三方支付公司,里面会产生支付里面的支付订单与下载渠道(微信、支付或者其它第三方支付)的每日交易账户需要进行对比。 关于微信支付的下载交易账单地址。 支付宝或者其它的下载交易单内容类似,只是文件格式不一样。
我们来看一下对账的数据流向:
今天要说的是在查询我们保存的第三方支付支付订单与微信支付的交易账单进行对比的时候,在查询我们 T 日数据的时候多查询出来了数据导致数据对不平。下面我把数据库的对账表的简化模型简单列举一下:
对账数据表
create table trade_record (
id BIGINT(20) AUTO_INCREMENT COMMENT '主键',
source_no varchar(32) not null DEFAULT '' COMMENT '数据来源(微信、交易系统、支付宝等)',
order_no VARCHAR(64) not null DEFAULT '' COMMENT '订单号',
compare_no VARCHAR(64) not null DEFAULT '' COMMENT '对比号',
amount DECIMAL(20,4) not null default '0' COMMENT '金额',
trade_at DATETIME not null COMMENT '交易成功时间',
create_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
index idx_trade_at(trade_at),
index idx_create_at(create_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '交易记录表';
我们先插入几条数据用于查询测试:
待对账数据
-- 支付系统订单
insert into trade_record(source_no, order_no, compare_no, amount, trade_at)
values ('payment', '111111', '111111', '100', '2022-05-10 02:23:43');
insert into trade_record(source_no, order_no, compare_no, amount, trade_at)
values ('payment', '222222', '222222', '200', '2022-05-10 05:23:43');
insert into trade_record(source_no, order_no, compare_no, amount, trade_at)
values ('payment', '333333', '333333', '300', '2022-05-10 12:23:43');
insert into trade_record(source_no, order_no, compare_no, amount, trade_at)
values ('payment', '444444', '444444', '400', '2022-05-10 23:23:43');
insert into trade_record(source_no, order_no, compare_no, amount, trade_at)
values ('payment', '555555', '555555', '500', '2022-05-11 00:00:10');
-- 渠道返回订单
insert into trade_record(source_no, order_no, compare_no, amount, trade_at)
values ('wechat_pay', '111111', '111111', '100', '2022-05-10 02:23:43');
insert into trade_record(source_no, order_no, compare_no, amount, trade_at)
values ('wechat_pay', '222222', '222222', '200', '2022-05-10 05:23:43');
insert into trade_record(source_no, order_no, compare_no, amount, trade_at)
values ('wechat_pay', '333333', '333333', '300', '2022-05-10 12:23:43');
insert into trade_record(source_no, order_no, compare_no, amount, trade_at)
values ('wechat_pay', '444444', '444444', '400', '2022-05-10 23:23:43');
insert into trade_record(source_no, order_no, compare_no, amount, trade_at)
values ('wechat_pay', '555555', '555555', '500', '2022-05-11 00:00:00');
插入完成后,总共 10 条数据:
比如我们需要比较 2022-05-10 的数据的时候,那些我们只需要查询出时间范围为:2022-05-10 00:00:00 ~ 2022-05-10 23:59:59 的微信支付以及支付平台的数据然后按照 compare_no 进行逐条对比就行了。
支付系统数据:
渠道返回数据:
查询出来两方数据,我们就可以根据 compare_no 进行逐一比对,可以得到两方的对账是可以对平的。虽然我们是这样设计的,然后我们验证也没有问题。但是在 线上出现了对账不匹配的情况 。
DateUtils.java
public abstract class DateUtils {
/**
* 昨天的开始时间
* @return
*/
public static LocalDateTime yesterdayDateBegin() {
LocalDate currentTime = LocalDate.now();
LocalDate yesterday = currentTime.plusDays(-1);
return LocalDateTime.of(yesterday, LocalTime.MIN);
}
/**
* 昨天的结束时间
* @return
*/
public static LocalDateTime yesterdayDateEnd() {
LocalDate currentTime = LocalDate.now();
LocalDate yesterday = currentTime.plusDays(-1);
return LocalDateTime.of(yesterday, LocalTime.MAX);
}
}
以上是日期工具类,在单元测试的时候没有问题。但是上面的工具类得到的开始结束时间,以 2022-05-10 为例:
昨日开始时间:2022-05-09T00:00
昨日结束时间:2022-05-09T23:59:59.999999999
然后以上面的时间进行查询的得到的结果是:
结果查询出来了一条交易成功时间为:2022-05-11 00:00:00 的数据,与我们的期望不符。我们可以查看 Mysql 官网对于 Datetime 这个日期类型的描述。可以看到 Datetime 这个日期类型的精度为小数点后面 6 位 。而我们在 查询的时候使用的是 9 位 。于是我就使用不同的精度的结束时间进行查询:
- 使用 6 位精度的结束时间查询:也就是 2022-05-10 23.59.59. 添加 6 个 9 进行查询,查询总条数为 4 条,符合期望。
- 使用 7 位精度的结束时间查询:也就是 2022-05-10 23.59.59. 添加 7 个 9 进行查询,查询总条数为 5 条,不符合期望。
- 使用 7 位精度的结束时间查询:也就是 2022-05-10 23.59.59. 添加 9999991 进行查询,查询总条数为 4条,符合期望。
- 使用 7 位精度的结束时间查询:也就是 2022-05-10 23.59.59. 添加 9999992 进行查询,查询总条数为 4条,符合期望。
- 使用 7 位精度的结束时间查询:也就是 2022-05-10 23.59.59. 添加 9999993 进行查询,查询总条数为 4条,符合期望。
- 使用 7 位精度的结束时间查询:也就是 2022-05-10 23.59.59. 添加 9999994 进行查询,查询总条数为 4条,符合期望。
- 使用 7 位精度的结束时间查询:也就是 2022-05-10 23.59.59. 添加 9999995 进行查询,查询总条数为 5条,不符合期望。
- 使用 8 位精度的结束时间查询:也就是 2022-05-10 23.59.59. 添加 8 个 9 进行查询,查询总条数为 5 条,不符合期望。
- 使用 9 位精度的结束时间查询:也就是 2022-05-10 23.59.59. 添加 9 个 9 进行查询,查询总条数为 5 条,不符合期望。
所以我们可以得出结论: 在使用 MySQL datetime 进行数据查询的时候只能使用正确的精度才能得出符合期望的数据。并且当使用 datetime 大于精度的时候是进行四舍五入的 。
建议大家在查询一天内的数据的时候使用 左关右开 模式也就是:
时间 >= ‘2022-05-10 00:00:00’ 并且 时间 < ‘2022-05-11 00:00:00’
参考文章
转自:carl-zhao,
链接: blog.csdn.net/u012410733/article/details/124678331
猜你喜欢
- 2024-11-24 Java好用的时间类,别再用Date了
- 2024-11-24 DATE #4、Java操作日期时间-⑦.日期格式化字符串
- 2024-11-24 Java 时间轮算法该如何实现?
- 2024-11-24 JDK8 新特性之新的日期&时间API,一篇讲清楚!
- 2024-11-24 java操作Redis缓存设置过期时间的方法
- 2024-11-24 日期循环遍历 shell & java
- 2024-11-24 Java日期查询
- 2024-11-24 JAVA8时间工具类
- 2024-11-24 equals与时间序列攻击
- 2024-11-24 详细介绍一下Spring Boot中对于日期时间数据类型的处理?
你 发表评论:
欢迎- 04-11Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- 04-11Java中你知道几种从字符串中找指定的字符的数量
- 04-11探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- 04-11Python字符串详解与示例(python字符串的常见操作)
- 04-11java正则-取出指定字符串之间的内容
- 04-11String s1 = new String("abc");这句话创建了几个字符串对象?
- 04-11java判断字符串中是否包含某个字符
- 04-11关于java开发中正确的发牌逻辑编写规范
- 最近发表
-
- Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- Java中你知道几种从字符串中找指定的字符的数量
- 探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- Python字符串详解与示例(python字符串的常见操作)
- java正则-取出指定字符串之间的内容
- String s1 = new String("abc");这句话创建了几个字符串对象?
- java判断字符串中是否包含某个字符
- 关于java开发中正确的发牌逻辑编写规范
- windows、linux如何后台运行jar(并且显示进程名)
- 腾讯大佬私人收藏,GitHub上最受欢迎的100个JAVA库,值得学习
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)