国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java游戲服務器之數據庫表存取封裝

2019-11-26 14:48:22
字體:
來源:轉載
供稿:網友

項目涉及的數據庫表并不多,但每個select、insert、update和delete都去手動拼接字符串,是很低效的,尤其在時常要修改結構的情況下。開發的一個目標就是自動化,即能自動實現的事情就不要手動去做;還有一個原則是單一化,即盡量保證數據或邏輯一個入口一個出口。這個需求可以使用一些開源庫解決,但因為需求簡單,目標明確,沒有必要引入多余的第三方庫。于是自己寫了一個,至少滿足當前需求。

數據庫表的封裝,核心類有兩個,表(Table)和記錄(Record)。首先需要一個Table類保存數據庫表結構的描述,并籍此自動生成相應SQL語句。其次需要一個Record類自動設置SQL參數,并從返回結果集中自動生成邏輯對象。

table類表結構描述可以有兩個來源,自動從數據庫獲取,或從配置表加載。這里選擇從配置表加載的方式,一來實現簡單,二來應用面更廣。

下面是一個賬戶表的配置示例(user.xml)。

<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對應邏輯對象的成員變量名,type對應字段的類型,比如是int、string、timestamp等,有了名字和類型,就可以使用反射方式自動get和set數據。

Table類讀取配置文件獲得數據表的結構描述。

public class Table<T> {  public class TableField {    public static final int TYPE_INTEGER = 1;    public static final int TYPE_STRING = 2;    public static final int TYPE_TIMESTAMP = 3;    public String columnName = "";    public String fieldName = "";    public int type = 0;  }  private String tableName = "";  private TableField primaryField = new TableField();  private ArrayList<TableField> tableFields = new ArrayList<TableField>();  private String selectAllSql = "";  private String selectSql = "";  private String insertSql = "";  private String updateSql = "";  private String deleteSql = "";  ...

然后生成PrepareStatement方式讀寫的select、insert、update和delete的預處理SQL字符串。如update:

private String generateUpdateSql() {    String sql = "UPDATE " + tableName + " SET ";    int size = tableFields.size();    for (int index = 0; index < size; ++index) {      TableField tableField = tableFields.get(index);      String conjunction = index == 0 ? "" : ",";      String colSql = tableField.columnName + " = ?";      sql = sql + conjunction + colSql;    }    sql = sql + " WHERE " + primaryField.columnName + "=?";    return sql;  }

Table類的功能就這么多,下面是關鍵的Record類,其使用反射自動存取數據。

public class Record<T> {  private Table<T> table = null;  private T object = null;  ...

模板參數T即一個表記錄對應的邏輯對象。在我們的示例里,即賬戶數據類:

public class UserData implements Serializable {  // 用戶ID  public int userId = 0;  // 用戶名  public String username = "";  // 密碼  public String password = "";  ...

有了SQL語句,要先設置參數,才能執行。主鍵和普通字段分開設置。

 public int setPrimaryParams(int start, PreparedStatement pst) throws Exception {    Table<T>.TableField primaryField = table.getPrimaryField();    Object value = getFieldValue(primaryField);    value = toDBValue(primaryField, value);    pst.setObject(start, value);    return start + 1;  }  public int setNormalParams(int start, PreparedStatement pst) throws Exception {    ArrayList<Table<T>.TableField> normalFields = table.getNoramlFields();    final int size = normalFields.size();    for (int index = 0; index < size; ++index) {      Table<T>.TableField tableField = normalFields.get(index);      Object value = getFieldValue(tableField);      value = toDBValue(tableField, value);      pst.setObject(start + index, value);    }    return start + size;  }

就是根據表結構描述,通過反射獲取對應字段的值然后設置。

 private Object getFieldValue(Table<T>.TableField tableField) throws Exception {    Field field = object.getClass().getDeclaredField(tableField.fieldName);    return field.get(object);  }

toDBValue作用是將Java邏輯類型轉成對應數據庫類型,比如時間,在邏輯里是Long,而數據庫類型是Timestamp。

 private Object toDBValue(Table<T>.TableField tableField, Object value) {    if (tableField.type == TableField.TYPE_TIMESTAMP) {      value = new Timestamp((long) value);    }    return value;  }

以設置update SQL參數為例:

 public void setUpdateParams(PreparedStatement pst) throws Exception {    final int start = setNormalParams(1, pst);    setPrimaryParams(start, pst);  }

之后執行該SQL語句就可以了。如果是select語句還會返回結果集(ResultSet),從結果集自動生成邏輯對象原理類似,算是一個逆過程,詳細參看文末代碼。

下面給出一個使用的完整示例:

private static final Table<UserData> udTable = new Table<UserData>();...udTable.load("user.xml");...public static boolean updateUserData(UserData userData) {    boolean result = false;    Record<UserData> record = udTable.createRecord();    record.setObject(userData);    PreparedStatement pst = null;    try {      String sql = udTable.getUpdateSql();      pst = DbUtil.openConnection().prepareStatement(sql);      record.setUpdateParams(pst);      result = pst.executeUpdate() > 0;    } catch (Exception e) {      e.printStackTrace();    } finally {      DbUtil.closeConnection(null, pst);    }    return result;  }

代碼封裝得很簡易,有更多需求可據此改進。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 玉门市| 正镶白旗| 巩义市| 临潭县| 南投市| 呼和浩特市| 焦作市| 成安县| 平陆县| 五莲县| 梅州市| 怀柔区| 安国市| 昌都县| 鄂尔多斯市| 定州市| 年辖:市辖区| 阿坝县| 松滋市| 灌南县| 高清| 吴桥县| 宁津县| 九龙坡区| 林周县| 武邑县| 大厂| 司法| 绥阳县| 奉化市| 阳谷县| 鄂温| 远安县| 大安市| 密云县| 南京市| 炎陵县| 怀化市| 兴安县| 洛宁县| 定州市|