Java游戲辦事器之數據庫表存取封裝。本站提示廣大學習愛好者:(Java游戲辦事器之數據庫表存取封裝)文章只能為提供參考,不一定能成為您想要的結果。以下是Java游戲辦事器之數據庫表存取封裝正文
項目觸及的數據庫表其實不多,但每一個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;
}
代碼封裝得很簡略單純,有更多需求可據此改良。