Java开发笔记(一百四十八)通过JDBC查询数据记录
前面介绍了通过JDBC如何管理数据库,当时提到Statement专门提供了executeQuery方法用于查询操作,为什么查询操作这么特殊呢?这是因为其它语句跑完一次就了事了,顶多像insert、update、delete再返回受影响的记录数量,但select命令跟它们不一样,查询语句可能会返回多条记录,每条记录又包含多个字段。似此多条记录多个字段的情景,返回值无论定义为哪种类型都不太好办,故而干脆给个单独的executeQuery方法,该方法的返回值也设置成专属的ResultSet类型,表示查询方法返回了一个结果集,详细的记录结果请到结果集中遍历获得。
据此可将记录查询的操作过程分成以下四个步骤:
1、获取数据库连接:该步骤调用DriverManager类的getConnection方法获得连接对象。
2、创建该连接的执行报告:该步骤调用Connection对象的createStatement方法获得执行报告。
3、命令报告执行查询语句:该步骤调用报告对象的executeQuery方法来执行查询语句,并返回查询记录的结果集。
4、循环遍历结果集里面的所有记录:通常该步骤需调用结果集对象的next方法不断往后遍历,也就是将结果集的指示游标一步一步向后移动。在遍历过程当中,可能要调用结果集对象的其它方法进一步操作,ResultSet的常见方法分成三类,说明如下:
1、移动游标
该类方法可将当前游标移动到指定位置,主要包括下列方法:
next:将游标移到后一条记录。该方法返回true表示尚未移到末尾,返回false表示已经移到末尾。
absolute:将游标移到第几条记录,如果参数为负数则表示倒数的第几条。
first:将游标移到第一条记录。
last:将游标移到最后一条记录。
previous:将游标移到前一条记录。
beforeFirst:将游标移到第一条记录之前。
afterLast:将游标移到最后一条记录之后。
2、判断游标位置
该类方法可判断当前游标是否处于某个位置,主要包括下列方法:
isFirst:游标是否指向第一条记录。
isLast:游标是否指向最后一条记录。
isBeforeFirst:游标是否在第一条记录之前。
isAfterLast:游标是否在最后一条记录之后。
3、从当前游标获取数据
该类方法可从当前游标指向的记录中获取字段值,当方法参数为整型时,表示获取指定序号的字段值;当方法参数为字符串时,表示获取指定名称的字段值。相关的获取方法罗列如下:
getInt:获取指定序号或者指定名称的字段整型值。
getLong:获取指定序号或者指定名称的字段长整值。
getFloat:获取指定序号或者指定名称的字段浮点值。
getDouble:获取指定序号或者指定名称的字段双精度值。
getString:获取指定序号或者指定名称的字段字符串值。
getDate:获取指定序号或者指定名称的字段日期值。
接下来举几个具体应用的例子,首先要从teacher表中查询所有记录,则依次连接数据库、创建连接的报告、执行查询语句,再循环遍历结果集获取每条记录的字段信息。这一连串的查询代码示例如下:
// 查询所有记录(默认排序)
private static void showAllRecord() {
String sql = "select * from teacher";
// 连接数据库、创建连接的报告、执行查询语句
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) { // 循环遍历结果集里面的所有记录
int gonghao = rs.getInt("gonghao"); // 获取指定字段的整型值
String name = rs.getString("name"); // 获取指定字段的字符串值
Date birthday = rs.getDate("birthday"); // 获取指定字段的日期值
int sex = rs.getInt("sex"); // 获取指定字段的整型值
String course = rs.getString("course"); // 获取指定字段的字符串值
String desc = String.format("工号为%d,姓名为%s,出生日期为%s,性别为%s,任教课程为%s。",
gonghao, name, getFormatDate(birthday), sex==0 ? "男性" : "女性", course);
System.out.println("当前教师信息为:"+desc);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
注意MySQL未提供将日期转成字符串的to_char函数,因而只能先取到Date类型的字段值,再将其通过Java代码转为字符串。日期类型转换为字符串类型的方法代码如下所示:
// 获取指定格式的日期字符串
public static String getFormatDate(Date date) {
// 创建一个日期格式化的工具
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 将当前日期时间按照指定格式输出格式化后的日期时间字符串
return sdf.format(date);
}
接着运行上面的查询方法showAllRecord,观察到日志窗口完整输出了如下的五条记录信息。
当前教师信息为:工号为1,姓名为张老师,出生日期为1983-03-03,性别为女性,任教课程为语文。
当前教师信息为:工号为2,姓名为李老师,出生日期为1984-04-04,性别为男性,任教课程为数学。
当前教师信息为:工号为3,姓名为王老师,出生日期为1985-05-05,性别为女性,任教课程为英语。
当前教师信息为:工号为4,姓名为赵老师,出生日期为1986-06-06,性别为男性,任教课程为物理。
当前教师信息为:工号为5,姓名为刘老师,出生日期为1987-07-07,性别为女性,任教课程为化学。
然后在原语句增加排序条件,让所有记录按照生日字段降序排列,则修改后的查询代码如下所示:
// 查询所有记录(按照生日倒序)
private static void showAllRecordByBirthday() {
String sql = "select * from teacher order by birthday desc";
// 连接数据库、创建连接的报告、执行查询语句
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) { // 循环遍历结果集里面的所有记录
int gonghao = rs.getInt("gonghao"); // 获取指定字段的整型值
String name = rs.getString("name"); // 获取指定字段的字符串值
Date birthday = rs.getDate("birthday"); // 获取指定字段的日期值
int sex = rs.getInt("sex"); // 获取指定字段的整型值
String course = rs.getString("course"); // 获取指定字段的字符串值
String desc = String.format("工号为%d,姓名为%s,出生日期为%s,性别为%s,任教课程为%s。",
gonghao, name, getFormatDate(birthday), sex==0 ? "男性" : "女性", course);
System.out.println("当前教师信息为:"+desc);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
增加了showAllRecordByBirthday方法之后,再次运行测试程序,从日志窗口可见这次的记录结果以生日字段降序显示了。
当前教师信息为:工号为5,姓名为刘老师,出生日期为1987-07-07,性别为女性,任教课程为化学。
当前教师信息为:工号为4,姓名为赵老师,出生日期为1986-06-06,性别为男性,任教课程为物理。
当前教师信息为:工号为3,姓名为王老师,出生日期为1985-05-05,性别为女性,任教课程为英语。
当前教师信息为:工号为2,姓名为李老师,出生日期为1984-04-04,性别为男性,任教课程为数学。
当前教师信息为:工号为1,姓名为张老师,出生日期为1983-03-03,性别为女性,任教课程为语文。
排序条件仅仅调整返回记录的顺序,然而分组条件就不一样了。因为分组条件存在统计操作,像count、sum、max这些函数只返回运算结果,但从结果集中取数据有赖于字段名称,所以需要在统计函数之后加个别名,相当于该函数的运算结果暂存于该别名变量。比如表达式“count(sex) count”说的就是计数结果以count命名,游标从count字段获取到的即为计数值。下面是对teacher表按照性别字段分组统计的查询代码例子:
// 查询性别分组。注意要给count之类的函数结果分配别名
private static void showRecordGroupBySex() {
String sql = "select sex,count(sex) count from teacher group by sex order by sex asc";
// 连接数据库、创建连接的报告、执行查询语句
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) { // 循环遍历结果集里面的所有记录
int sex = rs.getInt("sex"); // 获取指定字段的整型值
int count = rs.getInt("count"); // 获取指定字段的整型值
String desc = String.format("%s老师有%d位;", sex==0 ? "男" : "女", count);
System.out.print(desc);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
运行包含showRecordGroupBySex方法的测试程序,果然正确输出了预期的统计日志如下所示。
男老师有2位;女老师有3位;
更多Java技术文章参见《Java开发笔记(序)章节目录》
Java开发笔记(一百四十八)通过JDBC查询数据记录的更多相关文章
- Java开发笔记(三十八)利用正则表达式校验字符串
前面多次提到了正则串.正则表达式,那么正则表达式究竟是符合什么定义的字符串呢?正则表达式是编程语言处理字符串格式的一种逻辑式子,它利用若干保留字符定义了形形色色的匹配规则,从而通过一个式子来覆盖满足了 ...
- Java开发笔记(二十八)布尔包装类型
前面介绍了数值包装类型,因为不管是整数还是小数,它们的运算操作都是类似的,所以只要学会了Integer的用法,其它数值包装类型即可一并掌握.但是对于布尔类型boolean来说,该类型定义的是“true ...
- Java开发笔记(四十八)类的简单继承
前面介绍了类的基本用法,主要是如何封装一个类的各项要素,包括成员属性.成员方法.构造方法等,想必大家对类的简单运用早已驾轻就熟.所谓“物以类聚,人以群分”,之所以某些事物会聚在一起,乃是因为它们拥有类 ...
- Java开发笔记(五十八)简单接口及其实现
前面介绍了抽象方法及抽象类的用法,看似解决了不确定行为的方法定义,既然叫唤动作允许声明为抽象方法,那么飞翔.游泳也能声明为抽象方法,并且鸡类涵盖的物种不够多,最好把这些行为动作扩展到鸟类这个群体,于是 ...
- Java开发笔记(六十八)从泛型方法探究泛型的起源
前面介绍各种容器之时,通过在容器名称后面添加包裹数据类型的一对尖括号,表示该容器存放的是哪种类型的元素.这样一来总算把Java当中的各类括号都凑齐了,例如包裹一段代码的花括号.指定数组元素下标的方括号 ...
- Java开发笔记(七十八)面向对象的后门——反射
作为一门面向对象的编程语言,Java认为一切皆是对象,每个对象都能归属于某个类,甚至每个类均可提取出一种特殊的类型,即Class类型.早在前面介绍多态的时候,就提到每个类都存在独一无二的基因,通过比较 ...
- Java开发笔记(四十)日期与字符串的互相转换
前面介绍了如何通过Date工具获取各个时间数值,但是用户更喜欢形如“2018-11-24 23:04:18”这种结构清晰.简洁明了的字符串,而非啰里八唆依次汇报每个时间单位及其数值的描述.既然日期时间 ...
- Java开发笔记(二十九)大整数BigInteger
早期的编程语言为了节约计算机的内存,给数字变量定义了各种存储规格的数值类型,比如字节型byte只占用一个字节大小,短整型short占用两个字节大小,整型int占用四个字节大小,长整型long占用八个字 ...
- Java开发笔记(三十二)字符型与整型相互转化
前面提到字符类型是一种新的变量类型,然而编码实践的过程中却发现,某个具体的字符值居然可以赋值给整型变量!就像下面的例子代码那样,把字符值赋给整型变量,编译器不但没报错,而且还能正常运行! // 字符允 ...
随机推荐
- Android根据加速度和地磁场传感器实现自动对焦
在相机预览开始后新建AutoFocusManage对象即可,传入context和camera. 注意,在停止预览或者关闭相机时需调用方法中unregisterListener方法. 目前实现是当前方向 ...
- 在UE4C++中的宏
1. UE4蓝图的宏 在蓝图中,我们可以把一堆经常使用的节点封装为一个宏,然后通过多次使用这个宏,达到了减少重复代码量的效果. 如图: 2. UE4C++中的宏 那么,在UE4的C++中怎么实现宏呢? ...
- 基于centos搭建微信小程序服务,配置及数据库等
基于centos搭建小程序, ps:请提前20天准备将域名备案,申请ssl证书 实验上机地址:https://cloud.tencent.com/developer/labs/lab/10004 准备 ...
- WAMP完整配置教程(启用php extensions、修改端口、允许外网访问、wamp绑定域名)。
作为一名php爱好者,很希望自己的写的代码能够快速的在浏览器页面展现出来,wamp是一款集成很完善.很方便的软件,我刚开始研究的时候,会因为对于wamp的不熟悉,导致修改一点点配置就会在百度查好久,这 ...
- Cesium中的几种坐标和相互转换【转】
几个重要的坐标对象:1.世界坐标 Cartesian3:笛卡尔空间直角坐标系 new Cesium.Cartesian3(x, y, z) 可以看作,以椭球中心为原点的空间直角坐标系中的一个点的坐标. ...
- Windows系统中CreateFileMapping实现的共享内存及用法
在32位的Windows系统中,每一个进程都有权访问他自己的4GB(232=4294967296)平面地址空间,没有段,没有选择符,没有near和far指针,没有near和far函数调用,也没有内存模 ...
- sql server数据库备份单个表的结构和数据生成脚本【转】
1.使用场景:sql server数据库备份单个表的结构和数据,在我们要修改正式系统的数据的一天或者多条某些数据时候,要执行update语句操作,安全稳健考虑,最好先做好所修改的表的结构和数据备份! ...
- 【深入学习linux】CentOS 7 最小化安装后的注意事项及一些必备组件的安装
转载:https://blog.csdn.net/F_Srion/article/details/54910943 在VM虚拟机中安装CentOS 7 时 有时候顾虑到电脑硬件性能,我们需要最小化安装 ...
- Python之多态案例
class Canvas: def draw_pic(self, shape): print('--start draw--') shape.draw(self) class Rectangle: d ...
- 理解 uptime 的:“平均负载”? 如何模拟测试
每次发现系统变慢时,我们通常做的第一件事,就是执行 top 或者 uptime 命令,来了解系统的负载情况.比如像下面这样,我在命令行里输入了 uptime 命令,系统也随即给出了结果. [root@ ...