1. 本文核心内容
- 深入了解BeanPropertyRowMapper为什么可以自动帮我们封装实体类。
- BeanPropertyRowMapper 是怎么识别 成员变量与列字段进行映射的。
- 字段驼峰写法 映射失败 的现象重现以及解决方法。
2. BeanPropertyRowMapper 映射原理
- 变量名与字段名完全相同,即可自动完成映射。
- 驼峰映射方式。
1. 变量名与字段名相同(代码演示)
-
先准备好一张表,如下: -
实体类代码: @Data
@AllArgsConstructor
@NoArgsConstructor
public class CfgInfo {
private Integer id;
private String CFG_NAM;
private String CFG_TYP;
private String CFG_010;
private String CFG_020;
}
-
代码: public class demo {
public static final String DRIVER = "com.mysql.cj.jdbc.Driver";
public static final String URL = "jdbc:mysql://localhost:3306/test_mysql?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8";
public static final String USERNAME = "root";
public static final String PASSWORD = "xxxxxx";
public static void main(String[] args) {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(DRIVER);
dataSource.setUrl(URL);
dataSource.setUsername(USERNAME);
dataSource.setPassword(PASSWORD);
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
CfgInfo cfgInfo = jdbcTemplate.queryForObject("SELECT * FROM CFG_TB",
new BeanPropertyRowMapper<>(CfgInfo.class));
System.out.println(cfgInfo);
}
}
这种情况,怎么样子都可以完美自动映射,不必多说。
2. 驼峰映射方式(错误重现)
-
表与上面相同。 -
实体类改为驼峰写法(除了id): @Data
@AllArgsConstructor
@NoArgsConstructor
public class CfgInfo {
private Integer id;
private String cfgNam;
private String cfgTyp;
private String cfg010;
private String cfg020;
}
-
jdbcTemplate代码不变,重新运行: 我们发现有些映射成功了,有些映射失败了,具体原因,请看下面的底层源码解析:
3. BeanPropertyRowMapper 底层原理
1. BeanPropertyRowMapper初始化源码
-
直接点进源码:
2. BeanPropertyRowMapper映射源码
插入小知识点:jdbc元数据相关博客:https://blog.csdn.net/xueyijin/article/details/121456405
4. 驼峰映射问题解决
1. 解释上述(驼峰映射方式)代码 原因
- 现在来解释一下 上述(驼峰映射方式)代码的问题了,cfg010 与 cfg020 没有办法被映射,
第一,全部变成小写还是 cfg010,cfg020 没有问题吧, 第二,驼峰换下划线,结果这tm数字没办法搞,因此等于没有。 然后字段CFG_010,CFG_020,这边全部去掉空格加变小写,cfg_010,cfg_020 ,这哪里有可以对应上的,所以才映射不上,为null。
2. 解决方法
1. 字段取名字规范
- 别取这么奇怪的,还带数字,恶心人啊,规范真正的驼峰。
2. sql语句 使用别名
3. 继承BeanPropertyRowMapper,重写里面的underscoreName方法
-
可以重写里面的underscoreName方法,生成mappedFields的key 条件变成个性化。 public class MyBeanPropertyRowMapper<T> extends BeanPropertyRowMapper<T> {
public MyBeanPropertyRowMapper(Class<T> mappedClass) {
super(mappedClass);
}
@Override
protected String underscoreName(String name) {
if (!StringUtils.hasLength(name)) {
return "";
}
if (name.length() < 3) {
return name;
}
StringBuilder result = new StringBuilder();
result.append(name).insert(3, "_");
return result.toString().toLowerCase();
}
}
4. 自己实现一个implements RowMapper
- 也可以自己实现一个映射关系的mapper,这个就不写代码了(有点麻烦,最简单就是copy BeanPropertyRowMapper源码 改一下),大体意思大家都明白的。
- 有的人问居然是copy BeanPropertyRowMapper源码,干嘛不直接继承它,一开始我也是这样子想的,但是它里面的属性要么就是private,要么就是private,要么就是private,继承没啥作用呢。
|