Java中属性名与数据库字段名互转应优先使用ORM框架内置机制(如MyBatis的mapUnderscoreToCamelCase),反射仅用于自定义场景;基础转换需手动实现驼峰与下划线互转逻辑,结合注解(如@Column)支持字段名覆盖,并通过缓存优化反射开销。

Java中通过反射实现属性名(驼峰)与数据库字段名(下划线)互转,核心在于:不依赖外部框架时,用反射获取字段名后,手动做字符串转换;若结合MyBatis、JPA等,则优先走其内置映射机制(如MyBatis的mapUnderscoreToCamelCase),反射仅用于自定义场景(如通用DAO、字段元信息解析)。
一、基础字符串转换工具方法
这是互转的底层能力,与反射无关但必须先实现:
-
驼峰转下划线:遍历字符,遇到大写字母(非首字母)前插入
_,再转小写。例如:userName→user_name,XMLParser→xml_parser(需处理连续大写) -
下划线转驼峰:按
_分割,首段小写,后续每段首字母大写并拼接。例如:user_info_id→userInfoId,create_time→createTime
推荐使用 Apache Commons Lang 的 StringUtils.camelCaseToSnakeCase() 和 snakeCaseToCamelCase(),或自行实现时注意边界情况(如开头/结尾下划线、连续下划线、全大写缩写)。
二、用反射读取类字段并批量转换
适用于运行时动态获取实体类所有字段名,并统一转为数据库字段名(比如生成建表SQL、构造查询条件):
立即学习“Java免费学习笔记(深入)”;
- 调用
clazz.getDeclaredFields()获取全部字段(含私有) - 对每个
Field调用field.getName()得到驼峰属性名 - 用上一步的工具方法转为下划线格式,存入
Map<string string></string>(key=属性名,value=字段名) - 可缓存该映射结果(用
ConcurrentHashMap+ 类对象作key),避免重复反射开销
示例片段:
Field[] fields = User.class.getDeclaredFields();Map
for (Field f : fields) {
String prop = f.getName();
String col = StringUtils.camelCaseToSnakeCase(prop);
columnMap.put(prop, col);
}
三、结合注解支持自定义字段名
实际项目中常需覆盖默认规则(如属性 uid 对应字段 user_id),此时应引入注解:
- 定义一个简单注解,如
@Column(name = "user_id") - 反射获取字段时,先检查是否标注该注解:
f.getAnnotation(Column.class) - 若有,则直接取
name()值;否则走默认驼峰→下划线转换 - 同理,反向映射(查库后填充对象)时,也优先按注解名匹配,再 fallback 到转换逻辑
这样既保持灵活性,又不破坏约定优于配置的原则。
四、在ORM框架中慎用纯反射转换
MyBatis、Hibernate 等已内置成熟映射策略,直接使用更安全:
- MyBatis:开启
configuration.mapUnderscoreToCamelCase=true,自动完成 ResultSet 到对象的字段映射 - JPA/Hibernate:用
@Column(name = "xxx")或命名策略(如PhysicalNamingStrategy)统一管理 - 手写 JDBC 或轻量 DAO 时,才需自己用反射+转换逻辑组装 SQL 或参数(如
"SELECT " + join(columns, ", ") + " FROM user")
强行在框架内绕过其映射机制、另起一套反射转换,容易引发类型擦除、泛型丢失、代理对象失效等问题。


















