在JDBC实务中,查询操作是最复杂也是与性能连接最紧密的一环。由于查询后的结果需要输出,它和其他的操作略有不同。
现在我们开始执行JDBC的基本查询操作
一、执行查询前的准备
老规矩,在开始之前,我们思考一下执行查询需要哪些步骤?
1.创建连接
2.输入sql
3.执行sql
4.输出结果
差不多了嗯…(总觉得这个问题和把大象装进冰箱需要几个步骤一样…)
笔者把查询分为一下几个步骤
//1.定义JDBC变量
//2.创建连接
//3.定义sql
//4.预编译sql
//5.参数赋值
//6.执行sql
//7.检查是否有结果
//8.解析查询结果
其次,我们需要了解到这里使用了和“增删改”操作不同的方法和新增的接口
假设已实例化ResultSet--------->rs和PreparedStatement---------->pstm
新接口:ResultSet 结果集接口。
新方法:
pstm.executeQuery()
执行查询方法;由于我们之前执行的是数据更新语句,所以使用的一直是executeUpdate()
方法。
rs.next()
返回值为boolean,判断是否存在查询的下一行数据,如果存在, 则rs指针跳转到下一行。
rs.getString(columnIndex)
返回值为指定列的值
二、基本单行查询操作1
假设我们现在要查询一个stuid=22的学生,并将查询到结果println输出
StudentServices.java
//查询学生
public void findById1(Object id)throws Exception
{
//1.定义JDBC变量
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
try
{
//2.创建连接
conn = DBUtils.getConnection();
//3.定义sql
StringBuilder sql = new StringBuilder()
.append("SELECT A.STUID,A.SNAME,A.SDATE,A.SCORE,A.MEMO")
.append(" FROM STUDENT A")
.append(" WHERE A.STUID=?");
//4.预编译sql
pstm = conn.prepareStatement(sql.toString());
//5.参数赋值
pstm.setObject(1, id);
//6.执行sql
rs = pstm.executeQuery();
//7.检查是否有结果
if(rs.next())
{
//8.解析查询结果
System.out.println("stuid= "+rs.getString(1));
System.out.println("sname= "+rs.getString(2));
System.out.println("sdate= "+rs.getString(3));
System.out.println("score= "+rs.getString(4));
System.out.println("memo= "+rs.getString(5));
}
else
{
System.out.println("查无此人!");
}
}
finally
{
DBUtils.close(rs);
DBUtils.close(pstm);
DBUtils.close(conn);
}
}
StudentServicesTest.java
//测试查询学生方法1
public static void findStudentTest1()throws Exception
{
StudentServices services = new StudentServices();
services.findById1("22");
}
于是,我们得到输出结果
stuid= 22
sname= 葫芦娃
sdate= 1900-09-09 00:00:00
score= 0
memo= 那时还没考试
仔细观察,日期后边自动帮我们补上了00:00:00,这显然不是我们要的结果,因此可以在书写sql语句时,这样书写:
.append("SELECT A.STUID,A.SNAME,TO_CHAR('A.SDATE','YYYY-MM-DD') SDATE,A.SCORE,A.MEMO")
.append(" FROM STUDENT A")
.append(" WHERE A.STUID=?");
知识点:
JDBC三大接口的创建销毁顺序:正序创建,逆序销毁
由Connection对象编译SQL语句,生成PreparedStatement对象
由PreparedStatement对象执行SQL语句,生成ResultSet结果
实际上,这样将结果一行一行输出的方式过于笨重。在项目开发中(如网页设计),通过执行sql我们希望得到的并不是直接将其输出出来,而是一个可以二次利用(如对应到网页上的表格中)的结果集。因此我们需要一个容器来储存我们查询到的结果。
三、基本单行查询操作2
我们采用HashMap来作为我们的容器和返回值,将查询到的一条数据,封装成一个Map变量
同样的,我们想查询id为25的学生。操作2和操作1大同小异,只不过将得到的结果装载到Map并返回一个Map变量。
StudentServices.java
//查询学生方法2
public Map<String,String> findById2(Object id)throws Exception
{
//1.定义JDBC变量
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
try
{
//2.创建连接
conn = DBUtils.getConnection();
//3.定义sql
StringBuilder sql = new StringBuilder()
.append("SELECT A.STUID,A.SNAME,TO_CHAR(A.SDATE,'YYYY-MM-DD') SDATE,A.SCORE,A.MEMO")
.append(" FROM STUDENT A")
.append(" WHERE A.STUID=?");
//4.预编译sql
pstm = conn.prepareStatement(sql.toString());
//5.参数赋值
pstm.setObject(1, id);
//6.执行sql
rs = pstm.executeQuery();
//7.定义装载结果集的Map容器
Map<String,String> cup = new HashMap<>();
//8.判断是否存在查询结果
if(rs.next())
{
//9.完成列级映射
cup.put("stuid", rs.getString(1));
cup.put("sname", rs.getString(2));
cup.put("sdate", rs.getString(3));
cup.put("score", rs.getString(4));
cup.put("memo", rs.getString(5));
}
return cup;
}
finally
{
DBUtils.close(rs);
DBUtils.close(pstm);
DBUtils.close(conn);
}
}
StudentServicesTest.java
//测试学生查询方法2
public static void findStudentTest2()throws Exception
{
StudentServices services = new StudentServices();
Map<String,String> cup = services.findById2("25");
System.out.println(cup);
}
问题导出:
以上已经实现了单行查询的基本方案,但它依旧不方便于我们实际的使用:在代码中,我们需要知道每一列的名称,并将其一行一行的put到目标容器中
//9.完成列级映射
cup.put("stuid", rs.getString(1));
cup.put("sname", rs.getString(2));
cup.put("sdate", rs.getString(3));
cup.put("score", rs.getString(4));
cup.put("memo", rs.getString(5));
如果能够让程序自动识别列名,自动将数据装载到容器中导出,这样显然会让操作者省心很多!于是我们在后文将寻求新的方式,优化我们的结果集描述。
JDBC进化史(八)优化之:查询结果描述优化