记得第一次写项目的时候,傻傻的数据库一张表,代码里就写一个DAO类,几张表就写几个DAO类,大量的反复代码,自己粘着都嫌烦,后来接触了Hibernate,不得不说对我们这样的小白用处还是非常大的。那么多的实体类,一个DAO就能够实现主要的数据库操作了。于是我用的不亦乐乎,但究竟是怎么做的,从来没有考虑过。如今用这些框架已经有一段时间了,原谅我脑洞大开,想自己实现一下这样的类似的功能:
在准备写之前,我们须要一些规则:
1、由实体类名,能够知道我这个类是存放在哪张表里---这里我採用的是和t_类名
2、由实体类中的变量名能够知道相应表中的字段名的一一这里我採用f_变量名做为字段名
3、实体类里,有着对变量的赋值与获取,且方法名有一定的规则----比方我们经常使用的get、set方法 ,这里我也是採用这样的方法
一、利用如上规则设计相关的类与表:
我这里写了两个实体类customer和admin,并在类中多加了一个toString方法,便于后面信息打印查看:
类似能够写admin。都贴出来的话会非常长,就不贴了,相应的表结构设计例如以下:
二、利用反射拼出相应的数据库操作语句
保存语句拼凑:
这里的重点在于利用反射拼凑SQL语句的过程----
1、这个函数的參数类型是什么?怎样接收一个随意的实体类?
这里我用的是object,由于不管你传什么样的一个參数过来,其都是Objcet类的一个子类。用Object没有问题,这里我在考虑后面利用泛型,只是这种话在后面查询的话。实例化的时候要麻烦一点。
有了字段名。接下来,拿相应的值,也存到相应的list里。这里取值用的method.invoke方法。请參照上面代码,为了拼凑方便,对于字符串。我直接以“xxxx”的形式存储。
这里没用泛型的一个不好的地方在于,操作时常常须要进行强制类型转换。后面能够考虑利用泛型。
在准备写之前,我们须要一些规则:
1、由实体类名,能够知道我这个类是存放在哪张表里---这里我採用的是和t_类名
2、由实体类中的变量名能够知道相应表中的字段名的一一这里我採用f_变量名做为字段名
3、实体类里,有着对变量的赋值与获取,且方法名有一定的规则----比方我们经常使用的get、set方法 ,这里我也是採用这样的方法
一、利用如上规则设计相关的类与表:
我这里写了两个实体类customer和admin,并在类中多加了一个toString方法,便于后面信息打印查看:
package com.java.reflect.database;
public class Customer {
private Long id;
private String username;
private String password;
private String realname;
private String address;
private String email;
private String mobile;
@Override
public String toString() {
return "Customer [id=" + id + ", username=" + username + ", password="
+ password + ", realname=" + realname + ", address=" + address
+ ", email=" + email + ", mobile=" + mobile + "]";
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRealname() {
return realname;
}
public void setRealname(String realname) {
this.realname = realname;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
}
二、利用反射拼出相应的数据库操作语句
保存语句拼凑:
public static String saveSql(Object o){
StringBuilder sql = new StringBuilder();
Class c = o.getClass();
sql.append("INSERT INTO ");
Method[] methods = c.getMethods();
String cName = c.getName();
ArrayList<String> fieldNames = new ArrayList<String>();
ArrayList<Object> fieldValues = new ArrayList<Object>();
String tableName = "t_"+cName.substring(cName.lastIndexOf(".")+1,cName.length());
sql.append(tableName);
sql.append(" (");
for(Method method : methods){
String mName = method.getName();
if(mName.startsWith("get") && !mName.startsWith("getClass")){
String fName = "f_"+mName.substring(3);
fieldNames.add(fName);
try{
Object value = method.invoke(o, null);
if(value instanceof String){
fieldValues.add("""+value+""");
}
else{
fieldValues.add(value);
}
}
catch(Exception e){
e.printStackTrace();
}
}
}
for(int i = 0;i<fieldNames.size();++i){
if(i==0){
sql.append(fieldNames.get(i));
}
else{
sql.append(","+fieldNames.get(i));
}
}
sql.append(") values (");
for(int i = 0;i<fieldValues.size();++i){
if(i==0){
sql.append(fieldValues.get(i));
}
else{
sql.append(","+fieldValues.get(i));
}
}
sql.append(")");
return sql.toString();
}
1、这个函数的參数类型是什么?怎样接收一个随意的实体类?
这里我用的是object,由于不管你传什么样的一个參数过来,其都是Objcet类的一个子类。用Object没有问题,这里我在考虑后面利用泛型,只是这种话在后面查询的话。实例化的时候要麻烦一点。
临时先不考虑。
2、怎样知道这个实体类的类名?并找到相应的表?
利用函数getClass得到这个实体类相应的类。再利用getName得到类名,包含包名,再依照你制定的规则解析出相应的表名
3、開始拼凑sql语句,由于要重复的改变sql字符串,这里我用的StringBuilder对象。在插入的时候。我们的语句是这种
INSERT INTO 表名(字段名) VALUES (相应的值)
这里我们有三个须要知道的变量。表名已经在第二步中拿到
如今我们考虑拿字段名。拿到后存放到一个list里,首先拿我们全部的方法。找到以get开头的方法,我们依照对变量赋值时命名函数规则。全部以get开头的(我们把getClass排除在外),解析得到相应的字段名。这里相应我的语句:
有了字段名。接下来,拿相应的值,也存到相应的list里。这里取值用的method.invoke方法。请參照上面代码,为了拼凑方便,对于字符串。我直接以“xxxx”的形式存储。
有了对应的值。接下就是拼凑了,这个应该没什么难度,最后对于随意一个对象,拼凑的结果例如以下,customer有点长没能截全:
三、利用已经拼凑好的sql语句,运行。这个应该简单了吧
运行结果如图:
代码大致是这样子的,可是从健壮性上去考虑的话。还有非常多地方须要改动,这里仅仅是用来简单说明怎样利用反射来实现这样的统一的DAO操作。
关于查询,能够自己练习一下,也是相同利用反射拼凑出来,可是查询的关键在于怎样利用反射把查到数据包装成你须要的一个实体类。
測试代码:
打印结果:
这里没用泛型的一个不好的地方在于,操作时常常须要进行强制类型转换。后面能够考虑利用泛型。