获得一个包含对象的List集合,然后选择两个属性,执行List转换Map时,报如下错误:
java.lang.IllegalStateException: Duplicate key可能存在的问题
本来想通过加上形参(entity1, entity2) -> entity1 )来解决,但我还是想从数据来源上解决该问题,因为担心这种处理方式会导致产生不正常的业务数据,而导致Duplicate key重复的业务数据就像黑盒现象,严重了说可能是一个定时炸d,总会在某个测试场景爆发出来。
IpMacQuery ipMacQuery = new IpMacQuery(); ListmacList = IpMacRelationDao.queryGroupConcatMac(ipMacQuery); Map macList = macList.stream().collect(Collectors.toMap(IpMacRelation::getAssetId, IpMacRelation::getMac),(entity1, entity2) -> entity1));
最后发现是因为MYSQL的GROUP_CONCAT)排序问题+SQL UNIOn *** 作符导致的,问题数据示例如下
UNIOn *** 作符用于合并两个或多个 SELECt 语句的结果集。
请注意,UNIOn 内部的每个 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每个 SELECT 语句中的列的顺序必须相同
SQL UNIOn *** 作符 | 菜鸟教程 (runoob.com)
-
三个IP,三个MAC地址,本次以MAC作为演示
100 10.255.174.152 B0:83:FE:88:46:3A 100 3.3.5.7 62:45:23:45:23:46 100 3.3.5.8 25:43:53:54:53:54
如果不对结果中的值进行排序,遇到情况是,多个MAC的排序不一样,未排序的查询结果会与加入排序的查询结果不一样。
- 未排序的查询结果
SELECT test.id, group_concat( test.mac ) AS macs FROM ip_mac_test test GROUP BY test.pc_id
#1 100 B0:83:FE:88:46:3A,62:45:23:45:23:46,25:43:53:54:53:54
我们预期结果是:查询的内容是一样,即使MAC顺序不一样,也应该当作相同的记录,所以我们加上排序后就可以实现了,如下
- 加入排序的查询结果
SELECt test.pc_id, group_concat( test.mac ORDER BY test.mac ) AS macs FROM ip_mac_test test GROUP BY test.pc_id
查询结果
#2 100 25:43:53:54:53:54,62:45:23:45:23:46,B0:83:FE:88:46:3A
两次结果比对
#1 100 B0:83:FE:88:46:3A,62:45:23:45:23:46,25:43:53:54:53:54 #2 100 25:43:53:54:53:54,62:45:23:45:23:46,B0:83:FE:88:46:3A
异常场景举例使用UNIOn *** 作符,如果结果集1不排序,结果集2排序的话,那么会出现相同pc_id,macs不同的结果集(但实际上内容是一样),也就造成了Duplicate key异常的原因
SELECt test.pc_id, group_concat( test.mac ) AS macs FROM ip_mac_test test GROUP BY test.pc_id UNIOn SELECt test.pc_id, group_concat( test.mac ORDER BY test.mac ) AS macs FROM ip_mac_test test GROUP BY test.pc_id
相同pc_id,macs不同的结果集(但实际上内容是一样,group_concat拼接字符串顺序不一样)
100 B0:83:FE:88:46:3A,62:45:23:45:23:46,25:43:53:54:53:54 100 25:43:53:54:53:54,62:45:23:45:23:46,B0:83:FE:88:46:3A
以上 *** 作我们可以看出,如果两个查询SQL使用了group_concat 和 union时,不统一使用使用排序ORDER BY,那么合并的结果集在List转Map时必定导致异常。
正确示例SELECt test.pc_id, group_concat( test.mac ORDER BY test.mac ) AS macs FROM ip_mac_test test GROUP BY test.pc_id UNIOn SELECt test.pc_id, group_concat( test.mac ORDER BY test.mac ) AS macs FROM ip_mac_test test GROUP BY test.pc_id # 真实项目中,第1个和第2个SELECT的where条件可能不一样,这里只是简单举例说明示例数据SQL
-
DDL
CREATE TABLE `ip_mac_test` ( `id` int(11) NOT NULL, `pc_id` int(11) DEFAULT NULL, `ip` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `mac` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-
DML
INSERT INTO `ip_mac_test`(`id`, `pc_id`, `ip`, `mac`) VALUES (1, 100, '10.255.174.152', 'B0:83:FE:88:46:3A'); INSERT INTO `ip_mac_test`(`id`, `pc_id`, `ip`, `mac`) VALUES (2, 100, '3.3.5.7', '62:45:23:45:23:46'); INSERT INTO `ip_mac_test`(`id`, `pc_id`, `ip`, `mac`) VALUES (3, 100, '3.3.5.8', '25:43:53:54:53:54');
- 一次Collectors.toMap的问题 - 简书 (jianshu.com)
- (70条消息) mysql使用group_concat拼接查询时数据顺序无规律_王梦蛟的博客-CSDN博客
- MySQL中函数CONCAT及GROUP_ConCAT - 王不惑 - 博客园 (cnblogs.com)
- (69条消息) Java 8 – Convert List to Map(将 List 转换为 Map)_wangmm0218的博客-CSDN博客
- java8两个List集合取交集、并集、差集、去重并集 - 掘金 (juejin.cn)
- List集合常规去重与java8新特性去重方法 - 奕锋博客 - 博客园 (cnblogs.com)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)