工作问题总结
总结了工作中遇到的一些问题及bug。
Mysql group by 不区分大小写的问题
在Mysql中,如果不特意指定字段,字段数据在group by时是不区分大小写的。
如下图:
对于user表,我们有4个用户,通过user_name group by之后我们只得到了两条数据。
可以看到,如果不特殊处理的话,Mysql在group by时是不区分大小写的。
解决方案有两个,都是通过BINARY
关键字解决:
BINARY
运算符将紧随其后的string
转换为 二进制字符串。
主要用来强制进行按字节进行比较的数据。这使得字符串比较是区分大小写的, 不管原始的列定义是否是 BINARY
或者 BLOB
。BINARY
也对字符串末尾的空格敏感。
对于查询,我们使用
BINARY
关键字。如下图效果:1
select user_name,COUNT(1) from `user` GROUP BY BINARY user_name;
可以看到得到了我们想要的结果。
当然也可以给表结构字段添加
BINARY
来解决,这会改变表的字符集及排序规则。1
2ALTER TABLE `user`
MODIFY COLUMN `user_name` varchar(100) BINARY DEFAULT NULL COMMENT '用户名';得到的表结构如下,我们再进行group by查询,可以看到指定字段已经区分了大小写。
当然对于大小写敏感的字段数据,我们可以在建表的时候直接指定字段的字符集及排序规则。
List去重问题
当然我们可以使用Set进行去重。
对于Java 8之后,我们可以使用流进行去重,如下语法:
1 | list.stream().distinct().collect(Collectors.toList()); |
对于对象列表的话,我们应重写对象的hashCode()
和equals()
方法,再使用流的distinct()
方法来进行去重。
distinct()
方法不提供按照属性对对象列表进行去重的直接实现。它是基于hashCode()
和equals()
工作的。
我们如果想按照属性对对象列表进行去重,除了使用普通循环处理外,还可以构建一个我们自己的Predicate
实例,通过流过滤来实现,具体如下:
1 |
|
其关键方法就是distinctByKey
方法,这个方法原理很简单,我们将对象属性放入HashMap中,通过它的putIfAbsent
来判断是否放入成功,不成功返回false,filter
自动过滤此对象。
上面的例子中,我们如果在对phone号码进行去重的时候,只想要时间比较新的怎么办呢?
很简单,我们只需在处理是先对流按照时间进行排序即可,如下:
1 | list.stream().sorted(Comparator.comparing(Phone::getCreateDate).reversed()) |
Mysql字符集问题
我在插入Mysql数据库表情等特殊符号时遇到了如下错误:
1 | ......Cause: java.sql.SQLException: Incorrect string value: '\xF0\x9D\x91\x80\xF0\x9D...' for column 'xxxxx' at row 1...... |
如果我们的目标表字符集设置的是CHARSET=utf8mb4
但仍是有这种问题,可能是Mysql数据库连接的字符集不正确。
我们可以通过SHOW VARIABLES LIKE 'character_set_%';
来查看当前Mysql数据库连接字符集。如下:
其中:
- character_set_client:指客户端字符集属性
- character_set_connection:指连接字符集属性
- character_set_database:指数据库字符集属性
- character_set_filesystem:指文件系统字符集属性
- character_set_results:指返回结果字符集属性
- character_set_server:指服务端字符集属性
- character_set_system:指系统字符集属性
- character_sets_dir:指字符集路径
影响我们保存和读取的主要为character_set_client
、character_set_connection
和character_set_results
这三个属性。
比如下面图示,我们保存数据失败了。
这时候我们设置一下这三个属性为utf8mb4
即可。如下:
1 | SET character_set_client = utf8mb4; |
PS:这时候该表的CHARSET
需要为utf8mb4
。
这三个设置也可以用一条设置代替。
1 | SET NAMES 'utf8mb4'; |
需要注意的是这种设置只在本次连接中有效,当连接中断时,需要重新设置。
我们在开发时,程序调用,可以通过jdbcUrl
进行设置。如下:
1 | jdbc:mysql://xx:xx:xxx:xxx/test?useUnicode=true&characterEncoding=utf8mb4 = |
出现上面异常一般的解决步骤:
检查数据表字符集是不是
utf8mb4
,不是的话需要通过如下语句进行修改。1
ALTER TABLE tbl_name [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name]
检查
character_set_client
、character_set_connection
和character_set_results
这三个属性的设置,一般情况下我们在程序里配置characterEncoding=utf8mb4
即可。
Java 过滤 utf8mb4 字符
1 | /** |
该方法可以过滤掉utf8mb4字符(4字节的UTF-8字符)。