本文目录导读:

这是一个非常经典的造轮子问题,从零构建一个轻量级ORM(对象关系映射),能让你深刻理解JDBC、反射、泛型和设计模式。
为了控制复杂度,我们构建一个仅支持单表CRUD(增删改查)、基于注解、无缓存的迷你ORM,目标是用类似 userMapper.findById(1) 或 userMapper.save(user) 的方式操作数据库。
以下是完整的步骤和核心代码逻辑。
第一阶段:核心设计
定义映射注解
我们需要告诉ORM,Java类对应哪张表,字段对应哪一列。
// 表名注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {
String value(); // 表名
}
// 列名注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
String value(); // 列名
}
// 主键注解(特殊标记,用于更新/删除时的WHERE子句)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Id {
}
创建实体类示例
@Table("t_user")
public class User {
@Id
@Column("id")
private Long id;
@Column("user_name")
private String userName;
@Column("age")
private Integer age;
// getter / setter(必须,反射要用)
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
}
第二阶段:核心引擎
实体元数据解析器
解析类上的注解,缓存映射关系,避免每次操作都反射。
public class EntityMeta<T> {
private Class<T> entityClass;
private String tableName;
private Map<String, Field> columnFieldMap; // 列名 -> 字段
private Field idField; // 主键字段
private String idColumn; // 主键列名
public EntityMeta(Class<T> clazz) {
this.entityClass = clazz;
// 1. 解析表名
Table table = clazz.getAnnotation(Table.class);
if (table == null) throw new RuntimeException("Missing @Table annotation");
this.tableName = table.value();
// 2. 解析所有字段
this.columnFieldMap = new HashMap<>();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
Column column = field.getAnnotation(Column.class);
if (column != null) {
columnFieldMap.put(column.value(), field);
if (field.isAnnotationPresent(Id.class)) {
this.idField = field;
this.idColumn = column.value();
}
}
}
}
// getters...
public String getTableName() { return tableName; }
public Field getIdField() { return idField; }
public String getIdColumn() { return idColumn; }
public Map<String, Field> getColumnFieldMap() { return columnFieldMap; }
}
SQL 生成器
根据元数据动态生成SQL,防止SQL注入(使用 PreparedStatement)。
public class SqlBuilder<T> {
private EntityMeta<T> meta;
public SqlBuilder(EntityMeta<T> meta) {
this.meta = meta;
}
// 生成 INSERT 语句:INSERT INTO t_user (id, user_name, age) VALUES (?, ?, ?)
public String buildInsertSql() {
StringBuilder columns = new StringBuilder("(");
StringBuilder values = new StringBuilder("(");
for (String col : meta.getColumnFieldMap().keySet()) {
columns.append(col).append(",");
values.append("?,");
}
columns.deleteCharAt(columns.length()-1).append(")");
values.deleteCharAt(values.length()-1).append(")");
return "INSERT INTO " + meta.getTableName() + " " + columns + " VALUES " + values;
}
// 生成 SELECT BY ID:SELECT * FROM t_user WHERE id = ?
public String buildSelectByIdSql() {
return "SELECT * FROM " + meta.getTableName() + " WHERE " + meta.getIdColumn() + " = ?";
}
// 生成 UPDATE:UPDATE t_user SET user_name=?, age=? WHERE id=?
public String buildUpdateSql() {
StringBuilder setClause = new StringBuilder("SET ");
for (Map.Entry<String, Field> entry : meta.getColumnFieldMap().entrySet()) {
String col = entry.getKey();
if (col.equals(meta.getIdColumn())) continue; // 主键不更新
setClause.append(col).append("=?,");
}
setClause.deleteCharAt(setClause.length()-1);
return "UPDATE " + meta.getTableName() + " " + setClause + " WHERE " + meta.getIdColumn() + " = ?";
}
// 生成 DELETE BY ID
public String buildDeleteByIdSql() {
return "DELETE FROM " + meta.getTableName() + " WHERE " + meta.getIdColumn() + " = ?";
}
// 生成 SELECT ALL
public String buildSelectAllSql() {
return "SELECT * FROM " + meta.getTableName();
}
}
执行器(核心JDBC操作)
管理数据库连接,并处理 ResultSet -> 对象 的转换。
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class SimpleExecutor {
private DataSource dataSource; // 使用连接池,或简单的DriverManager
public SimpleExecutor(DataSource dataSource) {
this.dataSource = dataSource;
}
// 通用查询,返回实体列表
public <T> List<T> query(String sql, Object[] params, EntityMeta<T> meta) {
List<T> result = new ArrayList<>();
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
setParameters(pstmt, params);
try (ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
T entity = meta.getEntityClass().newInstance();
// 遍历所有列,通过反射赋值
for (Map.Entry<String, Field> entry : meta.getColumnFieldMap().entrySet()) {
String columnName = entry.getKey();
Field field = entry.getValue();
Object value = rs.getObject(columnName);
// 处理类型转换(如数据库中int到Java Integer)
if (value != null) {
field.set(entity, value);
}
}
result.add(entity);
}
}
} catch (Exception e) {
throw new RuntimeException("Query failed", e);
}
return result;
}
// 通用更新(INSERT/UPDATE/DELETE)
public int executeUpdate(String sql, Object[] params) {
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
setParameters(pstmt, params);
return pstmt.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException("Update failed", e);
}
}
// 设置参数到PreparedStatement
private void setParameters(PreparedStatement pstmt, Object[] params) throws SQLException {
if (params != null) {
for (int i = 0; i < params.length; i++) {
pstmt.setObject(i + 1, params[i]);
}
}
}
}
第三阶段:对外API(BaseMapper)
定义通用的CRUD接口,用户只需针对实体类调用。
public class BaseMapper<T> {
private final EntityMeta<T> meta;
private final SqlBuilder<T> sqlBuilder;
private final SimpleExecutor executor;
public BaseMapper(Class<T> clazz, DataSource dataSource) {
this.meta = new EntityMeta<>(clazz);
this.sqlBuilder = new SqlBuilder<>(meta);
this.executor = new SimpleExecutor(dataSource);
}
// --- CRUD 方法 ---
public T findById(Object id) {
String sql = sqlBuilder.buildSelectByIdSql();
List<T> list = executor.query(sql, new Object[]{id}, meta);
return list.isEmpty() ? null : list.get(0);
}
public List<T> findAll() {
String sql = sqlBuilder.buildSelectAllSql();
return executor.query(sql, null, meta);
}
public int save(T entity) {
// 获取所有非主键字段的值 + 主键值(如果主键是自增的,可以忽略主键字段)
List<Object> params = new ArrayList<>();
for (Field field : meta.getColumnFieldMap().values()) {
try {
params.add(field.get(entity));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
String sql = sqlBuilder.buildInsertSql();
return executor.executeUpdate(sql, params.toArray());
}
public int updateById(T entity) {
// 收集所有字段值(除主键外),最后加上主键值
List<Object> params = new ArrayList<>();
for (Map.Entry<String, Field> entry : meta.getColumnFieldMap().entrySet()) {
if (entry.getKey().equals(meta.getIdColumn())) continue;
try {
params.add(entry.getValue().get(entity));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
// 主键值放最后
try {
params.add(meta.getIdField().get(entity));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
String sql = sqlBuilder.buildUpdateSql();
return executor.executeUpdate(sql, params.toArray());
}
public int deleteById(Object id) {
String sql = sqlBuilder.buildDeleteByIdSql();
return executor.executeUpdate(sql, new Object[]{id});
}
}
如何使用?
public class Main {
public static void main(String[] args) {
// 1. 配置数据源(这里假设使用HikariCP或简单连接池)
DataSource dataSource = getDataSource();
// 2. 创建BaseMapper实例
BaseMapper<User> userMapper = new BaseMapper<>(User.class, dataSource);
// 3. 使用
// 查询
User user = userMapper.findById(1L);
System.out.println(user.getUserName());
// 新增
User newUser = new User();
newUser.setUserName("Alice");
newUser.setAge(30);
userMapper.save(newUser);
// 更新
user.setAge(31);
userMapper.updateById(user);
}
private static DataSource getDataSource() {
// 返回一个实现了 javax.sql.DataSource 的对象
// HikariDataSource
}
}
| 组件 | 职责 | 关键技术 |
|---|---|---|
| 注解 | 定义映射规则 | @Retention(RUNTIME) |
| EntityMeta | 缓存类/表/字段关系 | 反射 + Map |
| SqlBuilder | 预编译SQL生成 | PreparedStatement |
| SimpleExecutor | 执行JDBC,结果集转对象 | ResultSet.getObject + Field.set |
| BaseMapper | 统一CRUD接口 | 泛型 |
扩展方向(进阶)
如果你想让这个轻量级ORM更实用,可以逐步添加:
- 连接池集成:使用HikariCP或Druid作为DataSource。
- 命名策略:支持
camelCase -> snake_case自动映射,减少注解。 - 懒加载:对于关联对象,只在调用getter时查询。
- 条件查询:实现
QueryBuilder支持WHERE age > ? AND name LIKE ?。 - 事务管理:通过
Connection的commit/rollback实现。
这个Mini ORM的核心逻辑就在 反射(读注解、赋值) 和 JDBC(执行SQL、映射结果集) 之间来回穿梭,掌握它,你就掌握了所有ORM框架(MyBatis、Hibernate)的底层基因。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播