项目涉及的数据库表并不多,但每个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.TableField> normalFields = table.getNoramlFields();
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;
}
代码封装得很简易,有更多需求可据此改进。
Java相关栏目本月热门文章
- 1【Linux驱动开发】设备树详解(二)设备树语法详解
- 2别跟客户扯细节
- 3Springboot+RabbitMQ+ACK机制(生产方确认(全局、局部)、消费方确认)、知识盲区
- 4【Java】对象处理流(ObjectOutputStream和ObjectInputStream)
- 5【分页】常见两种SpringBoot项目中分页技巧
- 6一文带你搞懂OAuth2.0
- 7我要写整个中文互联网界最牛逼的JVM系列教程 | 「JVM与Java体系架构」章节:虚拟机与Java虚拟机介绍
- 8【Spring Cloud】新闻头条微服务项目:FreeMarker模板引擎实现文章静态页面生成
- 9JavaSE - 封装、static成员和内部类
- 10树莓派mjpg-streamer实现监控及拍照功能调试
- 11用c++写一个蓝屏代码
- 12从JDK8源码中看ArrayList和LinkedList的区别
- 13idea 1、报错java: 找不到符号 符号: 变量 log 2、转换成Maven项目
- 14在openwrt使用C语言增加ubus接口(包含C uci操作)
- 15Spring 解决循环依赖
- 16SpringMVC——基于MVC架构的Spring框架
- 17Andy‘s First Dictionary C++ STL set应用
- 18动态内存管理
- 19我的创作纪念日
- 20Docker自定义镜像-Dockerfile
热门相关搜索
路由器设置
木托盘
宝塔面板
儿童python教程
心情低落
朋友圈
vim
双一流学科
专升本
我的学校
日记学校
西点培训学校
汽修学校
情书
化妆学校
塔沟武校
异形模板
西南大学排名
最精辟人生短句
6步教你追回被骗的钱
南昌大学排名
清朝十二帝
北京印刷学院排名
北方工业大学排名
北京航空航天大学排名
首都经济贸易大学排名
中国传媒大学排名
首都师范大学排名
中国地质大学(北京)排名
北京信息科技大学排名
中央民族大学排名
北京舞蹈学院排名
北京电影学院排名
中国戏曲学院排名
河北政法职业学院排名
河北经贸大学排名
天津中德应用技术大学排名
天津医学高等专科学校排名
天津美术学院排名
天津音乐学院排名
天津工业大学排名
北京工业大学耿丹学院排名
北京警察学院排名
天津科技大学排名
北京邮电大学(宏福校区)排名
北京网络职业学院排名
北京大学医学部排名
河北科技大学排名
河北地质大学排名
河北体育学院排名



