以下文章来源于何先振,责编小何

上讲我们讲了PreparedStatement接口的使用,学会了如何进行增删改查,根据增删改的特点封装了一个通用的增删改操作方法。
那么查询我们是否也可以进行封装成通用的呢?
下面我们就来进行封装成通用的查询。
上篇中在查询用户信息时,我们发现所有的查询SQL语句不一样,设置参数也不同,获取结果集的参数也不一样。

参照通用的增删改的方式,我们可以把SQL和SQL的参数值作为参数提取出来。

获取查询结果集时,不同的查询SQL,有多少列我们现在还是自己去识别的。
比如:这里我知道一行数据有4列,所以写四个get方法接收。

要想获取列的数量,我们查看JDK的开发文档,ResultSet提供了getMetaData方法让我们获取。

我们调用这个方法,会返回一个ResultSetMetaData对象。

查看ResultSetMetaData对象的方法。找到了一个可以获取列数量的方法。

调用此方法,获取列的数量。

有了列的数量,我们就可以遍历得到列的索引,进行循环获取每列的值。

拿到值,我们如何将值添加到对象user中去呢?
之前我们是通过set方法设置进去的,但是现在我们不知道要调用哪个set方法。

除了直接调用对象的属性set方法,我们还可以通过反射调用set方法。
首先获取User类的Class对象。

要想调用属性的set方法,需要通过Class对象拿到对应的属性对象。这个时候就需要提供属性名。
为了解决属性名的问题。我们写SQL的时候可以通过表的字段名来充当属性名。
但是大多数情况下,字段名和属性名是不一样的,这个时候我们可以给字段名起别名,这样来保持字段名和属性名一样。
这样我们只需要获取列名就可以了,竟然能够获取列的数量,肯定还可以让我们获取列名。查JDK的开发文档。
我们看到ResultMetaData对象,还提供了获取列名和列的别名方法。

由于字段名和属性名不一样时,要起别名,所以我们不能直接调用获取列名的方法,要调用获取别名的方法。这个方法说明,没有起别名就返回列名。

调用这个方法就得到了列名。

然后就可以通过反射进行调用set方法了。

查的数据可能会有多个,我们可以添加List中,返回List中的User对象。

使用完之后别忘了,结果集也需要关闭资源。


准备SQL语句,运行程序,成功查出了对象。
注意:这里的SQL语句中的字段名跟属性名不一样,需要取别名作为属性名。

上面的通用查询方法还有个缺陷,就是只能查单个表。因为方法中写死了。是创建User对象,而User对象就表示user表。

接下来我们接着优化,将这段代码如何变成动态的呢?
针对不同类的对象,我们可以使用范型来实现。
首先将方法改写成泛型方法,不同的类传入不同类的Class对象。

将集合修改为泛型集合,用来装泛型对象。去掉直接new具体的用户对象,使用class对象通过反射创建泛型对象。

调用通用查询方法,需要增加传入对应类的Class对象,获取查询数据。一个通用的查询方法就被我们封装成了。

Statement接口有SQL注入的安全问题,那么使用PreparedStatement可以解决这种注入问题嘛?
打开到Statement接口注入SQL的代码。

我们改成使用PreparedStatement接口

修改之后运行程序,无法查出数据。

这是因为创建PreparedStatement时已经提前将SQL给它了,结构已经固定下来了,不能再修改成or的关系。
使用PreparedStatement的好处,除了可以解决SQL注入的安全问题。
还可以操作blob类型的数据,这是Statement做不到的。在做批量操作时会比Statement更高效。这些下篇将为大家来讲解。

扫码进微信答疑群





