前面介绍了连接数据库的工具类,现在就可以使用这些工具类连接数据
库,并编写相应的代码进行对数据库的增删改查了。出于同样的道理,为了更方便,安全,可移植性更强。下面介绍通用的增删改查实现。增删改操作一个方法就可以实现,查询操作单独作为一个方法,是因为增删改都不返回具体的数据库里面的数据,而查询操作返回具体的数据。
预备知识
首先,我们要使用上一篇的 JDBC_Utils 工具类,以及针对数据库中的不同的表,编写对应的 javabean 类。
通用的增删改操作
// 通用的增删改
public void update(String sql, Object ...args) {// sql语句中占位符的个数等于可变形参的个数
Connection conn = null;
PreparedStatement ps = null;
try {
// 1.获取连接
conn = JDBC_Utils.getConnection();
// 2.预编译
ps = conn.prepareStatement(sql);
// 3.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i+1, args[i]);
}
// 4.执行
ps.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭资源
JDBC_Utils.closeResource(conn,ps);
}
}
复制代码
下面测试增删改操作,了解是如何使用上面的方法的。
@Test
public void testCustomUpdate(){
// 测试删除
// ?表示占位符,和prepareStatement(sql)搭配可以有效防止SQL注入,出现安全问题
// String sql = "delete from customers where id = ?";
// update(sql, 3);
// 对test数据库中的order表进行处理
String sql = "update `order` set order_name = ? where order_id = ?";
update(sql,"DD", 2);
}
复制代码
通用的查询操作
注意:本方法使用了泛型:
原因:该方法是通用的查询方法,可以对数据库中不同的表进行查询,但是方法的返回值类型不确定到底是哪种类型,因此使用泛型可以解决这个问题。
本方法还使用了反射:
原因:
在 new 一个对应的对象时对查询的数据进行封装时,不知道到底该使用哪个 javabean 类,因此,使用反射可以解决这个问题,由方法传入的第一个参数,在方法体内部可以确定该 new 哪个对象。代码中的 24 行程序就是体现。
关于别名:数据库中的表的字段不一定是和 javabean 中的类的属性完全相同,通过在 sql 语句中设置把类的属性作为字段的别名,可以避免出现查询错误。
// 该方法可以得到多条数据,所用技术包括反射,泛型
public <T> List<T> getForList(Class<T> clazz, String sql, Object ...args){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JDBC_Utils.getConnection();
ps = conn.prepareStatement(sql);
// 填充占位符,目的是把sql语句填充完毕
for (int i = 0; i < args.length; i++) {
ps.setObject(i+1, args[i]);
}
// 获取结果集
rs = ps.executeQuery();
// 获取结果集的元数据:ResultSetMetaData
ResultSetMetaData rsmd = rs.getMetaData();
// 通过ResultSetMetaData获取结果集中的列数,也就是数据库中的一条数据的字段个数
int columnCount = rsmd.getColumnCount();
// 创建集合对象
ArrayList<T> ts = new ArrayList<>();
while (rs.next()){
T t = clazz.newInstance();// 造一个对象
for (int i = 0; i < columnCount; i++) {
Object columnValue = rs.getObject(i + 1); // 得到每一个字段对应的值,注意:这里你是不知道查了几个字段,以及字段的顺序
// 获取每个列的列名(也就是字段的字段名),
//这里使用的是getColumnLabel()方法,如果sql语句给字段起了别名,返回的是别名,如果没有起别名,返回的就是真实的字段名
String columnName = rsmd.getColumnLabel(i + 1);
// 给cus对象指定的某个属性,赋值为value(给cust对象指定的columnName属性,赋值为columnValue),通过反射
Field declaredField = clazz.getDeclaredField(columnName);
declaredField.setAccessible(true);
declaredField.set(t, columnValue);
}
ts.add(t);
}
return ts;
} catch (Exception e) {
e.printStackTrace();
}
finally {
JDBC_Utils.closeResource(conn,ps,rs);
}
return null;
}
复制代码
通用查询操作测试,了解如何使用该方法
@Test
public void testGetForList(){
// 该例子没有别名,因为javabean类的属性和字段名一样,这个地方具体问题具体分析
String sql = "select id, name, email from customers where id < ?";
List<Customer> forList = getForList(Customer.class, sql, 5);
forList.forEach(System.out::println);
}
复制代码
评论