遊戲伺服器資料表雖不多,但手寫 SQL 拼接維護成本高、易出錯。目標:自動化(減少手工勞動)與 單一化(資料/邏輯單一入口出口),且不引入重型 ORM 框架。
<Table name="user" primaryKey="user_id" primaryField="userId">
<Column name="username" field="username" type="2" />
<Column name="password" field="password" type="2" />
<Column name="salt" field="salt" type="1" />
<Column name="reg_time" field="registerTime" type="3" />
<Column name="last_login_time" field="lastLoginTime" type="3" />
</Table>
name:資料庫欄位名field:Java 物件屬性名type:1=int、2=String、3=Timestamppublic class Table<T> {
public static class TableField {
public static final int TYPE_INT = 1, TYPE_STRING = 2, TYPE_TIMESTAMP = 3;
public String columnName, fieldName;
public int type;
}
private String tableName;
private TableField primaryField;
private List<TableField> fields = new ArrayList<>();
private String selectSql, insertSql, updateSql, deleteSql;
public void load(String xmlPath) { /* DOM 解析 XML 填充上述欄位 */ }
private String generateUpdateSql() {
StringBuilder sql = new StringBuilder("UPDATE ").append(tableName).append(" SET ");
for (int i = 0; i < fields.size(); i++) {
if (i > 0) sql.append(",");
sql.append(fields.get(i).columnName).append(" = ?");
}
sql.append(" WHERE ").append(primaryField.columnName).append(" = ?");
return sql.toString();
}
// 同理生成 select/insert/delete SQL
}
public class Record<T> {
private Table<T> table;
private T object; // 業務物件,如 UserData
public void setUpdateParams(PreparedStatement pst) throws Exception {
int idx = setNormalParams(1, pst); // 普通欄位
setPrimaryParams(idx, pst); // 主鍵
}
private int setNormalParams(int start, PreparedStatement pst) throws Exception {
for (int i = 0; i < table.getFields().size(); i++) {
TableField f = table.getFields().get(i);
Object val = getFieldValue(f);
val = toDBValue(f, val); // 型別轉換:Long → Timestamp
pst.setObject(start + i, val);
}
return start + table.getFields().size();
}
private Object getFieldValue(TableField f) throws Exception {
Field field = object.getClass().getDeclaredField(f.fieldName);
field.setAccessible(true);
return field.get(object);
}
private Object toDBValue(TableField f, Object val) {
if (f.type == TableField.TYPE_TIMESTAMP && val instanceof Long) {
return new Timestamp((Long) val);
}
return val;
}
}
public class UserData implements Serializable {
public int userId;
public String username;
public String password;
public String salt;
public long registerTime; // 對應 Timestamp
public long lastLoginTime;
}
// 單例 Table 實例
private static final Table<UserData> USER_TABLE = new Table<>();
static { USER_TABLE.load("user.xml"); }
public static boolean updateUser(UserData user) {
try (Connection conn = DbUtil.getConnection();
PreparedStatement pst = conn.prepareStatement(USER_TABLE.getUpdateSql())) {
Record<UserData> record = USER_TABLE.createRecord();
record.setObject(user);
record.setUpdateParams(pst);
return pst.executeUpdate() > 0;
} catch (Exception e) {
log.error("更新失敗", e);
return false;
}
}
batchInsert(List<T>) 使用 addBatch()selectByCondition(Map<String, Object>) 動態構建 WHERE此輕量封裝以 XML 描述結構 + 反射自動映射 為核心,約 200 行代碼解決 80% CRUD 需求,無第三方依賴、編譯期無錯誤、運行期靈活擴展,極適合中小型遊戲伺服器快速迭代開發。