目录
1. 前言
2. 准备工作
2.1 ResultSet介绍
2.2 ResultSetMetaData介绍
2.3 ORM思想
3. 增删改操作的封装
3.1 代码封装
3.2 测试
4. 查询数据的封装
5.封装工具类总结
在前一篇文章中,我们介绍了如何使用PrepareStatement来进行数据库的增删改查。但是如果不做改进的话,我们每一次进行数据库的增删改查的时候都要重写一遍之前的过程。那么有没有办法可以让我们只写一遍就可以呢?答案就是将那些公共部分封装起来,成为一个工具类,使用时只需要向其中提供必要参数即可。所以我们接下来介绍如何将数据库的增删改查操作封装到一个类中。需要注意的是,下面的内容涉及到泛型、反射,对于不熟悉的读者需要先行了解相关内容。通过这篇文章我们可以深入体会Java面向对象的思想。
在正式开始之前我们先介绍一下一些需要使用的API以及ORM思想。
ResultSet是在我们进行查询操作时,执行完sql语句后用来承接结果集的接口,通过这个接口我们才能对结果集中的数据进行读取。
ResultSet中的常用方法:
ResultSetMetaData是用来接收结果集的元数据的,比如说结果集中有多少列、每个列的列名等。只有配合ResultSetMetaData我们才能完整的实现对结果集数据的读取。
ResultSetMetaData中常用方法
ORM思想是Java面向对象的具体体现,就是将相关事物抽象成一个类,然后事物的一个实例对应一个对象。在我们这篇文章中ORM思想的具体体现如下
对于增删改来说,我们的处理结果没有返回一个结果集,所以我们不需要使用ResultSet来对其进行操作,自然而然的就和查询分开了。
我们封装过程中需要注意的是有哪些是不确定因数,确定了不确定因素后将不确定因素作为方法参数,这样在使用方法时只需要提供具体实参即可。封装步骤如下:
数据库连接是可以通过之前文章中封装的获取数据库连接的方法,其中需要提供的是一个String类型的配置文件名称,所以是String类型的形参;sql语句是String类型;占位符的个数我们不确定所以使用Object类型的可变形参。
具体封装代码如下
package uitl;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import com.mysql.cj.protocol.Resultset;
public class ConnectionUtil {
//增删改数据表
public static void CUDTable(String fileName,Connection con,String sql,Object...obj) throws Exception {
Connection connect = null;
PreparedStatement ps = null;
try {
//获取数据库连接
connect = getConnection(fileName);
//预编译sql语句
ps = connect.prepareStatement(sql);
//填充占位符
for(int i=1;i<=obj.length;i++) {
ps.setObject(i, obj[i-1]);
}
//执行sql语句
ps.execute();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}finally {
//关闭相关资源
closeConnection(connect, ps);
}
}
}
1.向test_table数据表中增加三条数据如下
user | password |
133290 | 123456 |
105651 | 133290 |
123456 | 105651 |
2.将数据修改为如下
user | password |
133290 | 133290 |
105651 | 105651 |
123456 | 123456 |
3.删除user=133290的数据
增加数据:
@Test
public void test1() {
String fileName="test.properties";
Scanner scanner=new Scanner(System.in);
//增加数据
for(int i=1;i<=3;i++) {
System.out.println("账号:");
Integer user=scanner.nextInt();
System.out.println("密码:");
Integer password=scanner.nextInt();
String sql="insert into test_table(`user`,`password`) values (?,?)";
ConnectionUtil.CURTable(fileName, sql,user,password);
}
}
运行结果
账号:
133290
密码:
123456
操作成功
账号:
105651
密码:
133290
操作成功
账号:
123456
密码:
105651
操作成功
sql查询结果
修改数据和删除数据只是sql语句改变,其他不变
由于查询在执行完sql语句后得到的是一个结果集并没有输出出来,所以我们要将结果集中的数据提取后再输出才行。对于提取数据,我们结合ResultSet和ResultSetMetaData来提取。但是对于提取出来后的承接和输出的方式却是值得我们思考的。
诚然我们可以直接将一个个数据提取出来后再拼接输出,但是Java作为面向对象语言,我们将表中的各个字段都作为类的一个属性,提取出来的数据都封装到一个对象中,这样能更好的体现面向对象的思想。所以查询的步骤如下:
package uitl;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Properties;
import com.mysql.cj.protocol.Resultset;
public class ConnectionUtil {
//查询数据表
public static ArrayList ReferTable(String fileName,Class clazz,String sql,Object...object) throws Exception {
Connection connection=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
//创建集合对象用来存储对象
ArrayList arrayList=new ArrayList();
//获取连接
connection = getConnection(fileName);
//预编译sql语句
ps = connection.prepareStatement(sql);
//填充占位符
for(int i=1;i<=object.length;i++) {
ps.setObject(i, object[i-1]);
}
//执行sql语句获取ResultSet对象
rs = ps.executeQuery();
//获取结果集的元数据
ResultSetMetaData rsmd=rs.getMetaData();
//获取列数
int column=rsmd.getColumnCount();
//读取数据构造对象
while(rs.next()) {
//创建对象
T t=clazz.newInstance();
//读取数据,并将对象的属性值修改为读取的数据
for(int i=1;i<=column;i++) {
//获取结果集中列名
String columnName=rsmd.getColumnLabel(i);
//获取结果集中列值
Object columnValue=rs.getObject(i);
//将对象中与结果集列名相对应的属性赋值为对应的值
Field field=clazz.getDeclaredField(columnName);
field.setAccessible(true);
field.set(t,columnValue);
}
//将对象添加到集合中
arrayList.add(t);
}
//返回集合值
return arrayList;
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭相关资源
closeConnection(connection, ps, rs);
}
return null;
}
}
示例
查询test_table中账号为133290和105651的数据
查询数据
package curd;
public class Test_Table {
int identification;
int cipher;
@Override
public String toString() {
return "identification=" + identification + ", cipher=" + cipher;
}
public int getIdentification() {
return identification;
}
public void setIdentification(int identification) {
this.identification = identification;
}
public int getCipher() {
return cipher;
}
public void setCipher(int cipher) {
this.cipher = cipher;
}
}
@Test
public void test4() throws Exception {
//查询数据
/*获取配置文件名*/
String fileName="test.properties";
/*查询语句*/
String sql="select `user` as identification,`password` as cipher from test_table where `user`=? or `user`=?";
Scanner scanner=new Scanner(System.in);
/*占位符*/
Integer user1=133290;
Integer user2=123456;
ArrayList list= ConnectionUtil.ReferTable(fileName, Test_Table.class, sql, user1,user2);
System.out.println(list);
}
查询结果如下
[identification=123456, cipher=123456, identification=133290, cipher=133290]
最终完成的JDBC工具类包括如下功能:通过输入配置文件名获取数据库连接、关闭数据库连接、提供相应的条件完成增删改查。总的工具类代码如下,建议保存起来,下次可以直接使用,省去很多麻烦。
不能用占位符代替表名!!!!!!!!(博主已经吃过亏了)