在进行增删改操作时,不需要返回值或返回值仅仅作为操作成功与否的标志,三者可以一同实现;而在进行查操作时,需要返回查询表的内容,因此将其单独实现。
实现增删改操作
public class Function{
public void update(String sql,Object...args){
Connection connection = null;
PreparedStatement ps = null;
try{
//利用先前封装好的JDBCUtils类建立连接
connection = JDBCUtils.getConnection();
//预编译sql语句
ps = connection.preparedStatement(sql);
//填充占位符
for(int i = 0; i<args.length; i++){
ps.setObject(i+1,args[i]);
}
//执行操作
ps.execute();
} catch (Exception e){
e.printStackTrace();
} finally {
JDBCUtils.close(connection, ps);//提前在JDBCUtils中封装好
}
}
}
总体来说增删改操作比较容易实现,需要注意的是之所以使用PreparedStatement而非Statement,因为Statement不能防止“注入”问题,不安全。
实现查操作
首先明确一点,对于查询到的表内容需要以什么样的形式保存起来,推荐使用创建相应类的对象来存储信息。例如对表customers进行查询操作,就根据表中列的名称和数据类型创建对应的JavaBean。
对特定表(customers)进行查操作
↓TABLE customers中包含的属性


注意一下因为sql和Java命名习惯不太一样,Java中的属性不再使用下划线,后面会针对这个改变进一步说明。
public List<Customer> select(String sql, Object...args) {
Connection connection = null;
PreparedStatement ps = null;
ResultSet rs = null;
//创建容器储存Customer对象
List<Customer> customers = new ArrayList<>();
try {
//建立连接
connection = JDBCUtils.getConnection();
//预编译sql语句
ps = connection.prepareStatement(sql);
//填充占位符
for(int i=0;i<args.length;i++) {
ps.setObject(i+1, args[i]);
}
//执行操作并获得结果集
rs = ps.executeQuery();
//获得结果集元数据
ResultSetMetaData rsmd = rs.getMetaData();
//获得TABLE customers的列数
int columnCount = rsmd.getColumnCount();
while(rs.next()) {
//创建对象,用于保存查询到的数据
Customer cust = new Customer();
for(int i=0;i<columnCount;i++) {
//利用结果集元数据获取属性名
String columnName = rsmd.getColumnLabel(i+1);
//利用结果集获取属性值
Object columnValue = rs.getObject(i+1);
//利用反射将获取的属性值赋给对应的属性
Field field = Customer.class.getDeclaredField(columnName);
field.setAccessible(true);
field.set(cust, columnValue);
}
//添加对象到容器中
customers.add(cust);
}
return customers;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(connection, ps, rs);
}
return null;
}
因为结果集中没有获取属性名和属性数的方法,必须使用结果集元数据才能获得。
针对之前提到的注意到sql和Java属性命名不一致的问题,在利用结果集元数据获取属性名时String columnName = rsmd.getColumnLabel(i+1);使用的是getColumnLabel()方法,这里意味着获取属性标签,即在sql语句中设置的标签名,标签名要与Java类中属性名一致。在sql语句中select cust_name custName, cust_address custAddress from customers通过标签把sql与Java属性名对应起来。如果这里使用getColumnName()方法,返回的就是数据库的属性名,就不能在Java类中找到对应的属性,出错。另外,如果没有设置标签名,那么getColumnLabel()默认与getColumnName()一致。
建议使用
getColumnLabel()
对任意表进行查操作
操作前需要对不同的表创建对应的类,与特定表操作区别不大,在输入时需要增加操作表对应的类Class<T> clz,把对特定类Customer的操作用泛型T替代,即可。
public <T> List<T> select(Class<T> clz, String sql, Object...args) {
Connection connection = JDBCUtils.getConnection();
PreparedStatement ps = null;
ResultSet rs = null;
List<T> customers = new ArrayList<>();
try {
ps = connection.prepareStatement(sql);
for(int i=0;i<args.length;i++) {
ps.setObject(i+1, args[i]);
}
rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
while(rs.next()) {
T t = clz.getConstructor().newInstance();
for(int i=0;i<columnCount;i++) {
String columnName = rsmd.getColumnLabel(i+1);
Object columnValue = rs.getObject(i+1);
Field field = clz.getDeclaredField(columnName);
field.setAccessible(true);
field.set(t, columnValue);
}
customers.add(t);
}
return customers;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(connection, ps, rs);
}
return null;
}