标题解释
MySQL数据库在Linux下的内容默认是大小写不区分的
遇到问题
最近在做从第三方获取数据,同步到本地库。
同步的原则很简单:数据存在就更新,不存在则新增。
伪代码:
// 从第三方获取数据列表 list
List<Dto> list = getListFromThird();
// 循环list,按照某个唯一字段作为key存入map;并将这个唯一字段存入列表
int listSize = list.size();
Map<String, Dto> key2DtoMap = new HashMap(listSize);
List<String> keys = new ArrayList(listSize);
list.forEach( d-> {
String key = d.getUniqueName();
key2DtoMap.put(key, d);
keys.add(key);
});
// 根据唯一字段列表从本地数据库查询
List<Po> poList = getLocalPoList(keys);
// 循环查出的数据,根据唯一字段从map中获取对象,更新旧数据
if(!CollectionUtis.isEmpty(poList)) {
poList.forEach( po -> {
String key = po.getUniqueName();
Dto dto = key2DtoMap.get(key);
// 注意:此处出现了NPE
po.setXXX(dto.getXXX()); // 注意:此处出现了NPE
// 注意:此处出现了NPE
...
update(po); // 此处单个保存或循环外批量保存都可以
}) ;
}
// 处理新增数据
...
在循环本地数据,从map中获取的dto为null。
很奇怪吧,map里面保存了第三方所有的唯一key。并且本地的数据是根据key来获取的,为什么会是null。
原因分析
Debug后发现,本地的数据库的key和第三方的key大小写不一致。
例如第三方的key为abc,并存入到map中;根据abc去db查询,查出了aBc。
循环本地数据,根据aBc去map中获取为null(map中的key为abc)。
解决或避免方案
- 使用mysql 的BINARY 关键字使搜索区分大小写。
select * from tb_user where BINARY account_name='abc';
优点:不需要改表
缺点:需要写sql,并要加BINARY。无法使用例如mybatis框架(度娘了下,没找到可以自动加BINARY的语句)
2. 建表使用BINARY限制
CREATE TABLE `t_account` (
`id` BIGINT (20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增id',
`account_name` VARCHAR (50) BINARY NOT NULL COMMENT '账号名',
PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT = '账号表';
- 代码对唯一值新增修改前做校验