JAVA数据库游戏记录_Java游戏服务器之数据库表存取封装

项目涉及的数据库表并不多,但每个select、insert、update和delete都去手动拼接字符串,是很低效的,尤其在时常要修改结构的情况下。开发的一个目标就是自动化,即能自动实现的事情就不要手动去做;还有一个原则是单一化,即尽量保证数据或逻辑一个入口一个出口。这个需求可以使用一些开源库解决,但因为需求简单,目标明确,没有必要引入多余的第三方库。于是自己写了一个,至少满足当前需求。

数据库表的封装,核心类有两个,表(Table)和记录(Record)。首先需要一个Table类保存数据库表结构的描述,并籍此自动生成相应SQL语句。其次需要一个Record类自动设置SQL参数,并从返回结果集中自动生成逻辑对象。

table类表结构描述可以有两个来源,自动从数据库获取,或从配置表加载。这里选择从配置表加载的方式,一来实现简单,二来应用面更广。

下面是一个账户表的配置示例(user.xml)。

只定义了一个主键,有需要可对此扩充。每列name对应数据库表的列名,field对应逻辑对象的成员变量名,type对应字段的类型,比如是int、string、timestamp等,有了名字和类型,就可以使用反射方式自动get和set数据。

Table类读取配置文件获得数据表的结构描述。

public class Table {

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 tableFields = new ArrayList();

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 {

private Table 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.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

final int size = normalFields.size();

for (int index = 0; index < size; ++index) {

Table.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.TableField tableField) throws Exception {

Field field = object.getClass().getDeclaredField(tableField.fieldName);

return field.get(object);

}

toDBValue作用是将Java逻辑类型转成对应数据库类型,比如时间,在逻辑里是Long,而数据库类型是Timestamp。

private Object toDBValue(Table.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 udTable = new Table();

...

udTable.load("user.xml");

...

public static boolean updateUserData(UserData userData) {

boolean result = false;

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

}

代码封装得很简易,有更多需求可据此改进。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值