JDBC规范五-ResultSet详解 jdbc resultset fetchsize
yuyutoo 2024-10-12 00:49 11 浏览 0 评论
ResultSet接口是JDBC API中另一个比较重要的组件,提供了检索和操作SQL执行结果相关的方法。
1.ResultSet类型
ResultSet对象的类型主要体现在两个方面:
(1)游标可操作的方式。(2)ResultSet对象的修改对数据库的影响。
后者称为ResultSet对象的敏感性。ResultSet有3种不同的类型,分别说明如下。
(1)TYPE_FORWARD_ONLY
这种类型的ResultSet不可滚动,游标只能向前移动,从第一行到最后一行,不允许向后移动,即只能使用ResultSet接口的next()方法,而不能使用previous()方法,否则会产生错误。
(2)TYPE_SCROLL_INSENSITIVE这种类型的ResultSet是可滚动的,它的游标可以相对于当前位置向前或向后移动,也可以移动到绝对位置。当ResultSet没有关闭时,ResultSet的修改对数据库不敏感,也就是说对ResultSet对象的修改不会影响对应的数据库中的记录。
(3)TYPE_SCROLL_SENSITIVE这种类型的ResultSet是可滚动的,它的游标可以相对于当前位置向前或向后移动,也可以移动到绝对位置。当ResultSet没有关闭时,对ResultSet对象的修改会直接影响数据库中的记录。
默认情况下,ResultSet的类型为TYPE_FORWARD_ONLY。DatabaseMetaData接口中提供了一个supportsResultSetType()方法,用于判断数据库驱动是否支持某种类型的ResultSet对象,如果支持,则返回true,否则返回false。如果JDBC驱动不支持某一类型的ResultSet对象,在调用Connection对象的createStatement()、prepareStatement()或prepareCall()方法指定创建该类型的ResultSet对象时,会在Connection对象中产生一个SQLWarning对象,当Statement对象执行时,产生的ResultSet对象可以通过ResultSet对象的getType()方法确定它的类型。
2.ResultSet并行性
ResultSet对象的并行性决定了它支持更新的级别,目前JDBC中支持两个级别,分别如下:
CONCUR_READ_ONLY:为ResultSet对象设置这种属性后,只能从ResulSet对象中读取数据,但是不能更新ResultSet对象中的数据。
CONCUR_UPDATABLE:该属性表明,既可以从ResulSet对象中读取数据,又能更新ResultSet中的数据。
ResultSet对象默认并行性为CONCUR_READ_ONLY。DatabaseMetaData接口中提供了一个supportsResultSetConcurrency()方法,用于判断JDBC驱动是否支持某一级别的并行性,如果支持就返回true,否则返回false。
如果JDBC不支持某一级别的并行性,则调用createStatement()、prepareStatement()或prepareCall()方法指定该级别时会在Connection对象中产生一个SQLWarning对象。在应用程序中,可以调用ResultSet对象的getConcurrency()方法获取ResultSet的并行性级别。
3.ResultSet可保持性
调用Connection对象的commit()方法能够关闭当前事务中创建的ResultSet对象。然而,在某些情况下,这可能不是我们期望的行为。ResultSet对象的holdability属性使得应用程序能够在Connection对象的commit()方法调用后控制ResultSet对象是否关闭。
下面两个常量用于在调用Connection对象的createStatement()、prepareStatement()或prepareCall()方法时指定ResultSet对象的可保持性。
HOLD_CURSORS_OVER_COMMIT:当调用Connection对象的commit()方法时,不关闭当前事务创建的ResultSet对象。
CLOSE_CURSORS_AT_COMMIT:当前事务创建的ResultSet对象在事务提交后会被关闭,对一些应用程序来说,这样能够提升系统性能。
ResultSet对象的默认可保持性取决于具体的驱动实现,DatabaseMetaData接口中提供了getResultSetHoldability()方法用于获取JDBC驱动的默认可保持性。如果JDBC驱动不支持某一级别的可保持性,则调用createStatement()、prepareStatement()或prepareCall()方法指定该级别时,会在Connection对象中产生一个SQLWarning对象,应用程序可以调用ResultSet对象的getHoldability()方法获取ResultSet的可保持性。
4.ResultSet属性设置
ResultSet的类型、并行性和可保持性等属性可以在调用Connection对象的createStatement()、prepareStatement()或prepareCall()方法创建Statement对象时设置,例如:
Connection conn = ds.getConnection(user, passwd);
Statement stmt = conn.createStatement(
ResultSet.TYPE SCROLL INSENSITIVE,ResultSet.CONCUR READ ONLY,ResultSet.CLOSE CURSORS AT COMMIT);
上面的代码中,创建Statement对象时,指定ResultSet对象可以滚动,ResultSet中的数据不可以修改,而且在调用Connection对象的commit()方法提交事务时当前事务创建的ResultSet对象自动关闭。Statement、PreparedStatement和CallableStatement接口中为这些属性提供了Getter方法,用于获取ResultSet的类型、并行性及可保持性等属性。
5.ResultSet游标移动
ResultSet对象中维护了一个游标,游标指向当前数据行。当ResultSet对象第一次创建时,游标指向数据的第一行。ResultSet接口中提供了一系列的方法,用于操作ResultSet对象中的游标,这些方法的作用如下。
next():游标向前移动一行,如果游标定位到下一行,则返回true;如果游标位于最后一行之后,则返回false。previous():游标向后移动一行,如果游标定位到上一行,则返回true;如果游标位于第一行之前,则返回false。first():游标移动到第一行,如果游标定位到第一行,则返回true;如果ResultSet对象中一行数据都没有,则返回false。
last():移动游标到最后一行,如果游标定位到最后一行,则返回true;如果ResultSet不包含任何数据行,则返回false。
beforeFirst():移动游标到ResultSet对象的第一行之前,如果ResultSet对象不包含任何数据行,则该方法不生效。
afterLast():游标位置移动到ResultSet对象最后一行之后,如果ResultSet对象中不包含任何行,则该方法不生效。
relative(int rows):相对于当前位置移动游标,如果参数rows为0,则游标不会移动。如果rows为正数,则游标向前移动指定的行数,如果rows大于当前位置到最后一行的偏移量,则游标移动到最后一行之后。如果rows为负数,则游标向后移动,如果rows大于当前位置到第一行的偏移量,则游标移动到第一行之前的位置。当游标正确定位到某一行时,该方法返回true,否则返回false。如果参数rows值为1,则该方法的效果和next()方法相同;如果rows参数为-1,则该方法的效果和previous()方法相同。
absolute(int row):游标定位到ResultSet对象中的第row行。如果row为正数,则游标移动到ResultSet对象的第row行。需要注意的是,这里行的序数从1开始。如果参数row大于ResultSet对象中的最大行数,则游标移动到最后一行之后。如果参数row为负数,游标从行尾开始移动。例如,row值为-1时,游标移动到最后一行;为-2时,游标移动到倒数第二行;如果row的绝对值大于最大行,则游标移动到第一行之前。
当ResultSet对象的类型为TYPE_FORWARD_ONLY时,游标只能向前移动,调用其他方法操作游标向后移动时将会抛出SQLException异常。
6.修改ResultSet对象
并行性为CONCUR_UPDATABLE的ResultSet对象可以使用ResultSet接口中提供的方法对其进行更新,包括更新行、删除行,在JDBC驱动支持的情况下,还可以插入新的行。
接下来我们就来了解一下如何使用ResultSet接口中提供的方法修改ResultSet对象。
首先来看一下如何更新ResultSet记录中的某一行,更新ResultSet对象中的某一行是一个两阶段的过程。首先需要为某一行的每个字段设置新的值,然后更新修改到具体的行。第一阶段完成后,底层数据库数据不会更新,第二阶段会把ResultSet对象的修改同步到数据库。ResultSet接口针对所有JDBC类型,提供了两个更新方法,其中一个方法需要指定更新列的序数,另一个方法需要指定列的名称(大小写不敏感)。如果在并行性级别为ResultSet.CONCUR_READ_ONLY的ResultSet对象上调用更新方法,将会抛出SQLException异常。ResultSet对象的updateRow()方法用于将所有列的修改应用到当前行,并清除先前更新方法所做更改的记录。
public void testJdbc() {
// 初始化数据
DbUtils.initData();
try {
// 加载驱动
Class.forName("org.hsqldb.jdbcDriver");
// 获取Connection对象
Connection connection = DriverManager.getConnection("jdbc:hsqldb:mem:mybatis",
"sa", "");
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet resultSet = statement.executeQuery("select * from user limit 2");
// 遍历ResultSet
ResultSetMetaData metaData = resultSet.getMetaData();
int columCount = metaData.getColumnCount();
while (resultSet.next()) {
for (int i = 1; i <= columCount; i++) {
String columName = metaData.getColumnName(i);
String columVal = resultSet.getString(columName);
System.out.println(columName + ":" + columVal);
}
System.out.println("--------------------------------------");
}
// hsqldb 不支持
// 换成mysql
System.out.println(connection.getMetaData().supportsResultSetType(ResultSet.CONCUR_UPDATABLE));
resultSet.first();
resultSet.updateString("NICK_NAME", "xuxu");
resultSet.updateRow();
System.out.println(resultSet.isClosed());
// 遍历ResultSet
ResultSet resultSet2 = statement.executeQuery("select * from rr_banner_bannermodel limit 1");
ResultSetMetaData metaData2 = resultSet2.getMetaData();
while (resultSet2.next()) {
for (int i = 1; i <= columCount; i++) {
String columName = metaData2.getColumnName(i);
String columVal = resultSet2.getString(columName);
System.out.println(columName + ":" + columVal);
}
System.out.println("--------------------------------------");
}
// 关闭连接
IOUtils.closeQuietly(statement);
IOUtils.closeQuietly(connection);
} catch (Exception e) {
e.printStackTrace();
}
}
上面用的是hsqldb 驱动,hsqldb 驱动不支持CONCUR_READ_ONLY ,可以更新到mysql的驱动,这里只作为一个实例看看。
如上面的代码所示,执行查询SQL生成ResultSet对象后,调用next()方法将游标定位到第一行,然后调用updateString()方法更新第一行的nick_name字段,接着调用ResultSet的updateRow()方法将ResultSet对象的修改应用到数据库
DatabaseMetaData接口中的ownUpdatesAreVisible(int type)方法用于判断指定类型的ResultSet对象的更新是否对当前事务可见,如果可见,就返回true,否则返回false。DatabaseMetaData接口的othersUpdatesAreVisible(int type)方法用于判断指定类型的ResultSet对象的更新是否对其他事务可见,如果可见,就返回true,否则返回false。ResultSet对象可以调用rowUpdated()方法来判断是否调用了updateRow()方法确认更新。对于任何给定的ResultSet,应用程序不应该在调用updateXXX()方法之后以及在调用后续的updateRow()或cancelRowUpdates()方法之前修改通过updateXXX()方法设置的参数值,否则可能会产生不可预期的效果。
接下来了解如何删除ResultSet对象中的某一行。ResultSet对象中的行可以调用deleteRow()方法进行删除,例如:
rs.absolute(4)
rs.deleteRow
将ResultSet对象的游标定位到某一行后,调用deleteRow()方法会删除数据库中对应的行。这种删除对于一个打开的ResultSet对象是可见的,它会反映到ResultSet对象的变化—ResultSet对象会移除对应的行,或者把对应的行设置为空或无效行。若如此,则调用DatabaseMetaData对象的ownDeletesAreVisible(int type)方法将返回true。如果调用deleteRow()方法删除行后ResultSet对象中仍然包含该行,那么调用DatabaseMetaData对象的ownDeletesAreVisible(int type)方法将返回false,意味着数据删除对当前ResultSet对象不可见。
DatabaseMetaData对象的othersDeletesAreVisible(int type)方法用于判断数据行的删除对其他事务中的ResultSet对象是否可见,如果返回值为true,就表明当前ResultSet行的删除对其他事务中的ResultSet对象是可见的,否则返回false。当前行被删除后,如果ResultSet对象能够检测到行被删除,那么ResultSet对象的rowDeleted()方法会返回true,否则返回false。
最后,我们来了解一下如何向ResultSet对象中插入行。在JDBC驱动支持的情况下,可以调用ResultSet接口提供的方法向ResultSet对象中插入行。如果JDBC驱动不支持向ResultSet对象中插入行,就会抛出SQLFeatureNotSupportedException异常。
ResultSet对象中插入行需要以下几步:
(1)移动游标到待插入的位置。
(2)调用ResultSet接口提供的updateXXX()方法为每一个字段设置值。
(3)插入行到当前ResultSet对象中。
代码如下:
ResultSet rs = stmt.executeQuery("select author, title, isbn"from booklist");
rs.moveToInsertRow();
//为每列设置值
rs.updateString(1,"Huxley, Aldous");
rs.updateString(2,"Doors of Perception and Heaven and Hell");
rs.updateLong(3,60900075);
插入行
rs.insertRow();
//移动游标到插入前的行
rs.moveToCurrentRow();
需要注意的是,插入行中的每一个字段不允许为null,必须使用合适的updateXXX()方法指定一个确定的值。如果updateXXX()方法指定的值与数据库字段类型不匹配,那么调用insertRow()方法会抛出SQLException异常。如果新插入的行对ResultSet对象可见,那么调用DatabaseMetaData对象的ownInsertsAreVisible(int type)方法是返回true,否则返回false。如果新插入的行对其他事务中的ResultSet对象可见,则调用DatabaseMetaData对象的othersInsertsAreVisible(int type)方法返回true。如果ResultSet对象能够识别新插入的行,那么调用DatabaseMetaData对象的insertsAreDetected(int type)方法将会返回true,意味着插入行对ResultSet对象可见。
对于一个给定的ResultSet对象,调用updateXXX()方法为每一个字段设置值后,在insertRow()方法调用前,应用程序不可以修改参数值,否则可能产生不可预料的结果。
7.关闭ResultSet对象
ResultSet对象在下面两种情况下会显式地关闭:
(1)调用ResultSet对象的close()方法。
(2)创建ResultSet对象的Statement或者Connection对象被显式地关闭。
在下面两种情况下ResultSet对象会被隐式地关闭:
(1)相关联的Statement对象重复执行时。
(2)可保持性为CLOSE_CURSORS_AT_COMMIT的ResultSet对象在当前事务提交后会被关闭。
注意一些JDBC驱动实现,当ResultSet类型为TYPE_FORWARD_ONLY并且next()方法返回false时,也会隐式地关闭ResultSet对象。一旦ResultSet对象被关闭,调用除isClosed()和close()之外的方法就会抛出SQLException异常,但是通过ResultSet创建的ResultSetMetaData实例仍然可以访问。
ResultSet对象关闭后,不会关闭由ResultSet对象创建的Blob、Clob、NClob或SQLXML对象,除非调用这些对象的free()方法。
相关推荐
- 深度解读Spring框架的核心原理
-
深度解读Spring框架的核心原理在Java开发的世界里,提到Spring框架,就像提起一位久经沙场的老将,它几乎成了企业级应用开发的代名词。那么,这个被无数开发者膜拜的框架究竟有何独特之处?今天,我...
- 「Spring认证」Spring 框架概述
-
Spring是最流行的企业Java应用程序开发框架。全球数以百万计的开发人员使用SpringFramework来创建高性能、易于测试和可重用的代码。Spring框架是一个开源的Java...
- 学习Spring框架 这一篇就够了
-
1.spring概述1.1Spring是什么(理解)...
- Spring框架双核解析:IOC与AOP的本质与实战
-
#Spring核心#IOC容器#AOP编程#Java框架设计...
- Spring Boot与传统Spring框架的对比:探索Java开发的新境界
-
SpringBoot与传统Spring框架的对比:探索Java开发的新境界在Java生态系统中,Spring框架无疑是一个里程碑式的存在。从最初的简单依赖注入容器,到如今覆盖企业级开发方方面面的庞大...
- Spring MVC框架源码深度剖析:从入门到精通
-
SpringMVC框架源码深度剖析:从入门到精通SpringMVC框架简介SpringMVC作为Spring框架的一部分,为构建Web应用程序提供了强大且灵活的支持。它遵循MVC(Model-V...
- Spring框架入门
-
一.spring是什么?Spring是分层...
- 程序员必知必会技能之Spring框架基础——面向切面编程!
-
面向切面编程AOP(AspectOrientedProgramming)与OOP(ObjectOrientedProgramming,面向对象编程)相辅相成。AOP提供了与OOP不同的抽象软件结...
- Spring Security安全框架深度解读:为你的应用穿上“钢铁铠甲”
-
SpringSecurity安全框架深度解读:为你的应用穿上“钢铁铠甲”在现代网络世界里,保护我们的应用程序免受各种威胁攻击至关重要。而在这个过程中,SpringSecurity框架无疑是我们最可...
- Spring框架的设计哲学与实现:打造轻量级的企业级Java应用
-
Spring框架的设计哲学与实现:打造轻量级的企业级Java应用Spring框架自2003年诞生以来,已成为企业级Java应用开发的代名词。它不仅仅是一个框架,更是一种设计理念和哲学的体现。本文将带你...
- Spring框架深度解析:从核心原理到底层实现的全方位避坑指南
-
一、Spring框架核心概念解析1.控制反转(IoC)与依赖注入(DI)Spring的核心思想是通过IoC容器管理对象的生命周期和依赖关系。传统开发中,对象通过new主动创建依赖对象,导致高耦合;而S...
- Java框架 —— Spring简介
-
简介一般来说,Spring指的是SpringFramework,它提供了很多功能,例如:控制反转(IOC)、依赖注入...
- Spring 框架概述,模块划分
-
Spring框架以控制反转(InversionofControl,IoC)和面向切面编程(Aspect-OrientedProgramming,AOP)为核心,旨在简化企业级应用开发,使开发者...
- spring框架怎么实现依赖注入?
-
依赖注入的作用就是在使用Spring框架创建对象时,动态的将其所依赖的对象注入到Bean组件中,其实现方式通常有两种,一种是属性setter方法注入,另一种是构造方法注入。具体介绍如下:●属性set...
- Spring框架详解
-
Spring是一种开放源码框架,旨在解决企业应用程序开发的复杂性。一个主要优点就是它的分层体系结构,层次结构让你可以选择要用的组件,同时也为J2EE应用程序开发提供了集成框架。 Spring特征...
你 发表评论:
欢迎- 一周热门
-
-
前端面试:iframe 的优缺点? iframe有那些缺点
-
带斜线的表头制作好了,如何填充内容?这几种方法你更喜欢哪个?
-
漫学笔记之PHP.ini常用的配置信息
-
推荐7个模板代码和其他游戏源码下载的网址
-
其实模版网站在开发工作中很重要,推荐几个参考站给大家
-
[干货] JAVA - JVM - 2 内存两分 [干货]+java+-+jvm+-+2+内存两分吗
-
正在学习使用python搭建自动化测试框架?这个系统包你可能会用到
-
织梦(Dedecms)建站教程 织梦建站详细步骤
-
【开源分享】2024PHP在线客服系统源码(搭建教程+终身使用)
-
2024PHP在线客服系统源码+完全开源 带详细搭建教程
-
- 最近发表
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)