Java 和 MySQL - 快速指南


Java 和 MySQL - 概述

JDBC代表Java数据库连接,它是一种标准Java API,用于 Java 编程语言和各种数据库之间的独立于数据库的连接

JDBC 库包含用于下面提到的通常与数据库使用相关的每项任务的 API。

  • 建立与数据库的连接。

  • 创建 SQL 或 MySQL 语句。

  • 在数据库中执行 SQL 或 MySQL 查询。

  • 查看和修改结果记录。

从根本上来说,JDBC 是一个提供一整套接口的规范,允许对底层数据库进行可移植的访问。Java 可用于编写不同类型的可执行文件,例如 -

  • Java应用程序

  • Java 小程序

  • Java Servlet

  • Java ServerPages (JSP)

  • 企业 JavaBean (EJB)。

所有这些不同的可执行文件都能够使用 JDBC 驱动程序访问数据库,并利用存储的数据。

JDBC 提供与 ODBC 相同的功能,允许 Java 程序包含与数据库无关的代码。

先决条件

在进一步进行之前,您需要很好地理解以下两个主题 -

JDBC架构

JDBC API 支持数据库访问的两层和三层处理模型,但一般来说,JDBC 架构由两层组成 -

  • JDBC API - 这提供了应用程序到 JDBC 管理器的连接。

  • JDBC 驱动程序 API - 这支持 JDBC 管理器到驱动程序的连接。

JDBC API 使用驱动程序管理器和特定于数据库的驱动程序来提供与异构数据库的透明连接。

JDBC 驱动程序管理器确保使用正确的驱动程序来访问每个数据源。驱动程序管理器能够支持连接到多个异构数据库的多个并发驱动程序。

以下是架构图,显示了驱动程序管理器相对于 JDBC 驱动程序和 Java 应用程序的位置 -

JDBC架构

通用 JDBC 组件

JDBC API 提供以下接口和类 -

  • DriverManager - 此类管理数据库驱动程序列表。使用通信子协议将来自 java 应用程序的连接请求与正确的数据库驱动程序相匹配。第一个识别 JDBC 下某个子协议的驱动程序将用于建立数据库连接。

  • 驱动程序- 该接口处理与数据库服务器的通信。您很少会直接与 Driver 对象交互。相反,您可以使用 DriverManager 对象来管理此类对象。它还抽象了与使用驱动程序对象相关的细节。

  • 连接- 该接口包含用于联系数据库的所有方法。连接对象代表通信上下文,即与数据库的所有通信仅通过连接对象进行。

  • 语句- 您使用从此接口创建的对象将 SQL 语句提交到数据库。一些派生接口除了执行存储过程之外还接受参数。

  • ResultSet - 这些对象保存使用 Statement 对象执行 SQL 查询后从数据库检索的数据。它充当迭代器,允许您移动其数据。

  • SQLException - 此类处理数据库应用程序中发生的任何错误。

JDBC 4.0 包

java.sql 和 javax.sql 是 JDBC 4.0 的主要包。这是撰写本教程时的最新 JDBC 版本。它提供了与数据源交互的主要类。

这些软件包中的新功能包括以下方面的变化 -

  • 自动数据库驱动程序加载。

  • 异常处理改进。

  • 增强的 BLOB/CLOB 功能。

  • 连接和语句接口增强。

  • 国家字符集支持。

  • SQL ROWID 访问。

  • SQL 2003 XML 数据类型支持。

  • 注释。

Java 和 MySQL - 环境设置

要开始使用 JDBC 进行开发,您应该按照下面所示的步骤设置 JDBC 环境。我们假设您正在 Windows 平台上工作。

安装Java

Java SE 可供免费下载。要下载,请单击此处,请下载与您的操作系统兼容的版本。

按照说明下载 Java,然后运行​​.exe以在您的计算机上安装 Java。在计算机上安装 Java 后,您需要设置环境变量以指向正确的安装目录。

设置 Windows 2000/XP 的路径

假设您已将 Java 安装在 c:\Program Files\java\jdk 目录中 -

  • 右键单击“我的电脑”并选择“属性”。

  • 单击“高级”选项卡下的“环境变量”按钮。

  • 现在,编辑“Path”变量并在其末尾添加 Java 可执行文件目录的路径。例如,如果路径当前设置为C:\Windows\System32,则按以下方式编辑它

C:\Windows\System32;c:\Program Files\java\jdk\bin

设置Windows 95/98/ME的路径

假设您已将 Java 安装在 c:\Program Files\java\jdk 目录中 -

  • 编辑“C:\autoexec.bat”文件并在末尾添加以下行 -

SET PATH = %PATH%;C:\Program Files\java\jdk\bin

设置 Linux、UNIX、Solaris、FreeBSD 的路径

应将环境变量 PATH 设置为指向 Java 二进制文件的安装位置。如果您在执行此操作时遇到问题,请参阅您的 shell 文档。

例如,如果您使用 bash 作为 shell,那么您可以在.bashrc末尾添加以下行-

export PATH = /path/to/java:$PATH'

当您安装 J2SE 开发工具包时,您会自动获得 JDBC 包java.sqljavax.sql

安装数据库

当然,您需要的最重要的东西是一个实际运行的数据库,其中包含可以查询和修改的表。

安装最适合您的数据库。您可以有很多选择,最常见的是 -

  • MySQL DB - MySQL 是一个开源数据库。您可以从MySQL 官方网站下载它。我们建议下载完整的 Windows 安装。

  • 此外,下载并安装MySQL Administrator以及MySQL Query Browser。这些是基于 GUI 的工具,可以让您的开发变得更加容易。

  • 最后,下载MySQL Connector/J(MySQL JDBC 驱动程序)并将其解压到一个方便的目录中。出于本教程的目的,我们假设您已将驱动程序安装在 C:\Program Files\MySQL\mysql-connector-java-5.1.8 中。

  • 因此,将 CLASSPATH 变量设置为 C:\Program Files\MySQL\mysql-connector-java-5.1.8\mysql-connector-java-5.1.8-bin.jar。您的驱动程序版本可能会因您的安装而异。

设置数据库凭证

当我们安装 MySQL 数据库时,其管理员 ID 被设置为root,并且可以设置您选择的密码。

使用 root ID 和密码,您可以创建另一个用户 ID 和密码,也可以将 root ID 和密码用于 JDBC 应用程序。

有各种数据库操作,例如数据库创建和删除,需要管理员 ID 和密码。

对于 JDBC 教程的其余部分,我们将使用 MySQL 数据库,其中guest作为 ID,guest123作为密码。

如果您没有足够的权限来创建新用户,那么您可以要求数据库管理员 (DBA) 为您创建用户 ID 和密码。

创建数据库

要创建TUTORIALSPOINT数据库,请使用以下步骤 -

步骤1

打开命令提示符并更改为安装目录,如下所示 -

C:\>
C:\>cd Program Files\MySQL\bin
C:\Program Files\MySQL\bin>

注意- mysqld.exe的路径可能会有所不同,具体取决于系统上 MySQL 的安装位置。您还可以查看有关如何启动和停止数据库服务器的文档。

第2步

如果数据库服务器尚未运行,请执行以下命令来启动它。

C:\Program Files\MySQL\bin>mysqld
C:\Program Files\MySQL\bin>

步骤3

通过执行以下命令创建TUTORIALSPOINT数据库 -

C:\Program Files\MySQL\bin> mysqladmin create TUTORIALSPOINT -u guest -p
Enter password: ********
C:\Program Files\MySQL\bin>

创建表

要在 TUTORIALSPOINT 数据库中创建员工表,请使用以下步骤 -

步骤1

打开命令提示符并更改为安装目录,如下所示 -

C:\>
C:\>cd Program Files\MySQL\bin
C:\Program Files\MySQL\bin>

第2步

登录数据库如下 -

C:\Program Files\MySQL\bin>mysql -u guest -p
Enter password: ********
mysql>

步骤3

创建表Employees如下 -

mysql> use TUTORIALSPOINT;
mysql> create table Employees
    -> (
    -> id int not null,
    -> age int not null,
    -> first varchar (255),
    -> last varchar (255)
    -> );
Query OK, 0 rows affected (0.08 sec)
mysql>

创建数据记录

最后,您在 Employee 表中创建几条记录,如下所示 -

mysql> INSERT INTO Employees VALUES (100, 18, 'Zara', 'Ali');
Query OK, 1 row affected (0.05 sec)

mysql> INSERT INTO Employees VALUES (101, 25, 'Mahnaz', 'Fatma');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO Employees VALUES (102, 30, 'Zaid', 'Khan');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO Employees VALUES (103, 28, 'Sumit', 'Mittal');
Query OK, 1 row affected (0.00 sec)

mysql>

要完整了解 MySQL 数据库,请学习MySQL 教程

现在您已准备好开始尝试 JDBC。下一章为您提供了有关 JDBC 编程的示例。

Java 和 MySQL - 示例代码

本章提供了如何创建一个简单的基于 java 的应用程序来访问 MySQL 数据库的示例。这将向您展示如何打开数据库连接、执行 SQL 查询并显示结果。

此模板示例中提到的所有步骤将在本教程的后续章节中进行解释。

创建 JDBC 应用程序

构建 JDBC 应用程序涉及以下六个步骤 -

  • 导入包- 要求您包含包含数据库编程所需的 JDBC 类的包。大多数情况下,使用import java.sql.*就足够了。

  • 打开连接- 需要使用DriverManager.getConnection()方法创建一个 Connection 对象,该对象表示与数据库的物理连接。

  • 执行查询- 需要使用 Statement 类型的对象来构建 SQL 语句并将其提交到数据库。

  • 从结果集中提取数据- 要求您使用适当的ResultSet.getXXX()方法从结果集中检索数据。

  • 清理环境- 需要显式关闭所有数据库资源,而不是依赖 JVM 的垃圾收集。

示例代码

当您将来需要创建自己的 JDBC 应用程序时,此示例示例可以用作模板

该示例代码是根据上一章中完成的环境和数据库设置编写的。

将以下示例复制并粘贴到 TestApplication.java 中,编译并运行如下 -

import java.sql.*;

public class TestApplication {
   static final String DB_URL = "jdbc:mysql://localhost/TUTORIALSPOINT";
   static final String USER = "guest";
   static final String PASS = "guest123";
   static final String QUERY = "SELECT id, first, last, age FROM Employees";

   public static void main(String[] args) {
      // Open a connection
      try(Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
         Statement stmt = conn.createStatement();
         ResultSet rs = stmt.executeQuery(QUERY);) {
         // Extract data from result set
         while (rs.next()) {
            // Retrieve by column name
            System.out.print("ID: " + rs.getInt("id"));
            System.out.print(", Age: " + rs.getInt("age"));
            System.out.print(", First: " + rs.getString("first"));
            System.out.println(", Last: " + rs.getString("last"));
         }
      } catch (SQLException e) {
         e.printStackTrace();
      } 
   }
}

现在让我们按如下方式编译上面的示例 -

C:\>javac TestApplication.java
C:\>

当您运行TestApplication时,它会产生以下结果 -

C:\>java TestApplication
ID: 100, Age: 18, First: Zara, Last: Ali
ID: 101, Age: 25, First: Mahnaz, Last: Fatma
ID: 102, Age: 30, First: Zaid, Last: Khan
ID: 103, Age: 28, First: Sumit, Last: Mittal
C:\>

Java 和 MySQL - 连接

安装适当的驱动程序后,就可以使用 JDBC 建立数据库连接了。

建立 JDBC 连接所涉及的编程相当简单。这是简单的三个步骤 -

  • 导入 JDBC 包- 将导入语句添加到 Java 程序中,以导入 Java 代码中所需的类。

  • 数据库 URL 公式- 这是为了创建一个格式正确的地址,指向您想要连接的数据库。

  • 创建连接对象- 最后,编写对DriverManager对象的getConnection()方法的调用来建立实际的数据库连接。

导入 JDBC 包

Import语句告诉 Java 编译器在哪里可以找到您在代码中引用的类,并且这些语句被放置在源代码的最开头

要使用标准 JDBC 包(允许您选择、插入、更新和删除 SQL 表中的数据),请将以下导入添加到源代码中 -

import java.sql.* ;  // for standard JDBC programs
import java.math.* ; // for BigDecimal and BigInteger support

注册 JDBC 驱动程序

您必须在类路径中具有所需的 JDBC 驱动程序。在当前情况下,您将 CLASSPATH 变量设置为 C:\Program Files\MySQL\mysql-connector-java-5.1.8\mysql-connector-java-5.1.8-bin.jar。您的驱动程序版本可能会因您的安装而异。

数据库 URL 制定

加载驱动程序后,您可以使用DriverManager.getConnection()方法建立连接。为了便于参考,让我列出三个重载的 DriverManager.getConnection() 方法 -

  • 获取连接(字符串网址)

  • getConnection(字符串 url, 属性 prop)

  • getConnection(字符串 url, 字符串用户, 字符串密码)

这里每个表单都需要一个数据库URL。数据库 URL 是指向您的数据库的地址。

大多数与建立连接相关的问题都发生在制定数据库 URL 的地方。

下表列出了 MySQL JDBC 驱动程序名称和数据库 URL。

关系型数据库管理系统 JDBC 驱动程序名称 网址格式
MySQL com.mysql.jdbc.驱动程序 jdbc:mysql://主机名/ 数据库名

URL 格式中所有突出显示的部分都是静态的,您只需根据数据库设置更改其余部分。

创建连接对象

我们列出了三种形式的DriverManager.getConnection()方法来创建连接对象。

使用带有用户名和密码的数据库 URL

getConnection() 最常用的形式要求您传递数据库 URL、用户名密码-

当您使用 MySQL 驱动程序时,您将为 URL 的数据库部分指定 host:port:databaseName 值。

如果您的主机位于 TCP/IP 地址 192.0.0.1,主机名为 localhost,并且您的 MySQL 侦听器默认配置为侦听端口 3306,并且您的数据库名称为 TUTORIALSPOINT,则完整的数据库 URL 将为 -

jdbc:mysql://localhost/TUTORIALSPOINT

现在您必须使用适当的用户名和密码调用 getConnection() 方法来获取Connection对象,如下所示 -

String URL = "jdbc:mysql://localhost/TUTORIALSPOINT";
String USER = "guest";
String PASS = "password"
Connection conn = DriverManager.getConnection(URL, USER, PASS);

使用数据库 URL 和属性对象

DriverManager.getConnection() 方法的第三种形式需要数据库 URL 和 Properties 对象 -

DriverManager.getConnection(String url, Properties info);

Properties 对象保存一组关键字-值对。它用于在调用 getConnection() 方法期间将驱动程序属性传递给驱动程序。

要建立与前面示例相同的连接,请使用以下代码 -

import java.util.*;

String URL = "jdbc:mysql://localhost/TUTORIALSPOINT";
Properties info = new Properties( );
info.put( "user", "guest" );
info.put( "password", "guest123" );

Connection conn = DriverManager.getConnection(URL, info);

为了更好地理解,我们建议您学习我们的Java 和 MySQL - 示例代码教程

现在让我们按如下方式编译上面的示例 -

C:\>javac FirstExample.java
C:\>

当您运行FirstExample时,它​​会产生以下结果 -

C:\>java FirstExample
ID: 100, Age: 18, First: Zara, Last: Ali
ID: 101, Age: 25, First: Mahnaz, Last: Fatma
ID: 102, Age: 30, First: Zaid, Last: Khan
ID: 103, Age: 28, First: Sumit, Last: Mittal
C:\>

Java 和 MySQL - 异常处理

异常处理允许您以受控方式处理异常情况,例如程序定义的错误。

当异常情况发生时,会抛出异常。术语“抛出”意味着当前程序执行停止,并且控制被重定向到最近的适用的 catch 子句。如果不存在适用的 catch 子句,则程序的执行结束。

JDBC 异常处理与 Java 异常处理非常相似,但对于 JDBC,您要处理的最常见异常是java.sql.SQLException。

SQLException 方法

SQLException 可能发生在驱动程序和数据库中。当发生此类异常时,SQLException 类型的对象将被传递给 catch 子句。

传递的 SQLException 对象具有以下可用于检索有关异常的附加信息的方法 -

方法 描述
获取错误代码() 获取与异常关联的错误号。
获取消息() 获取由驱动程序处理的 JDBC 驱动程序的错误消息,或者获取数据库错误的 Oracle 错误号和消息。
获取SQLState() 获取 XOPEN SQLstate 字符串。对于 JDBC 驱动程序错误,此方法不会返回任何有用的信息。对于数据库错误,将返回五位 XOPEN SQLstate 代码。该方法可以返回 null。
获取下一个异常() 获取异常链中的下一个 Exception 对象。
打印堆栈跟踪() 打印当前异常或可抛出异常,并且回溯到标准错误流。
printStackTrace(PrintStream s) 将此 throwable 及其回溯打印到您指定的打印流。
printStackTrace(PrintWriter w) 打印此可抛出对象,并将其回溯到您指定的打印编写器。

通过利用 Exception 对象中的可用信息,您可以捕获异常并适当地继续您的程序。这是 try 块的一般形式 -

try {
   // Your risky code goes between these curly braces!!!
}
catch(Exception ex) {
   // Your exception handling code goes between these 
   // curly braces
}
finally {
   // Your must-always-be-executed code goes between these 
   // curly braces. Like closing database connection.
}

例子

研究以下示例代码以了解try...catch...finally块的用法。

该代码是根据上一章完成的环境和数据库设置编写的。

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class TestApplication {
   static final String DB_URL = "jdbc:mysql://localhost/TUTORIALSPOINT";
   static final String USER = "guest";
   static final String PASS = "guest123";
   static final String QUERY = "{call getEmpName (?, ?)}";

   public static void main(String[] args) {
      // Open a connection
      try(Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
         CallableStatement stmt = conn.prepareCall(QUERY);
      ) {		      
         // Bind values into the parameters.
         stmt.setInt(1, 1);  // This would set ID
         // Because second parameter is OUT so register it
         stmt.registerOutParameter(2, java.sql.Types.VARCHAR);
         //Use execute method to run stored procedure.
         System.out.println("Executing stored procedure..." );
         stmt.execute();
         //Retrieve employee name with getXXX method
         String empName = stmt.getString(2);
         System.out.println("Emp Name with ID: 1 is " + empName);
      } catch (SQLException e) {
         e.printStackTrace();
      } 
   }
}

现在让我们按如下方式编译上面的示例 -

C:\>javac TestApplication.java
C:\>

当您运行TestApplication时,如果没有问题,它会产生以下结果,否则将捕获相应的错误并显示错误消息 -

C:\>java TestApplication
Executing stored procedure...
Emp Name with ID: 1 is Zara
C:\>

Java 和 MySQL - 声明

JDBC Statement 接口定义了将 SQL 命令发送到 MySQL 数据库并从数据库检索数据的方法和属性。语句用于对数据库进行通用访问。当您在运行时使用静态 SQL 语句时,它非常有用。Statement 接口不能接受参数。

在使用Statement对象执行SQL语句之前,您需要使用Connection对象的createStatement()方法创建一个Statement对象,如下例所示:

Statement stmt = null;
try {
   stmt = conn.createStatement( );
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   . . .
}

创建 Statement 对象后,您可以使用它的三个执行方法之一来执行 SQL 语句。

  • booleanexecute(String SQL) - 如果可以检索 ResultSet 对象,则返回布尔值 true;否则,返回 false。使用此方法执行 SQL DDL 语句或需要使用真正的动态 SQL 时。

  • intexecuteUpdate(String SQL) - 返回受 SQL 语句执行影响的行数。使用此方法执行您希望受影响的行数的 SQL 语句 - 例如 INSERT、UPDATE 或 DELETE 语句。

  • ResultSetexecuteQuery(String SQL) - 返回一个 ResultSet 对象。当您希望获得结果集时,请使用此方法,就像使用 SELECT 语句一样。

结束语对象

正如关闭 Connection 对象以节省数据库资源一样,出于同样的原因,您也应该关闭 Statement 对象。

简单地调用 close() 方法即可完成这项工作。如果先关闭 Connection 对象,它也会关闭 Statement 对象。但是,您应该始终显式关闭 Statement 对象以确保正确清理。

Statement stmt = null;
try {
   stmt = conn.createStatement( );
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   stmt.close();
}

我们对资源使用 try 来自动处理资源关闭。以下示例演示了上述所有概念。

该代码是根据上一章完成的环境和数据库设置编写的。

将以下示例复制并粘贴到 TestApplication.java 中,编译并运行如下 -

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestApplication {
   static final String DB_URL = "jdbc:mysql://localhost/TUTORIALSPOINT";
   static final String USER = "guest";
   static final String PASS = "guest123";
   static final String QUERY = "SELECT id, first, last, age FROM Employees";
   static final String UPDATE_QUERY = "UPDATE Employees set age=30 WHERE id=103";

   public static void main(String[] args) {
      // Open a connection
      try(Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
         Statement stmt = conn.createStatement();
         ) {
         // Let us check if it returns a true Result Set or not.
         Boolean ret = stmt.execute(UPDATE_QUERY);
         System.out.println("Return value is : " + ret.toString() );

         // Let us update age of the record with ID = 103;
         int rows = stmt.executeUpdate(UPDATE_QUERY);
         System.out.println("Rows impacted : " + rows );

         // Let us select all the records and display them.
         ResultSet rs = stmt.executeQuery(QUERY);		      

         // Extract data from result set
         while (rs.next()) {
            // Retrieve by column name
            System.out.print("ID: " + rs.getInt("id"));
            System.out.print(", Age: " + rs.getInt("age"));
            System.out.print(", First: " + rs.getString("first"));
            System.out.println(", Last: " + rs.getString("last"));
         }
         rs.close();
      } catch (SQLException e) {
         e.printStackTrace();
      } 
   }
}

现在让我们按如下方式编译上面的示例 -

C:\>javac TestApplication.java
C:\>

当您运行TestApplication时,它会产生以下结果 -

C:\>java TestApplication
Return value is : false
Rows impacted : 1
ID: 100, Age: 18, First: Zara, Last: Ali
ID: 101, Age: 25, First: Mehnaz, Last: Fatma
ID: 102, Age: 30, First: Zaid, Last: Khan
ID: 103, Age: 30, First: Sumit, Last: Mittal
C:\>

Java 和 MySQL - 准备语句

PreparedStatement接口扩展了Statement 接口,它为您提供了附加功能并且与通用Statement 对象相比具有一些优势。

该语句使您能够灵活地动态提供参数。

创建PreparedStatement对象

PreparedStatement pstmt = null;
try {
   String SQL = "Update Employees SET age = ? WHERE id = ?";
   pstmt = conn.prepareStatement(SQL);
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   . . .
}

JDBC 中的所有参数均由?表示 符号,称为参数标记。在执行 SQL 语句之前,您必须为每个参数提供值。

setXXX ()方法将值绑定到参数,其中XXX表示您希望绑定到输入参数的值的 Java 数据类型。如果忘记提供值,您将收到 SQLException。

每个参数标记都由其顺序位置引用。第一个标记表示位置 1,下一个标记表示位置 2,依此类推。此方法与 Java 数组索引不同,Java 数组索引从 0 开始。

所有与数据库交互的Statement对象方法(a)execute()、(b)executeQuery()和(c)executeUpdate()也适用于PreparedStatement对象。然而,这些方法被修改为使用可以输入参数的SQL语句。

关闭PreparedStatement对象

正如您关闭 Statement 对象一样,出于同样的原因,您也应该关闭PreparedStatement 对象。

简单地调用 close() 方法即可完成这项工作。如果您先关闭 Connection 对象,它也会关闭PreparedStatement 对象。但是,您应该始终显式关闭PreparedStatement 对象以确保正确的清理。

PreparedStatement pstmt = null;
try {
   String SQL = "Update Employees SET age = ? WHERE id = ?";
   pstmt = conn.prepareStatement(SQL);
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   pstmt.close();
}

我们对资源使用 try 来自动处理资源关闭。以下示例演示了上述所有概念。

该代码是根据上一章完成的环境和数据库设置编写的。

将以下示例复制并粘贴到 TestApplication.java 中,编译并运行如下 -

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestApplication {
   static final String DB_URL = "jdbc:mysql://localhost/TUTORIALSPOINT";
   static final String USER = "guest";
   static final String PASS = "guest123";
   static final String QUERY = "SELECT id, first, last, age FROM Employees";
   static final String UPDATE_QUERY = "UPDATE Employees set age=? WHERE id=?";

   public static void main(String[] args) {
      // Open a connection
      try(Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
         PreparedStatement stmt = conn.prepareStatement(UPDATE_QUERY);
      ) {		      
         // Bind values into the parameters.
         stmt.setInt(1, 35);  // This would set age
         stmt.setInt(2, 102); // This would set ID

         // Let us update age of the record with ID = 102;
         int rows = stmt.executeUpdate();
         System.out.println("Rows impacted : " + rows );

         // Let us select all the records and display them.
         ResultSet rs = stmt.executeQuery(QUERY);		      

         // Extract data from result set
         while (rs.next()) {
            // Retrieve by column name
            System.out.print("ID: " + rs.getInt("id"));
            System.out.print(", Age: " + rs.getInt("age"));
            System.out.print(", First: " + rs.getString("first"));
            System.out.println(", Last: " + rs.getString("last"));
         }
         rs.close();
      } catch (SQLException e) {
         e.printStackTrace();
      } 
   }
}

现在让我们按如下方式编译上面的示例 -

C:\>javac TestApplication.java
C:\>

当您运行TestApplication时,它会产生以下结果 -

C:\>java TestApplication
Return value is : false
Rows impacted : 1
ID: 100, Age: 18, First: Zara, Last: Ali
ID: 101, Age: 25, First: Mehnaz, Last: Fatma
ID: 102, Age: 35, First: Zaid, Last: Khan
ID: 103, Age: 30, First: Sumit, Last: Mittal
C:\>

Java 和 MySQL - CallableStatement

CallableStatement接口用于执行对数据库存储过程的调用

假设您需要在 TUTORIALSPOINT 数据库中执行以下存储过程 -

DELIMITER $$

DROP PROCEDURE IF EXISTS `TUTORIALSPOINT`.`getEmpName` $$
CREATE PROCEDURE `TUTORIALSPOINT`.`getEmpName` 
   (IN EMP_ID INT, OUT EMP_FIRST VARCHAR(255))
BEGIN
   SELECT first INTO EMP_FIRST
   FROM Employees
   WHERE ID = EMP_ID;
END $$

DELIMITER ;

存在三种类型的参数 - IN、OUT 和 INOUT。PreparedStatement 对象仅使用 IN 参数。CallableStatement 对象可以使用所有这三个。

以下是每个的定义 -

范围 描述
创建 SQL 语句时其值未知的参数。您可以使用 setXXX() 方法将值绑定到 IN 参数。
出去 其值由它返回的 SQL 语句提供的参数。您可以使用 getXXX() 方法从 OUT 参数中检索值。
进出 提供输入值和输出值的参数。您可以使用 setXXX() 方法绑定变量,并使用 getXXX() 方法检索值。

以下代码片段显示了如何使用Connection.prepareCall()方法基于前面的存储过程实例化CallableStatement对象 -

CallableStatement cstmt = null;
try {
   String SQL = "{call getEmpName (?, ?)}";
   cstmt = conn.prepareCall (SQL);
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   . . .
}

字符串变量 SQL,表示带有参数占位符的存储过程。

使用CallableStatement 对象与使用PreparedStatement 对象非常相似。在执行语句之前,您必须将值绑定到所有参数,否则您将收到 SQLException。

如果您有 IN 参数,只需遵循适用于PreparedStatement 对象的相同规则和技术即可;使用与您要绑定的 Java 数据类型相对应的 setXXX() 方法。

当您使用 OUT 和 INOUT 参数时,您必须使用附加的 CallableStatement 方法,registerOutParameter()。registerOutParameter() 方法将 JDBC 数据类型绑定到存储过程预期返回的数据类型。

调用存储过程后,您可以使用适当的 getXXX() 方法从 OUT 参数中检索值。此方法将 SQL 类型的检索值转换为 Java 数据类型。

关闭 CallableStatement 对象

正如您关闭其他 Statement 对象一样,出于同样的原因,您也应该关闭 CallableStatement 对象。

简单地调用 close() 方法即可完成这项工作。如果先关闭 Connection 对象,它也会关闭 CallableStatement 对象。但是,您应该始终显式关闭 CallableStatement 对象以确保正确的清理。

CallableStatement cstmt = null;
try {
   String SQL = "{call getEmpName (?, ?)}";
   cstmt = conn.prepareCall (SQL);
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   cstmt.close();
}

我们对资源使用 try 来自动处理资源关闭。以下示例演示了上述所有概念。

该代码是根据上一章完成的环境和数据库设置编写的。

将以下示例复制并粘贴到 TestApplication.java 中,编译并运行如下 -

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class TestApplication {
   static final String DB_URL = "jdbc:mysql://localhost/TUTORIALSPOINT";
   static final String USER = "guest";
   static final String PASS = "guest123";
   static final String QUERY = "{call getEmpName (?, ?)}";

   public static void main(String[] args) {
      // Open a connection
      try(Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
         CallableStatement stmt = conn.prepareCall(QUERY);
      ) {		      
         // Bind values into the parameters.
         stmt.setInt(1, 102);  // This would set ID
         // Because second parameter is OUT so register it
         stmt.registerOutParameter(2, java.sql.Types.VARCHAR);
         //Use execute method to run stored procedure.
         System.out.println("Executing stored procedure..." );
         stmt.execute();
         //Retrieve employee name with getXXX method
         String empName = stmt.getString(2);
         System.out.println("Emp Name with ID: 102 is " + empName);
      } catch (SQLException e) {
         e.printStackTrace();
      } 
   }
}

现在让我们按如下方式编译上面的示例 -

C:\>javac TestApplication.java
C:\>

当您运行TestApplication时,它会产生以下结果 -

C:\>java TestApplication
Executing stored procedure...
Emp Name with ID: 102 is Zaid
C:\>

JDBC SQL 转义语法

转义语法使您能够通过标准 JDBC 方法和属性灵活地使用您无法使用的数据库特定功能。

一般的 SQL 转义语法格式如下 -

{keyword 'parameters'}

以下是以下转义序列,您会发现它们在执行 JDBC 编程时非常有用 -

d、t、ts 关键字

它们帮助识别日期、时间和时间戳文字。如您所知,没有两个 DBMS 以相同的方式表示时间和日期。此转义语法告诉驱动程序以目标数据库的格式呈现日期或时间。例如 -

{d 'yyyy-mm-dd'}

其中 yyyy = 年,mm = 月;dd = 日期。使用此语法 {d '2009-09-03'} 表示 2009 年 3 月 9 日。

这是一个简单的示例,显示如何在表中插入日期 -

//Create a Statement object
stmt = conn.createStatement();
//Insert data ==> ID, First Name, Last Name, DOB
String sql="INSERT INTO STUDENTS VALUES" +
   "(100,'Zara','Ali', {d '2001-12-16'})";

stmt.executeUpdate(sql);

同样,您可以使用以下两种语法之一,tts -

{t 'hh:mm:ss'}

其中 hh = 小时;毫米=分钟;ss = 第二。使用此语法 {t '13:30:29'} 为下午 1:30:29。

{ts 'yyyy-mm-dd hh:mm:ss'}

这是上述两种语法的组合语法,其中“d”和“t”表示时间戳。

转义关键字

该关键字标识 LIKE 子句中使用的转义字符。使用 SQL 通配符 % 时很有用,它匹配零个或多个字符。例如 -

String sql = "SELECT symbol FROM MathSymbols WHERE symbol LIKE '\%' {escape '\'}";
stmt.execute(sql);

如果使用反斜杠字符 (\) 作为转义字符,则还必须在 Java 字符串文本中使用两个反斜杠字符,因为反斜杠也是 Java 转义字符。

fn 关键字

该关键字表示 DBMS 中使用的标量函数。例如,您可以使用 SQL 函数length来获取字符串的长度 -

{fn length('Hello World')}

返回 11,即字符串“Hello World”的长度。

呼叫关键字

该关键字用于调用存储过程。例如,对于需要 IN 参数的存储过程,请使用以下语法 -

{call my_procedure(?)};

对于需要 IN 参数并返回 OUT 参数的存储过程,请使用以下语法 -

{? = call my_procedure(?)};

关键字

该关键字用于表示外连接。语法如下 -

{oj outer-join}

其中外连接=表{LEFT|RIGHT|FULL} OUTERJOIN {表| 搜索条件上的外连接}。例如 -

String sql = "SELECT Employees FROM {oj ThisTable RIGHT OUTER JOIN ThatTable on id = '100'}";
stmt.execute(sql);

Java 和 MySQL - 结果集

从数据库查询读取数据的 SQL 语句,返回结果集中的数据。SELECT 语句是从数据库中选择行并在结果集中查看它们的标准方法。java.sql.ResultSet接口表示数据库查询的结果集

ResultSet 对象维护一个指向结果集中当前行的游标。术语“结果集”是指 ResultSet 对象中包含的行和列数据。

ResultSet 接口的方法可以分为三类 -

  • 导航方法- 用于移动光标。

  • 获取方法- 用于查看光标指向的当前行的列中的数据。

  • 更新方法- 用于更新当前行列中的数据。然后,这些更新也可以在底层数据库中进行更新。

光标可以根据 ResultSet 的属性进行移动。这些属性是在创建生成 ResultSet 的相应语句时指定的。

JDBC 提供以下连接方法来创建具有所需结果集的语句 -

  • createStatement(int RSType, int RSConcurrency);

  • 准备语句(字符串SQL,int RSType,int RSConcurrency);

  • 准备调用(字符串sql,int RSType,int RSConcurrency);

第一个参数指示 ResultSet 对象的类型,第二个参数是两个 ResultSet 常量之一,用于指定结果集是只读还是可更新。

结果集类型

下面给出了可能的 RSType。如果您未指定任何 ResultSet 类型,您将自动获得 TYPE_FORWARD_ONLY 类型。

类型 描述
结果集.TYPE_FORWARD_ONLY 光标只能在结果集中向前移动。
结果集.TYPE_SCROLL_INSENSITIVE 游标可以向前和向后滚动,结果集对创建结果集后其他人对数据库所做的更改不敏感。
结果集.TYPE_SCROLL_SENSITIVE。 游标可以向前和向后滚动,结果集对创建结果集后其他人对数据库所做的更改很敏感。

结果集的并发

下面给出了可能的 RSConcurrency。如果您未指定任何并发类型,您将自动获得 CONCUR_READ_ONLY 并发类型。

并发性 描述
结果集.CONCUR_READ_ONLY 创建只读结果集。这是默认设置
结果集.CONCUR_UPDATABLE 创建可更新的结果集。

到目前为止我们编写的所有示例都可以写成如下,它初始化一个 Statement 对象来创建一个只进、只读的 ResultSet 对象 -

try(
   Statement stmt = conn.createStatement(
      ResultSet.TYPE_FORWARD_ONLY,
      ResultSet.CONCUR_READ_ONLY);)
}
catch(Exception ex) {
   ....
}
finally {
   ....
}

Java 和 MySQL - 导航结果集

ResultSet 接口中有多种涉及移动光标的方法,包括 -

序列号 方法与说明
1 public void beforeFirst() 抛出 SQLException

将光标移动到第一行之前。

2 public void afterLast() 抛出 SQLException

将光标移动到最后一行之后。

3 public boolean first() 抛出 SQLException

将光标移至第一行。

4 public void last() 抛出 SQLException

将光标移动到最后一行。

5 public boolean Absolute(int row) 抛出 SQLException

将光标移动到指定行。

6 public booleanrelative(int row) 抛出 SQLException

将光标从当前指向的位置向前或向后移动给定的行数。

7 public boolean previous() 抛出 SQLException

将光标移动到上一行。如果前一行不在结果集中,则此方法返回 false。

8 public boolean next() 抛出 SQLException

将光标移动到下一行。如果结果集中没有更多行,则此方法返回 false。

9 public int getRow() 抛出 SQLException

返回光标指向的行号。

10 public void moveToInsertRow() 抛出 SQLException

将游标移动到结果集中的特殊行,可用于将新行插入数据库。当前光标位置被记住。

11 public void moveToCurrentRow() 抛出 SQLException

如果光标当前位于插入行,则将光标移回当前行;否则,这个方法什么也不做

以下是使用所描述的几种导航方法的示例。

该示例代码是根据前面章节中完成的环境和数据库设置编写的。

将以下示例复制并粘贴到 TestApplication.java 中,编译并运行如下 -

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestApplication {
   static final String DB_URL = "jdbc:mysql://localhost/TUTORIALSPOINT";
   static final String USER = "guest";
   static final String PASS = "guest123";
   static final String QUERY = "SELECT id, first, last, age FROM Employees";

   public static void main(String[] args) {
      // Open a connection
      try(Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
         Statement stmt = conn.createStatement(
         ResultSet.TYPE_SCROLL_INSENSITIVE,
         ResultSet.CONCUR_READ_ONLY);
         ResultSet rs = stmt.executeQuery(QUERY);
      ) {		
         // Move cursor to the last row.
         System.out.println("Moving cursor to the last...");
         rs.last();

         // Extract data from result set
         System.out.println("Displaying record...");
         //Retrieve by column name
         int id  = rs.getInt("id");
         int age = rs.getInt("age");
         String first = rs.getString("first");
         String last = rs.getString("last");

         // Display values
         System.out.print("ID: " + id);
         System.out.print(", Age: " + age);
         System.out.print(", First: " + first);
         System.out.println(", Last: " + last);

         // Move cursor to the first row.
         System.out.println("Moving cursor to the first row...");
         rs.first();

         // Extract data from result set
         System.out.println("Displaying record...");
         // Retrieve by column name
         id  = rs.getInt("id");
         age = rs.getInt("age");
         first = rs.getString("first");
         last = rs.getString("last");

         // Display values
         System.out.print("ID: " + id);
         System.out.print(", Age: " + age);
         System.out.print(", First: " + first);
         System.out.println(", Last: " + last);
         // Move cursor to the first row.

         System.out.println("Moving cursor to the next row...");
         rs.next();

         // Extract data from result set
         System.out.println("Displaying record...");
         id  = rs.getInt("id");
         age = rs.getInt("age");
         first = rs.getString("first");
         last = rs.getString("last");

         // Display values
         System.out.print("ID: " + id);
         System.out.print(", Age: " + age);
         System.out.print(", First: " + first);
         System.out.println(", Last: " + last);		

      } catch (SQLException e) {
         e.printStackTrace();
      } 
   }
}

现在让我们按如下方式编译上面的示例 -

C:\>javac TestApplication.java
C:\>

当您运行TestApplication时,它会产生以下结果 -

C:\>java TestApplication
Moving cursor to the last...
Displaying record...
ID: 103, Age: 30, First: Sumit, Last: Mittal
Moving cursor to the first row...
Displaying record...
ID: 100, Age: 18, First: Zara, Last: Ali
Moving cursor to the next row...
Displaying record...
ID: 101, Age: 25, First: Mehnaz, Last: Fatma
C:\>

Java 和 MySQL - 查看结果集

ResultSet 接口包含数十种获取当前行数据的方法。

每种可能的数据类型都有一个 get 方法,每个 get 方法都有两个版本 -

  • 一个接受列名的列。

  • 接受列索引的一个。

例如,如果您有兴趣查看的列包含 int,则需要使用 ResultSet 的 getInt() 方法之一 -

序列号 方法与说明
1 public int getInt(String columnName) 抛出 SQLException

返回名为columnName 的列中当前行的int。

2 public int getInt(int columnIndex) 抛出 SQLException

返回当前行中指定列索引的 int。列索引从 1 开始,表示行的第一列为 1,行的第二列为 2,依此类推。

类似地,ResultSet 接口中对于八种 Java 基本类型以及 java.lang.String、java.lang.Object 和 java.net.URL 等常见类型中的每一种都有 get 方法。

还有一些获取 SQL 数据类型 java.sql.Date、java.sql.Time、java.sql.TimeStamp、java.sql.Clob 和 java.sql.Blob 的方法。有关使用这些 SQL 数据类型的更多信息,请查看文档。

以下是使用所描述的几种查看方法的示例。

该示例代码是根据前面章节中完成的环境和数据库设置编写的。

将以下示例复制并粘贴到 TestApplication.java 中,编译并运行如下 -

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestApplication {
   static final String DB_URL = "jdbc:mysql://localhost/TUTORIALSPOINT";
   static final String USER = "guest";
   static final String PASS = "guest123";
   static final String QUERY = "SELECT id, first, last, age FROM Employees";

   public static void main(String[] args) {
      // Open a connection
      try(Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
         Statement stmt = conn.createStatement(
         ResultSet.TYPE_SCROLL_INSENSITIVE,
         ResultSet.CONCUR_READ_ONLY);
         ResultSet rs = stmt.executeQuery(QUERY);
      ) {		
         // Move cursor to the last row.
         System.out.println("Moving cursor to the last...");
         rs.last();

         // Extract data from result set
         System.out.println("Displaying record...");
         //Retrieve by column name
         int id  = rs.getInt("id");
         int age = rs.getInt("age");
         String first = rs.getString("first");
         String last = rs.getString("last");

         // Display values
         System.out.print("ID: " + id);
         System.out.print(", Age: " + age);
         System.out.print(", First: " + first);
         System.out.println(", Last: " + last);

         // Move cursor to the first row.
         System.out.println("Moving cursor to the first row...");
         rs.first();

         // Extract data from result set
         System.out.println("Displaying record...");
         // Retrieve by column name
         id  = rs.getInt("id");
         age = rs.getInt("age");
         first = rs.getString("first");
         last = rs.getString("last");

         // Display values
         System.out.print("ID: " + id);
         System.out.print(", Age: " + age);
         System.out.print(", First: " + first);
         System.out.println(", Last: " + last);
         // Move cursor to the first row.

         System.out.println("Moving cursor to the next row...");
         rs.next();

         // Extract data from result set
         System.out.println("Displaying record...");
         id  = rs.getInt("id");
         age = rs.getInt("age");
         first = rs.getString("first");
         last = rs.getString("last");

         // Display values
         System.out.print("ID: " + id);
         System.out.print(", Age: " + age);
         System.out.print(", First: " + first);
         System.out.println(", Last: " + last);		

      } catch (SQLException e) {
         e.printStackTrace();
      } 
   }
}

现在让我们按如下方式编译上面的示例 -

C:\>javac TestApplication.java
C:\>

当您运行TestApplication时,它会产生以下结果 -

C:\>java TestApplication
Moving cursor to the last...
Displaying record...
ID: 103, Age: 30, First: Sumit, Last: Mittal
Moving cursor to the first row...
Displaying record...
ID: 100, Age: 18, First: Zara, Last: Ali
Moving cursor to the next row...
Displaying record...
ID: 101, Age: 25, First: Mehnaz, Last: Fatma
C:\>

Java 和 MySQL - 更新结果集

ResultSet 接口包含用于更新结果集数据的更新方法的集合。

与 get 方法一样,每种数据类型都有两种更新方法 -

  • 一个接受列名的列。

  • 接受列索引的一个。

例如,要更新结果集当前行的字符串列,您可以使用以下 updateString() 方法之一 -

序列号 方法与说明
1public void updateString(int columnIndex, String s) 抛出 SQLException

将指定列中的 String 更改为 s 的值。

2 public void updateString(String columnName, String s) 抛出 SQLException

与前面的方法类似,不同之处在于列是通过其名称而不是索引来指定的。

java.sql 包中提供了八种基本数据类型以及 String、Object、URL 和 SQL 数据类型的更新方法。

更新结果集中的行会更改 ResultSet 对象中当前行的列,但不会更改基础数据库中的列。要更新对数据库中行的更改,您需要调用以下方法之一。

序列号 方法与说明
1 公共无效更新行()

通过更新数据库中的相应行来更新当前行。

2 公共无效删除行()

从数据库中删除当前行

3 公共无效刷新行()

刷新结果集中的数据以反映数据库中的任何最新更改。

4 公共无效取消行更新()

取消对当前行所做的任何更新。

5 公共无效插入行()

将一行插入数据库。仅当光标指向插入行时才能调用此方法。

以下是使用结果集教程中描述的ResultSet.CONCUR_UPDATABLEResultSet.TYPE_SCROLL_INSENSITIVE的示例。此示例将解释表上的 INSERT、UPDATE 和 DELETE 操作。

应该注意的是,您正在处理的表应该正确设置主键。让我们首先更新我们的参考表。

删除表并再次创建表Employees ,如下所示 -

mysql> use TUTORIALSPOINT;
mysql> drop table Employees;
Query OK, 0 rows affected (0.08 sec)
mysql> create table Employees
    -> (
    -> id int primary key auto_increment,
    -> age int not null,
    -> first varchar (255),
    -> last varchar (255)
    -> );
Query OK, 0 rows affected (0.08 sec)
mysql>

创建数据记录

最后,您在 Employee 表中创建几条记录,如下所示 -

mysql> INSERT INTO Employees(AGE, FIRST, LAST) VALUES (18, 'Zara', 'Ali');
Query OK, 1 row affected (0.05 sec)

mysql> INSERT INTO Employees(AGE, FIRST, LAST) VALUES (25, 'Mahnaz', 'Fatma');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO Employees(AGE, FIRST, LAST) VALUES (30, 'Zaid', 'Khan');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO Employees(AGE, FIRST, LAST) VALUES (28, 'Sumit', 'Mittal');
Query OK, 1 row affected (0.00 sec)

mysql>

将以下示例复制并粘贴到 TestApplication.java 中,编译并运行如下 -

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestApplication {
   static final String DB_URL = "jdbc:mysql://localhost/TUTORIALSPOINT";
   static final String USER = "guest";
   static final String PASS = "guest123";
   static final String QUERY = "SELECT id, first, last, age FROM Employees";

   public static void printResultSet(ResultSet rs) throws SQLException{
      // Ensure we start with first row
      rs.beforeFirst();
      while(rs.next()){
         // Display values
         System.out.print("ID: " + rs.getInt("id"));
         System.out.print(", Age: " + rs.getInt("age"));
         System.out.print(", First: " + rs.getString("first"));
         System.out.println(", Last: " + rs.getString("last"));
      }
      System.out.println();
   }

   public static void main(String[] args) {
      // Open a connection
      try(Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
         Statement stmt = conn.createStatement(
         ResultSet.TYPE_SCROLL_INSENSITIVE,
         ResultSet.CONCUR_UPDATABLE);
         ResultSet rs = stmt.executeQuery(QUERY);
      ) {		

         System.out.println("List result set for reference....");