一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語言 - JAVA教程 - Java游戲服務(wù)器之?dāng)?shù)據(jù)庫表存取封裝

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

2020-03-06 19:44Metazion JAVA教程

這篇文章主要介紹了Java游戲服務(wù)器之?dāng)?shù)據(jù)庫表存取封裝的相關(guān)資料,需要的朋友可以參考下

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

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

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

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

?
1
2
3
4
5
6
7
<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對應(yīng)數(shù)據(jù)庫表的列名,field對應(yīng)邏輯對象的成員變量名,type對應(yīng)字段的類型,比如是int、string、timestamp等,有了名字和類型,就可以使用反射方式自動get和set數(shù)據(jù)。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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類,其使用反射自動存取數(shù)據(jù)。

?
1
2
3
4
public class Record<T> {
  private Table<T> table = null;
  private T object = null;
  ...

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

?
1
2
3
4
5
6
7
8
public class UserData implements Serializable {
  // 用戶ID
  public int userId = 0;
  // 用戶名
  public String username = "";
  // 密碼
  public String password = "";
  ...

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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)描述,通過反射獲取對應(yīng)字段的值然后設(shè)置。

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

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

?
1
2
3
4
5
6
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ù)為例:

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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ù)此改進。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日本高清中文字幕视频在线 | 国产精品一区二区三 | 色综合色狠狠天天综合色 | 猥琐对着美女飞机喷到脸上 | 亚洲AV中文字幕无码久久 | 污小说h| 久草热在线 | zoo性欧美 | 草综合 | 日本深夜视频 | 国产人成激情视频在线观看 | 99视频有精品 | 色图18p | 免费观看欧美性一级 | 日韩在线天堂 | 午夜国产小视频 | 花房乱爱在线观看 | 日韩精品欧美 | 美女脱了内裤打开腿让人羞羞软件 | 高清视频在线观看+免费 | 青青青青青 | 亚洲 综合 欧美在线 热 | 欧美人禽杂交在线视频 | 91青青国产在线观看免费 | 视频国产精品 | 成人免费观看网欧美片 | 色综合久久丁香婷婷 | 1024免费观看完整版在线播放 | 歪歪视频在线播放无遮挡 | 欧美添下面视频免费观看 | 国产精品久久久精品日日 | 色老板在线播放 | 四虎精品永久在线网址 | 亚洲福利电影一区二区? | 欧美三级免费观看 | 国产视频一区二区 | 小嫩videos | 国产在线视频福利 | 黑帮少爷爱上我第8集最新 荷兰精品女人性hd 和日本免费不卡在线v | 香蕉久久一区二区三区啪啪 | 亚洲福利电影一区二区? |