欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java游戲服務(wù)器之?dāng)?shù)據(jù)庫表存取封裝

 更新時(shí)間:2015年11月30日 15:11:18   作者:Metazion  
這篇文章主要介紹了Java游戲服務(wù)器之?dāng)?shù)據(jù)庫表存取封裝的相關(guān)資料,需要的朋友可以參考下

項(xiàng)目涉及的數(shù)據(jù)庫表并不多,但每個(gè)select、insert、update和delete都去手動(dòng)拼接字符串,是很低效的,尤其在時(shí)常要修改結(jié)構(gòu)的情況下。開發(fā)的一個(gè)目標(biāo)就是自動(dòng)化,即能自動(dòng)實(shí)現(xiàn)的事情就不要手動(dòng)去做;還有一個(gè)原則是單一化,即盡量保證數(shù)據(jù)或邏輯一個(gè)入口一個(gè)出口。這個(gè)需求可以使用一些開源庫解決,但因?yàn)樾枨蠛唵危繕?biāo)明確,沒有必要引入多余的第三方庫。于是自己寫了一個(gè),至少滿足當(dāng)前需求。

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

table類表結(jié)構(gòu)描述可以有兩個(gè)來源,自動(dòng)從數(shù)據(jù)庫獲取,或從配置表加載。這里選擇從配置表加載的方式,一來實(shí)現(xiàn)簡單,二來應(yīng)用面更廣。

下面是一個(gè)賬戶表的配置示例(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>

只定義了一個(gè)主鍵,有需要可對(duì)此擴(kuò)充。每列name對(duì)應(yīng)數(shù)據(jù)庫表的列名,field對(duì)應(yīng)邏輯對(duì)象的成員變量名,type對(duì)應(yīng)字段的類型,比如是int、string、timestamp等,有了名字和類型,就可以使用反射方式自動(dòng)get和set數(shù)據(jù)。

Table類讀取配置文件獲得數(shù)據(jù)表的結(jié)構(gòu)描述。

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的預(yù)處理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類的功能就這么多,下面是關(guān)鍵的Record類,其使用反射自動(dòng)存取數(shù)據(jù)。

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

模板參數(shù)T即一個(gè)表記錄對(duì)應(yīng)的邏輯對(duì)象。在我們的示例里,即賬戶數(shù)據(jù)類:

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

有了SQL語句,要先設(shè)置參數(shù),才能執(zhí)行。主鍵和普通字段分開設(shè)置。

 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;
  }

就是根據(jù)表結(jié)構(gòu)描述,通過反射獲取對(duì)應(yīng)字段的值然后設(shè)置。

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

toDBValue作用是將Java邏輯類型轉(zhuǎn)成對(duì)應(yīng)數(shù)據(jù)庫類型,比如時(shí)間,在邏輯里是Long,而數(shù)據(jù)庫類型是Timestamp。

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

以設(shè)置update SQL參數(shù)為例:

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

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

下面給出一個(gè)使用的完整示例:

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;
  }

代碼封裝得很簡易,有更多需求可據(jù)此改進(jìn)。

相關(guān)文章

  • Java CAS操作與Unsafe類詳解

    Java CAS操作與Unsafe類詳解

    這篇文章主要介紹了Java CAS操作與Unsafe類的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-02-02
  • SpringBoot2零基礎(chǔ)到精通之?dāng)?shù)據(jù)庫專項(xiàng)精講

    SpringBoot2零基礎(chǔ)到精通之?dāng)?shù)據(jù)庫專項(xiàng)精講

    SpringBoot是一種整合Spring技術(shù)棧的方式(或者說是框架),同時(shí)也是簡化Spring的一種快速開發(fā)的腳手架,本篇我們來學(xué)習(xí)如何連接數(shù)據(jù)庫進(jìn)行操作
    2022-03-03
  • Java核心編程之文件隨機(jī)讀寫類RandomAccessFile詳解

    Java核心編程之文件隨機(jī)讀寫類RandomAccessFile詳解

    這篇文章主要為大家詳細(xì)介紹了Java核心編程之文件隨機(jī)讀寫類RandomAccessFile,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • Monaco?Editor實(shí)現(xiàn)sql和java代碼提示實(shí)現(xiàn)示例

    Monaco?Editor實(shí)現(xiàn)sql和java代碼提示實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了Monaco?Editor代碼提示sql和java實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Java?Stream常用方法合集(超詳細(xì))

    Java?Stream常用方法合集(超詳細(xì))

    Stream?API?提供了一種更為簡潔高效的的方式來處理集合數(shù)據(jù),??可讀性較高,?所以本文為大家整理了Java?Stream中的常用方法,希望對(duì)大家有所幫助
    2023-07-07
  • Spring-retry實(shí)現(xiàn)循環(huán)重試功能

    Spring-retry實(shí)現(xiàn)循環(huán)重試功能

    這篇文章主要介紹了Spring-retry 優(yōu)雅的實(shí)現(xiàn)循環(huán)重試功能,通過@Retryable注解,優(yōu)雅的實(shí)現(xiàn)循環(huán)重試功能,需要的朋友可以參考下
    2023-07-07
  • SpringBoot整合Retry實(shí)現(xiàn)錯(cuò)誤重試過程逐步介紹

    SpringBoot整合Retry實(shí)現(xiàn)錯(cuò)誤重試過程逐步介紹

    重試的使用場(chǎng)景比較多,比如調(diào)用遠(yuǎn)程服務(wù)時(shí),由于網(wǎng)絡(luò)或者服務(wù)端響應(yīng)慢導(dǎo)致調(diào)用超時(shí),此時(shí)可以多重試幾次。用定時(shí)任務(wù)也可以實(shí)現(xiàn)重試的效果,但比較麻煩,用Spring Retry的話一個(gè)注解搞定所有,感興趣的可以了解一下
    2023-02-02
  • Java之ThreadLocal使用常見和方式案例講解

    Java之ThreadLocal使用常見和方式案例講解

    這篇文章主要介紹了Java之ThreadLocal使用常見和方式案例講解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • SpringBoot實(shí)現(xiàn)PPT格式文件上傳并在線預(yù)覽功能

    SpringBoot實(shí)現(xiàn)PPT格式文件上傳并在線預(yù)覽功能

    本文介紹SpringBoot實(shí)現(xiàn)PPT格式文件上傳并在線預(yù)覽功能,通過上傳接口,可在C盤的tempfile目錄下找到上傳的文件,預(yù)覽時(shí)會(huì)在同級(jí)目錄下創(chuàng)建一個(gè)相同文件名后綴為pdf的文件,每次預(yù)覽會(huì)先查找文件是否存在,存在則直接預(yù)覽,不存在則會(huì)走上面的處理,需要的朋友可以參考下
    2022-02-02
  • Java?NIO?中?Selector?解析

    Java?NIO?中?Selector?解析

    這篇文章主要介紹了Java?NIO?中?Selector,Selector即選擇器,選擇器提供選擇執(zhí)行已經(jīng)就緒的任務(wù)的能力即為翻譯為多路復(fù)用,下面文章對(duì)Selector詳細(xì)介紹內(nèi)容,需要的小伙伴可以參考一下
    2022-02-02

最新評(píng)論