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; }
代碼封裝得很簡略單純,有更多需求可據此改良。