Java8:解决List 转换为 Map出现Duplicate key问题

Java8:解决List 转换为 Map出现Duplicate key问题,第1张

Java8:解决List 转换为 Map出现Duplicate key问题

获得一个包含对象的List集合,然后选择两个属性,执行List转换Map时,报如下错误:

java.lang.IllegalStateException: Duplicate key
可能存在的问题

本来想通过加上形参(entity1, entity2) -> entity1 )来解决,但我还是想从数据来源上解决该问题,因为担心这种处理方式会导致产生不正常的业务数据,而导致Duplicate key重复的业务数据就像黑盒现象,严重了说可能是一个定时炸d,总会在某个测试场景爆发出来。

IpMacQuery ipMacQuery = new IpMacQuery();
List macList = 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)

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5573771.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-14

发表评论

登录后才能评论

评论列表(0条)

保存