Java高手速成│Java程序怎样和数据库对话

news2024/11/17 15:32:16

 

从上一篇 Java高手速成│编写你第一个数据库程序 的例子中可以看出,Java和数据库的连接和对话离不开JDK库类,如java.sql包中支持数据库编程的各种API类、数据库软件DBMS、JDBC驱动软件或Java Connector以及你编写的数据库编程代码。

并且,在访问数据库的程序中,除调用Class类的forName()来装载JDBC驱动软件外,所有数据库操作的API类由库包java.sql提供,各种操作包括:数据库连接、SQL指令的传送、选择记录的回传、提取和相关操作,以及数据表信息metadada的获取。如下内容通过实例详细讨论这些具体的数据库编程技术。

01、连接数据库——高手都会这样做

首先调用Class类的静态方法forName()装载指定的JDBC驱动软件,再调用java.sql包提供的DriverManager的静态方法getConnection(),对指定的数据库进行连接操作。其一般代码格式如下:

try {
  Class.forName(driverName);
  Connection con = DriverManager.getConnection(dbUrl, username, password);
  ...
}
catch (ClassNotFoundException e) {
  System.err.println(e);
}
catch (SQLException ex) {
  System.err.println(e);
}

其中:

driverName——字符串参数。由数据库指定的JDBC驱动软件名。如MySQL的驱动软件名为:

drivername = "com.mysql.cj.jdbc.Driver";

注意,不同的数据库使用各自规定的驱动软件名。使用时必须参考该数据库对驱动软件的命名。

dbUrl——字符串参数。指定的数据库连接方式和地址,可以包括已存在的数据库名。如以本机方式连接MySQL服务器的dbUrl为:

dbUrl = "jdbc:mysql://localhost:3306"; //连接到本机数据库服务器
//或:"jdbc:mysql://localhost:3306/ProductDB";//连接到本机服务器中的数据库

以远程方式通过网络连接MySQL服务器的dbUrl为:

dbUrl = "jdbc:mysql://hostServerIP:3306/ProductDB";

其中hostServerIP为MySQL服务器的IP地址或服务器名;3306为MySQL预设的网络端口;ProductDB为已创建的数据库名。

Username——字符串参数。指定的用户名。如"root"。

Password——字符串参数。指定的密码。如果没有密码,则为""。

forName()方法将抛出检查性异常ClassNotFoundException,getConection()将抛出检查性异常SQLException,代码中必须提供处理这两个异常的机制。

同样要注意不同的数据库使用各自规定的dbUrl和路径进行远程数据库连接。使用时必须参考该数据库对通过网络对数据库连接的规定。

02、向数据库发送SQL指令

发送SQL指令的一般代码格式为:

try {
  Connection con = DriverManager.getConnection(dbUrl, username, password);
  Statement stmt = con.createStatement(); //返回Statement对象
  stmt.executeUpdate(sqlString); //调用发送SQL指令方法;
  ... //更多调用发送SQL指令的方法
  stmt.close(); //关闭发送
}
catch (ClassNotFoundException e) {
  System.err.println(e);
}
catch (SQLException ex) {
  System.err.println(e);
}

其中createStatement()将返回一个Statement的对象,然后调用其executeUpdate()方法,将指定的SQL指令发送到数据库,并加以执行。

sqlString为字符串,必须是合法SQL指令,否则将产生检查性异常SQLException。sqlString可以是除SELECT之外的任何SQL指令。

最后调用close()方法,关闭发送SQL指令的操作。

如下是常用发送SQL指令的例子。


...
String createTable = "CREATE TABLE Books (ISBN CHAR(13),Title VARCHAR
  (50),Price DECIMAL("+ "6, 2),Inventory INT, Publisher VARCHAR(30))";
String insertRecord1 = "INSERT INTO Books (ISBN, Title, Price, Inventory, Publisher)VALUES ("+ "'9781890774555', 'Java Lover', 66, 10, 'ABC Press') ";
String updateRecord1 = "UPDATE Books SET Price = 69.15 WHERE Price= 66";
//String deleteRecord1 = " DELETE FROM Books WHERE ISBN = '9781890774555'";
stmt.executeUpdate(createTable); //调用发送SQL指令方法;
stmt.executeUpdate(insertRecord1);
stmt.executeUpdate(updateRecord1);
//stmt.executeUpdate(deleteRecord1); //可在理解这个编程实例后再执行删除指令
... //其他操作指令
Stmt.close(); //关闭
... //异常处理

这个例子向数据库发送了4个常用指令:

CREATE
INSERT
UPDATE
DELETE

建议你在理解了从java程序怎样发送指令到数据库后,再执行删除指令。另外建议你打开数据库服务器:

MySQL 8.0 Command Line Client

直接发送SQL指令,如use(调用数据库)、desc(描述数据表)、select (显示数据表)等帮助你查询和了解在执行了Java语句后数据库内容的变化。

03、接收从数据库传回的记录

调用Statement的方法executeQuery()将返回一个ResultSet对象。executeQuery()将执行指定的获取数据表数据的SQL指令,如SELECT,并将执行结果封装在这个ResultSet对象中。ResultSet提供了一系列方法和静态字段,用来提取回传的结果。

以Products数据表为例,得到回传结果的一般代码格式为:

try {
  Connection con = DriverManager.getConnection(dbUrl, username, password);
  Statement stmt = con.createStatement(); //返回Statement对象
  String sqlString = "SELECT * FROM Products"; //定义SQL指令
  ResultSet rs = stmt.executeQuery(sqlString); //执行SQL指令并得到回传结果
  while(rs.next()) { //如果还有记录则继续循环
    String code = rs.getString();//得到当前记录中的第一个 字段的值
    String Title = rs.getString(); //得到当前记录中的第二个字段的值
    Double price = rs.getDouble(); //得到当前记录中的第三个字段的值
    ... //执行利用得到数据的各种操作
  }
  rs.close(); //关闭
  catch (ClassNotFoundException e) {
    System.err.println(e);
  }
  catch (SQLException ex) {
    System.err.println(e);
  }

可以看到,利用executeUpdate()方法向数据库发送SQL指令;而利用executeQuery()得到数据库记录的回传结果。值得一提的是,ResultSet本身是一个接口,在执行executeQuery()时,产生一个完善了ResultSet的对象,并作为引用返回这个对象。

在提取封装在ResultSet中的记录时,涉及三类操作:

设置提取方式以及对ResultSet中记录指示器(也称光标)的操作,如移动或证实当前记录器位置。

得到记录中的数据或者删除、更新记录的操作。

得到有关数据表信息metadata,既元数据的操作。

java.sql包中的ResultSet提供静态字段来设置对记录的提取方式。表2列出了ResultSet常用字段和移动/证实记录指示器的常用方法。

表2 ResultSet的常用字段和移动/证实记录指示器常用方法

 

注意  ResultSet预设的纪录指示器位置为0。首次调用next()时,记录指示器位置为第一个记录的开始。如果记录指示器指向一个不存在的记录时,ResultSet对象则为null。

例子之一:利用ResultSet的静态字段设置按记录中的相反次序提取数据,并允许变更。提取方式的设定通过调用Statement重载的方法createStatement()实现,如:

Statement stmt = con.createStatement(ResultSet.FETCH_REVERSE, CONCUR_UPDATABLE);

例子之二:调用其他移动记录指示器的方法。

...
rs.first(); //指示器移到第一个记录的开始
rs.last(); //指示器移到最后一个记录的开始
rs.absolute(10); //指示器移到第10个记录的开始
rs.absolute(1); //等同于rs.first()
rs.absolute(-1); //等同于rs.last()
rs.absolute(-2); //倒数第二个记录的开始
rs.relative(-3); //指示器从当前位置返回3个记录
rs.relative(5); //指示器从当前位置往下移动5个记录。如果移至的位置无记录,ResultSet为null
if (isFirst())
  rs.next();//记录指示器在第二个记录的开始
...

 

04、提取和更新传回的记录

表3列出了ResultSet用来提取记录数据以及变更和删除记录的常用方法。

 表3 esultSet提取记录数据和更新记录的常用方法

 

值得一提的是,数据库操作中所有记录位置指示器,包括字段位置(列),都从1算起。

例子之一:提取ResultSet中的结果。假设执行了如下SQL指令:

ResultSet rs = stmt.executeQuery("SELECT * FROM Books");

数据表Books的字段定义见作者的新书22.5.2小节中的详细讨论。

例子之二:调用next()方法并利用循环提取ResultSet中的所有记录数据。

//完整程序见本文压缩附件中名为ResultSetTest.java源代码
...
while (rs.next()) { //如果还有记录,则继续循环
  //执行封装在rs中的各记录数据的操作
  System.out.println("ISNB: " + rs.getString(1)); //或rs.getString("ISNB"));
  System.out.println("Book Title: " + rs.getString(2)); //或rs.getString("Title"));
  System.out.println("Price: " + rs.getDouble(3)); //或rs.getString("Price"));
  System.out.println("Inventory: " + rs.getInt(4)); //或rs.getString("Inventory"));
  System.out.println("Publisher: " + rs.getString(5)); //或rs.getString("Publisher"));
}
...

 

例子之三:更新当前记录的内容。

 

rs.updateString(1, "1109123466666"); //修改当前记录指定字段(ISBN)的字符 //串值为新值
rs.updateDouble("Price", 125.89); //修改当前记录指定字段(Price)的值为 125.89

以上对当前记录的修改也可利用SQL指令UPDATE完成,如:

stmt.executeUpdate("UPDATE Books SET Code = '1109123466666', Price = 125.89"+ "WHERE Code = '9781890774555'");

这种操作指涉及数据库,而不影响当前在ResultSet中的该记录。

例子之四:继续上例,删除指定的记录。

rs.delelteRow(); //删除在ResultSet中以及数据库Books表中当前记录

同上,也可利用SQL指令DELETE删除数据库中的指定记录,如:

stmt.executeUpdate("DELETE FROM Books WHERE Code = '1109123466666'");

你可利用ResultSetTest.java这个程序实例,加入这里讨论的4个指令,运行并分析结果,以便加深理解如何应用这些操作。

05、预备指令是怎么回事

如果一个SQL指令需要以不同的数值或参数执行多次,预备指令,又称预备语句,则为首选。预备指令prepared statement,也称问号指令。指在SQL指令中将字段的值以问号?形式,设为变量,在执行中将被具体数据所代替。这种指令也称为参数化指令。

前面讨论的由Statement的executeUpdate()以及executeQuery()发送的SQL指令,都必须经过数据库编译后,方可执行。而预备指令,正如其名,则产生预先编译好的SQL指令,再由其setXxx()方法将具体参数值提供给SQL指令。预备指令实现了抽象指令模式和具体执行指令的分离,减少代码重复,提高编程效率。

预备指令功能包括在由java.sql包提供的PraparedStatement中,通过调用Connection的prepareStatement()方法,由其返回一个PreparedStatement对象而得到。调用其各种setXxx()方法得到参数值,再调用其executeUpdate()或executeQuery()完成指令的执行。如:

例子之一:一个典型预备指令。


...
try {
  Connection con = DriverManager.getConnection(url, username, password);
  String selectSql = "UPDATE Products SET Price = ? WHERE Code = ?";
  PreparedStatement ps = con.prepareStatement(selectSql); //编译预备指令
  ps.setDouble(1, 1209.88); //1代表第一个问号
  ps.setString(2, "2200"); //2代表第二个问号
  ps.executeUpdate(); //执行预备指令
  ps.close(); //关闭
}
catch(ClassNotFoundException e){
  System.out.println("Database driver not found.");
}
catch (SQLException e) {e.printStackTrace();}

以上代码中,两个问号代表指令参数。在调用setXxx()方法指定其值时,首先提供代表问号的序号(从1开始),再提供代表问号的值。如上例中,1代表第一个问号,表示Price的参数;2代表第二个问号,代表Code的参数。

一个预备指令中可以有多个问号。其序号按出现次序确定。PreparedStatement提供了设置所有数据类型值的方法setXx(),调用时必须注意数据类型的匹配。预备指令将抛出检查性异常SQLException,代码中必须提供处理这个异常的机制。

例子之二:利用预备指令在数据表中加入记录。


...
try {
  Connection con = DriverManager.getConnection(url, username, password);
  String insertSql = "INSERT INTO Products (Code, Title, Price) VALUES (?, ?, ?)";
  PreparedStatement ps = con.prepareStatement(insertSql); //编译预备指令
  ps.setString(1, "1110"); //1代表第一个问号
  ps.setString(2, "Java EE Programming" ); //2代表第二个问号
  ps.setDouble(3, 77.02); //3代表第三个问号
  ps.executeUpdate() //执行预备指令;
  ps.close(); //关闭
}
catch(ClassNotFoundException e){
    System.out.println("Database driver not found.");
}
catch (SQLException e) {e.printStackTrace();}

例子之三:利用预备指令选择指定数据表中的记录。


...
String choice = "y";
ResultSet rs = null;
Connection con = DriverManager.getConnection(dbURL, username, password);
String deleteSql = "SELECT * FROM Products WHERE Code = ?";
PreparedStatement ps = con.prepareStatement(deleteSql);
  while (true) {
    code = JOptionPane.showInputDialog("Enter the product code: ");
    ps.setString(1, code); //指定的记录
    rs = ps.executeQuery(); //执行预备指令
    rs.next(); //指向这个记录
    String record = rs.getString(1) + " " + rs.getString(2) + " " + rs.getDouble(3); //产生记录格式
    JOptionPane.showMessageDialog(null, record); //显示记录
    choice = JOptionPane.showInputDialog("是否继续?(y/n): "); ;
    if (choice.equalsIgnoreCase("n"))
      break;
  }
  ps.close();
...

例子之四:利用预备指令在数据表中删除记录。


...
try {
  double price = 0;
  boolean quit = false;
  Scanner sc = new Scanner(System.in);
  Connection con = DriverManager.getConnection(url, username, password);
  String deleteSql = "DELETE FROM Products WHERE Price) = ?";
  PreparedStatement ps = con.prepareStatement(deleteSql);
    while (true) {
      System.out.println("Please enter the price you want that record to be deleted: ");
      price = sc.nextDouble();
      ps.setDouble(1, price); //删除由price指定的记录
      ps.executeUpdate(); //执行预备指令
      System.out.println("Do you want to continue? (y/n): ");
           choice = sc.next();
        if (choice.equalsIgnoreCase("n"))
          break;
        else
      sc.nextLine();
  }
  ps.close();
}
catch(ClassNotFoundException e){
    System.out.println("Database driver not found.");
}
catch (SQLException e) {e.printStackTrace();}

 核心代码:

JDBCExamples.zip - 坚果云 - 云盘|网盘|企业网盘|同步|备份|无限空间|免费网络硬盘|企业云盘

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

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

相关文章

基础不牢,地动山摇系列 ------ 软硬通吃 unity常用API

👨‍💻个人主页:元宇宙-秩沅 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 秩沅 原创 收录于专栏 unity 实战系列 ⭐相关文章⭐ ——————————————————— -关于游戏剧情模式中用到的基础简单A…

第01讲:Git安装及基本操作

一、什么是Git 版本控制系统(VCS)是将『什么时候、谁、对什么文件做了怎样的修改』这样的信息以版本的形式保存并进行管理的系统。 简单来说,版本控制系统会去记录它所管理的文件的『历史版本』。 版本控制系统 “不是网盘,而胜…

linux常用命令(一)-路径切换及查看

切换路径-cd 我们可以使用cd(change directory,切换目录)的命令来进行目录切换 常规 其命令格式为 cd [相对路径或绝对路径] 例如: // 使用相对路径,切换到postfix目录下 cd ../postfix// 使用绝对路径切换到/var/…

Linux操作系统实验1——地址转换

实验要求: 1.在内核中先申请一个页面,使用内核提供的函数,按照寻页的步骤一步步的找到物理地址。这些步骤就相当于我们手动的模拟了mmu的寻页过程。(paging_lowmem.c) 2.通过mmap将物理内存的数据映射到一个设备文件中。 通过访问该设备就可以…

美图商业化2.0:探寻多元增长曲线

【潮汐商业评论/原创】 数字化智能化浪潮正席卷而来。与此前的工业革命、信息技术革命一样,这场箭在弦上的“数智化革命”核心也在于技术的突破与应用。 今年以来,AIGC作为AI技术在内容生产领域的应用,迎来了全球大厂的争相布局&#xff0c…

tensorflow2.x多层感知机模型参数量和计算量的统计

当创建了一个多层感知机模型后,如何调用接口获取该模型的参数量和计算量?首先,打印出模型结构,可通过graphviz模块实现 # 加载模型 model keras.models.load_model(modelPath) tf.keras.utils.plot_model(model, to_filemodel.p…

linux ubuntu 如何自动定时备份数据库到服务器 mysql mysqldump cron

linux ubuntu 如何自动定时备份数据库到服务器 mysql mysqldump cron 一、需求描述 我有一个小日记应用,从 2019 年到 2022 年已经出现了两次比较严重的数据丢失的情况,一次是服务器错误,一次是人为。 所以我急切需要它能自己自动备份数据库…

基于servlet+jsp+mysql实现的java web校园车辆管理系统

一、项目简介 本项目是一套基于servletjspmysql实现的java web校园车辆管理系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严…

WebDAV之葫芦儿·派盘+Orgzly

Orgzly 支持WebDAV方式连接葫芦儿派盘。 给大家推荐一款Android 上的笔记与 todo 待办事项相融合的应用,它通过树形结构来记录笔记,并且只需要对笔记进行 TODO 标记就能变身任务管理,十分方便。 Orgzly是一款多功能的应用,更确切地说,它是一款 org 文件编辑器。Org 和 …

ArcGIS基础实验操作100例--实验12以线要素分割面要素(二)

本实验专栏来自于汤国安教授《地理信息系统基础实验操作100例》一书 实验平台:ArcGIS 10.6 实验数据:请访问实验1(传送门) 基础编辑篇--实验12 以线要素分割面要素(二) 目录 一、实验背景 二、实验数据 …

C++ | 缺省参数

啊我摔倒了..有没有人扶我起来学习.... 👱个人主页:《CGod的个人主页》\color{Darkorange}{《CGod的个人主页》}《CGod的个人主页》交个朋友叭~ 💒个人社区:《编程成神技术交流社区》\color{Darkorange}{《编程成神技术交流社区》…

UDS - 10.2 DiagnosticSessionControl (10) service

来自:ISO 14229-1-2020.pdf 10.2.1 服务描述 DiagnosticSessionControl服务用于在服务器中启用不同的诊断会话。 诊断会话启用服务器中的一组特定诊断服务和/或功能。该服务提供了服务器可以报告数据链路层特定参数值的能力,这些参数值对于已启用的诊断…

Python语言快速入门下1

目录 一、函数 【函数定义与调用】 【形参与实参】 【return语句】 【变量作用域】 【可变长度参数】 二、lambda表达式 三、案例 【例题1】 【例题2】 【例题3】 【例题4】 【例题5】 一、函数 【函数定义与调用】 【例子】一个穷小子想娶富家之女,她…

【正点原子FPGA连载】第四章开发环境搭建摘自【正点原子】DFZU2EG/4EV MPSoC 之FPGA开发指南V1.0

1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id692450874670 3)全套实验源码手册视频下载地址: http://www.openedv.com/thread-340252-1-1.html 第四章开发环境搭…

HPA与VPA

写在前面 语雀原文阅读效果更佳: 6、HPA与VPA 语雀 《6、HPA与VPA》 HPA与VPA 1、HPA 在前面的学习中我们使用了一个 kubectl scale 命令可以来实现 Pod 的扩缩容功能,但是这个是完全手动操作的,要应对线上的各种复杂情况,我…

ELK收集交换机日志

1、环境介绍 交换机:华为、思科、H3C Elasticsearch版本:7.13.3 kibana版本:v 7.13.3 logstash版本:7.17.8 2、ES集群配置 参考: https://blog.csdn.net/zyj81092211/article/details/118935274 3、kibana配置 参考 …

实战 | 使用图像处理改善OCR结果(详细步骤 + 源码)

导 读 本文主要介绍一个通过图像处理改善OCR识别结果的实例,并给出详细步骤和源码。 背景介绍 在很多情况下,文字识别会遇到困难。比如非单一的背景、杂讯干扰、文字部分缺失等。如下图所示: 我们希望识别图中的黑色文字(12-14),但背景较复杂且存在其他干扰,如果直接…

rabbitmq基础8——持久化、存储机制、ETS、队列结构、消息状态、内存告警、磁盘告警

文章目录一、持久化1.1 持久化对象1.1.1 交换器持久化1.1.2 队列持久化1.1.3 消息持久化1.2 总结要点二、存储机制2.1 存储方式2.2 存储文件2.2.1 队列索引.idx文件2.2.2 消息存储.rdq文件2.2.3 垃圾回收机制(文件合并)2.3 存储原理2.3.1 生产者消息写入…

基于图形化界面的方式创建vue2项目

前提是安装vue-cli npm i -g vue/cli 接下来使用vue ui 创建vue项目 vue ui 浏览器自动打开 点击创建,然后去到你想把创建的项目放到的位置 如果到不了那个位置,就window E 打开打开文件夹去到那个位置,之后再在文件夹的搜索中输入cmd打开命…

某农业学校 算法设计与分析-第7次实验综合

寻找数组中的第k小元素 【问题描述】给定一个长度为n的整数数组nums和整数k,输出数组中的第k小元素。要求不能对数组排序,使用分治的思想求解。 【输入形式】输入的第1行中有1个数字n,表示数组的长度;第2行中有n个数字&#xff0c…