Java中用JDBC实现简单ORM映射的核心是通过反射+ResultSetMetaData自动将数据库记录转为POJO,要求实体类字段与列名一致、含无参构造器和getter/setter,并封装query、mapTo等通用方法支持泛型查询与主键回填。

Java 中用 JDBC 实现简单 ORM 映射,核心是把数据库记录自动转成 Java 对象(POJO),避免手写大量 rs.getString("xxx")。这不是用 MyBatis 或 Hibernate,而是基于 JDBC 原生 API 自己封装一层轻量映射逻辑。
定义实体类并约定字段与列名一致
这是最简前提:实体类的属性名和数据库表字段名保持一致(大小写可忽略,但建议统一小写),且提供无参构造器和 getter/setter。JDBC 本身不关心注解,所以靠反射 + 字符串匹配来赋值。
- 例如表
user(id, name, email)对应类:public class User { private Long id; private String name; private String email; public User() {} // getter/setter 省略 } - 不强制要求字段完全同名,但映射逻辑会更复杂;先按同名做,后续再扩展别名支持。
用反射 + ResultSetMetaData 自动填充对象
关键在遍历 ResultSetMetaData 获取列名,再通过反射调用对应 setter 方法。注意处理基本类型包装、null 值和类型转换。
- 示例工具方法(简化版):
public static <T> T mapTo(ResultSet rs, Class<T> clazz) throws Exception {
ResultSetMetaData md = rs.getMetaData();
int columnCount = md.getColumnCount();
T obj = clazz.getDeclaredConstructor().newInstance();
<pre class='brush:java;toolbar:false;'>for (int i = 1; i <= columnCount; i++) {
String columnName = md.getColumnName(i).toLowerCase(); // 统一小写匹配
Object value = rs.getObject(i);
String setterName = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
Method setter = clazz.getMethod(setterName, value == null ? Object.class : value.getClass());
setter.invoke(obj, value);
}
return obj;}
立即学习“Java免费学习笔记(深入)”;
- 实际中需增强:处理 int/Integer、boolean/Boolean 类型差异;跳过无 setter 的字段;支持 @Column 注解(可选);捕获 NoSuchMethodException 并提示字段不匹配。
封装通用查询方法(支持泛型返回)
把连接、预编译、执行、映射打包成一个方法,让业务代码只关注 SQL 和类型。
- 示例:
public static <T> List<T> query(String sql, Class<T> clazz, Object... params) throws Exception {
try (Connection conn = DriverManager.getConnection(url, user, pwd);
PreparedStatement ps = conn.prepareStatement(sql)) {
<pre class='brush:java;toolbar:false;'> for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]);
}
List<T> list = new ArrayList<>();
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
list.add(mapTo(rs, clazz));
}
}
return list;
}}
立即学习“Java免费学习笔记(深入)”;
- 调用:
List<User> users = query("SELECT * FROM user WHERE age > ?", User.class, 18); - 注意资源必须用 try-with-resources 自动关闭,否则连接泄漏。
补充:主键回填与单条插入
插入后想拿到自增 ID,可用 Statement.RETURN_GENERATED_KEYS,再用相同映射逻辑读取生成的 key。
- 示例插入:
public static Long insertAndReturnId(String sql, Object... params) throws Exception {
try (Connection conn = DriverManager.getConnection(url, user, pwd);
PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
<pre class='brush:java;toolbar:false;'> for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]);
}
ps.executeUpdate();
try (ResultSet rs = ps.getGeneratedKeys()) {
if (rs.next()) {
return rs.getLong(1);
}
}
}
return null;}
立即学习“Java免费学习笔记(深入)”;
- 这样就不用查一遍再 getLong("id"),直接拿到刚插入的主键值。


















