Java JDBC学习实战(二): 管理结果集

在我的上一篇博客《Java JDBC学习实战(一): JDBC的基本操作》中,简要介绍了jdbc开发的基本流程,并详细介绍了Statement和PreparedStatement的使用:利用这两个API可以执行SQL语句,完成基本的CURD操作。那么,当我们进行查询操作,查询到了结果集,该如何处理呢? Java提供了一个API,专门用于表示查询的结果集——ResultSet。此外,还提供了一个结果集的分析工具——ResultSetMetaData。


一、 ResultSet的介绍

1.1 可移动、可更新的ResultSet
 《Java JDBC学习实战(一): JDBC的基本操作》一文里,介绍过ResultSet的相关方法,可以通过一系列的方法来移动记录指针,如:absolute、previous、next、first、last、beforeFirst、afterLast等方法。
ResultSet默认是不支持更新的,如果希望ResultSet完成更新操作,必须在创建Statement或PrepareStatement时传入一些参数。
Connection对象在创建Statement或PrepareStatement时可以传入两个参数:
A、 resultSetType:控制ResultSet的类型,该参数有以下三个值:
    a、 ResultSet.TYPE_FORWARD_ONLY该常量控制记录指针只能向前移动。
    b、 ResultSet.TYPE_SCROLL_INSENSITIVE:该常量控制记录指针自由移动(可滚动结果集),但底层的数据改变不影响结果集ResultSet的内容
    c、 ResultSet.TYPE_SCROLL_SENSITIVE:该常量控制记录指针自由移动,但底层数据的影响会改变结果集ResultSet的内容
B、 resultSetConcurrency:控制ResultSet的并发类型,该参数可以接收如下两个值:
    a、 ResultSet.CONCUR_READ_ONLY:该常量表示ResultSet是只读并发模式
    b、 ResultSet.CONCUR_UPDATABLE:该常量表示ResultSet是更新并发模式
通过PrepareStatement、Statement的创建时进行参数设置来创建可滚动、可更新的ResultSet,然后通过rs的updateXxx方法来完成某列的更新值设置,通过updateRow来提交修改。

// 使用Connection创建一个PreparedStatement对象
// 传入控制结果集可滚动、可更新的参数
PreparedStatement pstmt = conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);



1.2、 ResultSet中的二进制Blob数据处理

Blob类型通常用来存储文件,如:图片、音频、视频文件。将文件转换成二进制保存在数据库中,取出来的时候可以二进制数据恢复成文件。

如果要插入图片到数据库,显然不能直接设置SQL参数拼接字符串进行插入。因为二进制常量无法表示。

但是将Blob类型数据插入到数据可以用PrepareStatement,通过PrepareStatement对象的setBinaryStream方法将参数传入到二进制输入流;也可以用Blob对象的getBytes方法直接取出数据。


二、 操作可滚动可更新的结果集

示例:(来自《疯狂Java讲义》)

public class ResultSetTest
{private String driver;private String url;private String user;private String pass;public void initParam(String paramFile)throws Exception{// 使用Properties类来加载属性文件Properties props = new Properties();props.load(new FileInputStream(paramFile));driver = props.getProperty("driver");url = props.getProperty("url");user = props.getProperty("user");pass = props.getProperty("pass");}public void query(String sql)throws Exception{// 加载驱动Class.forName(driver);try(// 获取数据库连接Connection conn = DriverManager.getConnection(url, user , pass);// 使用Connection来创建一个PreparedStatement对象// 传入控制结果集可滚动,可更新的参数。PreparedStatement pstmt = conn.prepareStatement(sql , ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);ResultSet rs = pstmt.executeQuery()){rs.last();// 指针移动到结果集的最后int rowCount = rs.getRow();for (int i = rowCount; i > 0 ; i-- ){rs.absolute(i);// 指针移动到指定位置System.out.println(rs.getString(1) + "\t"+ rs.getString(2) + "\t" + rs.getString(3));// 修改记录指针所有记录、第2列的值rs.updateString(2 , "学生名" + i);// 提交修改rs.updateRow();}}}public static void main(String[] args) throws Exception{ResultSetTest rt = new ResultSetTest();rt.initParam("mysql.ini");rt.query("select * from student_table");}
}


注: 如果要创建可更新的结果集,则使用查询的数据通常只能来自一个数据表,而且查询结果集中的数据列必须包含主键列,否则将会更新失败。

三、 处理Blob类型数据

比如我们有如下数据表,表中的字段img_data类型为mediumblob,专门保存图片数据

create table img_table(

   img_id int auto_increment primary key,

   img_name varchar(255),

   #创建一个mediumblob类型的数据列,用于保存图片数据

   img_data mediumblob

);


之前已经讲过,操作图片数据,需要通过PrepareStatement对象的setBinaryStream方法来实现.

public void upload(String fileName)
{// 截取文件名String imageName = fileName.substring(fileName.lastIndexOf('\\')+ 1 , fileName.lastIndexOf('.'));File f = new File(fileName);try(InputStream is = new FileInputStream(f)){// 设置图片名参数insert.setString(1, imageName);// 设置二进制流参数insert.setBinaryStream(2, is , (int)f.length());  int affect = insert.executeUpdate();if (affect == 1){// 重新更新ListModel,将会让JList显示最新的图片列表fillListModel();}}catch (Exception e){e.printStackTrace();}
}	

可见,上述程序已经能完成图片数据的插入操作,那如何读取数据库的图片数据呢?ResultSet结果集可以直接通过getBlob()方法,得到Blob数据,可以再将其转为Stream进行操作。

// ---------根据图片ID来显示图片----------public void showImage(int id)throws SQLException{// 设置参数query.setInt(1, id);try(	// 执行查询ResultSet rs = query.executeQuery()){if (rs.next()){// 取出Blob列Blob imgBlob = rs.getBlob(1);// 取出Blob列里的数据ImageIcon icon=new ImageIcon(imgBlob.getBytes(1L,(int)imgBlob.length()));imageLabel.setIcon(icon);}}}public static void main(String[] args)throws SQLException{new BlobTest().init();}
}


四、 使用ResultSetMetaData分析结果集

在我们查询数据返回的结果集中,我们不清楚结果集存放的数据类型、数据列数。
那样我们就可以用ResultSetMetaData来读取ResultSet的信息。
通过ResultSet的getMetaData()的方法可以获取ResultSetMetaData对象。
然后可以用ResultSetMetaData对象的方法来操作ResultSet,常用方法如下:
int getColumnCount():返回ResultSet的列名数量
int getColumnType(int column):返回指定索引的类型
String getColumnName(int column):返回指定索引的列名


     try(// 根据用户输入的SQL执行查询ResultSet rs = stmt.executeQuery(sqlField.getText())){// 取出ResultSet的MetaDataResultSetMetaData rsmd = rs.getMetaData();Vector<String> columnNames =  new Vector<>();Vector<Vector<String>> data = new Vector<>();// 把ResultSet的所有列名添加到Vector里for (int i = 0 ; i < rsmd.getColumnCount(); i++ ){columnNames.add(rsmd.getColumnName(i + 1));}// 把ResultSet的所有记录添加到Vector里while (rs.next()){Vector<String> v = new Vector<>();for (int i = 0 ; i < rsmd.getColumnCount(); i++ ){v.add(rs.getString(i + 1));}data.add(v);}}catch (Exception e){e.printStackTrace();}


注:虽然,ResultSetMetaData可以准确地分析出ResultSet里包含了多少列,以及每列的列名、数据类型等,但使用ResuleSetMetaData需要一定的系统开销,开发中尽量不要使用该API。

转载于:https://www.cnblogs.com/hehe520/p/6330016.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/375596.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

error: storage size of ‘threads’ isn’t known

出错的代码行&#xff1a; pthread_t threads[NUM_THREADS];原因&#xff1a; NUM_THREADS 无值 原先&#xff1a; #define NUM_THREADS修改为 #define NUM_THREADS 5

android之相机开发

http://blog.csdn.net/jason0539/article/details/10125017 android之相机开发 分类&#xff1a; android 基础知识2013-08-20 22:32 9774人阅读 评论(2) 收藏 举报Android在android中应用相机功能&#xff0c;一般有两种&#xff1a;一种是直接调用系统相机&#xff0c;一种自…

文件和文件夹权限-Win7公共盘中出现大量临时文件

公司中有一个文件服务器&#xff0c;给不同部门和员工设置了不同的权限&#xff0c;最近有员工&#xff08;没有修改权限&#xff0c;有读取及执行,读取,写入&#xff09;反映在公共盘上修改文件的时候会产生大量的临时文件&#xff0c;添加上修改权限之后就可以了&#xff0c;…

Duilib编辑框Edit输入完自动跳到下一个编辑框

首先xml文件中设置edit的maxchar参数&#xff0c;默认255好像。 <edit maxchar"10" />然后在notify函数中加入以下代码 if (msg.sType _T("textchanged")) {if (static_cast<CEditUI*>(msg.pSender)->GetMaxChar() msg.pSender->GetT…

Mysql数据库安全管理配置

1.删除test库 原因&#xff1a; The default MySQL installation comes with a database named test that anyone can access. This database is intended only for tutorials, samples, testing, etc. Databases named "test" and also databases with names starti…

duilib清空richedit内容

推荐使用以下方法&#xff1a; m_pRichEdit->SetSelAll(); m_pRichEdit->Clear();不推荐使用以下方法&#xff1a; m_pRichEdit->SetText("");虽然效果是一样的&#xff0c;但是当编辑框中文本存在多种格式的时候&#xff0c;第二种方法会存在问题&#x…

新学了一个用python编写的简单的百度贴吧帖子的爬虫

# -*- coding: utf-8 -*- #--------------------------------------- # 作者&#xff1a;chendn # 语言&#xff1a;Python 2.7.10 #---------------------------------------import string,urllib2 def tieba(url,beginPage,endPage):for i in range(beginPage,endPage1):…

duilib自定义消息

/** NOTE: All Message Numbers below 0x0400 are RESERVED.** Private Window Messages Start Here:*/ #define WM_USER 0x0400从WM_USER往上加就行了

BZOJ 2190仪仗队【欧拉函数】

问题的唯一难点就是如何表示队长能看到的人数&#xff1f;如果建系&#xff0c;队长所在的点为&#xff08;0,0&#xff09;分析几组数据就一目了然了&#xff0c;如果队长能看到的点为(m,n),那么gcd&#xff08;m&#xff0c;n&#xff09;1即m n 互质或者是&#xff08;0,1&a…

Codeforces Round #318 (Div. 2) B Bear and Three Musketeers (暴力)

算一下复杂度。发现可以直接暴。对于u枚举a和b&#xff0c;判断一下是否连边&#xff0c;更新答案。 #include<bits/stdc.h> using namespace std;int n,m; const int maxn 4001; #define PB push_back vector<int> G[maxn]; bool g[maxn][maxn]; int deg[maxn]; …

form表单,submit,ajax提交

尼玛... 一个简单的表单提交&#xff0c;竟然给我整的直郁闷。 本来就是个保存功能&#xff0c;几个前人都用的ajax提交&#xff0c;我也就没改成submit。然后坑爹的就来了。 我在表单里写了个<form></form>&#xff08;实际用ajax提交&#xff0c;也没必要写这个标…

windows 文件对话框

https://docs.microsoft.com/zh-cn/previous-versions/windows/desktop/legacy/bb776913(vvs.85)

python开发技术详解(一)

python是一门简单灵动的语言。从今天开始我要每天都做笔记&#xff0c;每天都要写博客记录我所想&#xff0c;我所学到的。 笔记提纲&#xff1a; 1&#xff0c;python的简单介绍&#xff0c;python的编译用法&#xff0c;有什么要注意的。 2&#xff0c;命名规则 3&#xff0c…

(Android Studio)添加文本框

此文大部分摘自http://hukai.me/android-training-course-in-chinese/basics/firstapp/building-ui.html android : id 这是定义View的唯一标识符。可以在程序代码中通过该标识符对对象进行引用&#xff0c;例如对这个对象进行读和修改的操作(在下一课里将会用到)。 当想从XML里…

java final keyword

依据上下文环境&#xff0c;java的keywordfinal也存在着细微的差别&#xff0c;但通常指的是“这是无法改变的。”不想改变的理由由两种&#xff1a;一种是效率&#xff0c;还有一种是设计。因为两个原因相差非常远&#xff0c;所以关键子final可能被吴用。 接下来介绍一下使用…

听GPT 讲Rust源代码--src/tools(24)

File: rust/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs 在Rust源代码中的rust/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs文件是Clippy项目的一个规则&#xff0c;用于检查可能是误用或错误的Box引用情况。 Rust中的Box是一个堆分配的值的所有权…

递归乘法

递归乘法。 写一个递归函数&#xff0c;不使用 * 运算符&#xff0c; 实现两个正整数的相乘。可以使用加号、减号、位移&#xff0c;但要吝啬一些。 示例1: 输入&#xff1a;A 1, B 10输出&#xff1a;10示例2: 输入&#xff1a;A 3, B 4输出&#xff1a;12提示: 保证乘法…

Building a RESTful Web Service

http://spring.io/guides/gs/rest-service/ Should shutdown tomcat service first , and then java -jar *.jar转载于:https://www.cnblogs.com/churuosi/p/4774151.html

IOS的各种手势

转自http://blog.csdn.net/likendsl/article/details/7554150 一、概述 iPhone中处理触摸屏的操作&#xff0c;在3.2之前是主要使用的是由UIResponder而来的如下4种方式&#xff1a; - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event - (void)touchesCancell…