我不知道现在原生的JDBC是否还受欢迎,但是我目前还在使用中,但是原生的JDBC对于查询还是太不智能了,不能通过简单的参数列表什么的返回需要的结果;我只想输入查询的sql语句,返回值的类型,参数列表,就可以得到查询的结果。不需要去获取链接,释放资源什么的。
所以,自己动手,丰衣足食是吧,开始写着一系列的包装类。
- 获取链接
目前最好的获取连接的方法是写一个连接池,将产生的连接保存起来,池满了进行资源的释放,这个留在以后改造
这次只是一个简单的链接获取类,可能还有些瑕疵,想的不够周全
/**
* 获取链接
*/
public class JdbcConnection {
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost:3306/mydb?user=root&password=root";
private JdbcConnection() {}
/**
* 获取数据库的链接
* @return conn
*/
public static Connection getJdbcConnetion() {
Connection conn = null;
try {
Class.forName(DRIVER);
conn = DriverManager.getConnection(URL);
} catch (ClassNotFoundException e) {
System.out.println("ClassNotFoundException when loading driver");
} catch (SQLException e) {
System.out.println("SQLException when loading driver");
}
return conn;
}
}
- queryForObjectList(String sql, Class clazz, String... params)
输入sql文,返回值类型,参数列表,返回一个该类型的List集合。
设计的思路:
sql文就不说了,查询肯定得用啊,然后就是返回值的类型,这个参数标识了你需要返回的集合类型(不知道我这样描述List<?>对不对),然后就是参数列表,当然你也可以不用穿参数列表把参数写在sql里就行了哈。
对于返回值类型这块我是通过JAVA中的反射获取到你想要的所有信息,然后进行一系列的处理,将结果返回,但是参数列表这,我原本打算是使用Object类型的,但是实际运用的时候发现有些问题没有解决,就放弃了,使用了String类型,我就好奇,为啥方法的参数类型是Object的时候,你传一个int、String、Integer啥的都不行。。。,这块还有一种思路就是使用Map<String, Object>去承接参数进行传递,但是我想了想可能处理比较复杂就放弃了,总的来说,反射很重要,所有的操作都是进行反射来进行的。 - 反射的入门
1.获取Class对象
- 反射的入门
//第一种方式
Class.forName("类的路径+名称");
//第二种方式
类的名称.class;
2.获取构造器
- - ```
//第一种方式,这种方式不能获取到私有的构造器
public Constructor<?>[] getConstructors();
//第二种方式,这种方式可以获取到所有的构造器与权限无关
public Constructor<?>[] getDeclaredConstructors();
3.获取方法
//第一种方式,通过方法的名字和他的形参类型进行获取
public Method getMethod(methodName, paramsType);
//第二种方式,获取所有的方法
public Method[] getDeclaredMethods();
使用上边的这些反射的知识就差不多可以动手写了。
- - 对于sql文的处理还是跟原有的一样
- - ```
//查询对象
PreparedStatement preparedStatement = null;
//结果集对象
ResultSet resultSet = null;
//获取查询对象
preparedStatement = conn.prepareStatement(sql);
/进行参数的处理
if ((null != params) && (params.length > 0)) {
for (int i = 0; i < params.length; i++) {
preparedStatement.setString(i + 1, params[i]);
}
}
//获得结果集
resultSet = preparedStatement.executeQuery();
- 根据返回值类型处理结果集
//结果集处理对象
ResultSetMetaData resultSetMetaData = null;
//结果集处理
resultSetMetaData = resultSet.getMetaData();
//获取到查询列的个数
int columnCount = resultSetMetaData.getColumnCount();
1.返回值类型是java.lang包下的类型,根据其对应的类型直接使用对应的构造器进行返回。
- - ```
//返回类型是java.lang下时的处理
if ("String".equals(clazz.getSimpleName())) {
resultObj = new String(resultSet.getString(resultSetMetaData.getColumnName(i)));
}
2.返回值类型是自定义的类型,通过反射进行处理,然后返回
//返回类型是自定义类型的处理
//获取到返回类型中的所有方法
Method[] methods = clazz.getDeclaredMethods();
String columnName = ("set" + resultSetMetaData.getColumnName(i)).toLowerCase();
for (int j = 0; j < methods.length; j++) {
String methodName = methods[j].getName().toLowerCase();
//使用对象中的setXXX()方法
if (columnName.equals(methodName)) {
String value = resultSet.getString(resultSetMetaData.getColumnName(i));
//进行查询结果类型的判断
String methodType = methods[j].getParameterTypes()[0].getName();
switch (methodType) {
case "java.lang.String":
methods[j].invoke(resultObj, value);
break;
case "int":
methods[j].invoke(resultObj, Integer.parseInt(value));
break;
case "java.lang.Integer":
methods[j].invoke(resultObj, Integer.parseInt(value));
break;
case "double":
methods[j].invoke(resultObj, Double.parseDouble(value));
break;
case "java.lang.Double":
methods[j].invoke(resultObj, Double.parseDouble(value));
break;
default:
break;
}
break;
}
}
对于switch这块的处理,还有一种方法如下,但是当返回对象中的属性类型是基本类型的时候,这种方式就会存在BUG,因为没有基本类型是没有构造器的。
- - ```
//进行查询结果类型的判断
Class methodType = methods[j].getParameterTypes()[0];
//获取参数类型的构造器
Constructor constructor = methodType.getConstructor(methodType);
methods[j].invoke(resultObj, constructor.newInstance(resultSet.getString(resultSetMetaData.getColumnName(i))));
- 测试
id | name | url | alexa | country |
---|---|---|---|---|
1 | Goole | https://www.google.com/ | 1 | USA |
2 | 淘宝 | https://www.taobao.com/ | 13 | CN |
3 | 菜鸟教程 | https://www.runoob.com/ | 4689 | CN |
4 | 微博 | https://weibo.com/ | 20 | CN |
5 | https://www.facebook.com/ | 30 | USA | |
6 | stackoverflow | https://stackoverflow.com/ | 0 | IND |
该表对应的DTO为
public class Websites implements Serializable {
/**
*
/
private static final long serialVersionUID = 8725455715197566090L;
/*
* id
/
private int id;
/*
* name
/
private String name;
/*
* url
/
private String url;
/*
* alexa
/
private String alexa;
/*
* country
*/
private String country;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getAlexa() {
return alexa;
}
public void setAlexa(String alexa) {
this.alexa = alexa;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
要求:查询id为1的记录
测试代码如下
- - ```
public class TestJdbcOperate {
public static void main(String[] args) {
StringBuilder sql = new StringBuilder();
sql.append(" select id id, ");
sql.append(" name name, ");
sql.append(" url url, ");
sql.append(" alexa alexa, ");
sql.append(" country country ");
sql.append(" from websites ");
sql.append(" where id = ?");
List<Websites> reuslt = JdbcOperate.queryForObjectList(sql.toString(), Websites.class, "1");
for(Websites websites : reuslt) {
System.out.println(websites.getId() + ", " + websites.getName() + "," + websites.getUrl() + ", " + websites.getAlexa() + ", " + websites.getCountry());
}
}
}
输出结果
1, Goole,https://www.google.com/, 1, USA
虽然说测试成功了,但是这个方法的健壮性还得测试,我是不想把测试方法写的这么LOW的,但是不知道Junit的jar为啥build不进去就放弃了。虽然Junit用的也不6。