JDBC知识点(初学用---超详细万字)

JDBC知识点(初学用)

J D B C-Java Database Connectivity(Java语言连接数据库)

简介

  1. JDBC是SUN公司制定的一套接口(interface)

    java.sql.*;(这个软件包下有很多接口)

    接口都有调用者和实现者。

    面向接口调用,面向接口写实现类,这都属于面向接口编程。

  2. 为什么要面向接口编程

    解耦合:降低程序的耦合度,提高程序的扩展力。

    多态机制就是非常典型的:面向抽象编程。(不要面向具体编程)

    建议:

    Animal a = new Cat();

    Animal a = new Dog();

    扫描二维码关注公众号,回复: 13729052 查看本文章

    public void feed (Animal a){ // 面向父类编程

    }

    不建议:

    Dog d = new Dog();

    Cat c = new Cat();

  3. 思考:为什么SUN要定义一套JDBC接口

    因为每个数据库的底层实现原理都不一样。

    Oracle数据库有自己的原理。

    MySQL也有自己的原理

    MS SQL server数据库有自己的原理

JDBC的本质:一套接口

1.JDBC SQL语法

结构化查询语言(SQL)是一种标准化语言,允许对数据库执行操作

例如:创建数据记录,读取内容,更新内容和删除数据记录等。

1. 创建数据库

CREATE DATABASE语句用于创建新的数据库。 语法是 -

SQL> CREATE DATABASE DATABASE_NAME;
SQL

示例 以下SQL语句创建一个名为EMP的数据库 -

SQL> CREATE DATABASE EMP;
SQL

2. 删除数据库

DROP DATABASE语句用于删除存在的数据库。 语法是 -

注意:要创建或删除数据库,需要有数据库服务器的管理员权限。 需要特别小心的是:删除数据库将丢失数据库中存储的所有数据(无法恢复)。

3. 创建表

CREATE TABLE语句用于创建新表。 语法是 -

SQL> CREATE TABLE table_name
(
   column_name column_data_type,
   column_name column_data_type,
   column_name column_data_type
   ...
);
SQL

示例

以下SQL语句创建一个名为Employees的表,其中包含四列:

SQL> CREATE TABLE Employees
(
   id INT NOT NULL,
   age INT NOT NULL,
   first VARCHAR(255),
   last VARCHAR(255),
   PRIMARY KEY ( id )
);
SQL

4. 删除表

DROP TABLE语句用于删除存在的表。 语法是 -

SQL> DROP TABLE table_name;
SQL

示例

以下SQL语句删除名为Employees的表 -

SQL> DROP TABLE Employees;
SQL

5. INSERT数据

INSERT的语法如下所示,其中column1column2等表示要显示在相应列中的数据值 -

SQL> INSERT INTO table_name VALUES (column1, column2, ...);
SQL

示例

以下SQL INSERT语句在先前创建的Employees表中插入一个新行 -

SQL> INSERT INTO Employees VALUES (100, 18, 'Max', 'Su');
SQL

6. 查询数据

SELECT语句用于从数据库检索数据。 SELECT的语法是 -

SQL> SELECT column_name, column_name, ...
     FROM table_name
     WHERE conditions;
SQL

WHERE子句可以使用比较运算符,例如:=!=<><=>=,以及BETWEENLIKE运算符。

示例

以下SQL语句从Employees表中选择:agefirstlast列,其中id列为100 -

SQL> SELECT first, last, age 
     FROM Employees 
     WHERE id = 100;
SQL

以下SQL语句从Employees表中选择:age, firstlast 列,其中first列包含Max -

SQL> SELECT first, last, age 
     FROM Employees 
     WHERE first LIKE '%Max%';
SQL

7. 更新数据

UPDATE语句用于更新数据。 UPDATE的语法是 -

SQL> UPDATE table_name
     SET column_name = value, column_name = value, ...
     WHERE conditions;
SQL

WHERE子句可以使用比较运算符,例如:=!=<><=>=,以及BETWEENLIKE运算符。

示例

以下SQL UPDATE语句更新id100的雇员的age列的值为:20

SQL> UPDATE Employees SET age=20 WHERE id=100;
SQL

8. 删除数据

DELETE语句用于从表中删除数据。 DELETE的语法是 -

SQL> DELETE FROM table_name WHERE conditions;
SQL

WHERE子句可以使用比较运算符,例如:=!=<><=>=,以及BETWEENLIKE运算符。

示例

以下SQL DELETE语句将删除ID100的员工的记录 -

SQL> DELETE FROM Employees WHERE id=100;

2.JDBC简单示例代码

本文章教程中将演示如何创建一个简单的JDBC应用程序的示例。 这将显示如何打开数据库连接,执行SQL查询并显示结果。

这个示例代码中涉及所有步骤,一些步骤将在本教程的后续章节中进行说明。

创建JDBC应用程序

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

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

  • 注册JDBC驱动程序:需要初始化驱动程序,以便可以打开与数据库的通信通道。

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

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

  • 从结果集中提取数据:需要使用相应的ResultSet.getXXX()方法从结果集中检索数据。

  • 清理环境:需要明确地关闭所有数据库资源,而不依赖于JVM的垃圾收集。

示例代码

此示例代码是基于上一章完成的环境和数据库设置之后编写的。

FirstExample.java (F:\worksp\jdbc\FirstExample.java)中复制并粘贴以下示例,编译并运行如下 -

//STEP 1. Import required packages
import java.sql.*;
​
public class FirstExample {
   // JDBC driver name and database URL
   static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";  
   static final String DB_URL = "jdbc:mysql://localhost/emp";
​
   //  Database credentials
   static final String USER = "root";
   static final String PASS = "123456";
​
   public static void main(String[] args) {
   Connection conn = null;
   Statement stmt = null;
   try{
      //STEP 2: Register JDBC driver
      Class.forName("com.mysql.jdbc.Driver");
​
      //STEP 3: Open a connection
      System.out.println("Connecting to database...");
      conn = DriverManager.getConnection(DB_URL,USER,PASS);
​
      //STEP 4: Execute a query
      System.out.println("Creating statement...");
      stmt = conn.createStatement();
      String sql;
      sql = "SELECT id, first, last, age FROM Employees";
      ResultSet rs = stmt.executeQuery(sql);
​
      //STEP 5: Extract data from result set
      while(rs.next()){
         //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);
      }
      //STEP 6: Clean-up environment
      rs.close();
      stmt.close();
      conn.close();
   }catch(SQLException se){
      //Handle errors for JDBC
      se.printStackTrace();
   }catch(Exception e){
      //Handle errors for Class.forName
      e.printStackTrace();
   }finally{
      //finally block used to close resources
      try{
         if(stmt!=null)
            stmt.close();
      }catch(SQLException se2){
      }// nothing we can do
      try{
         if(conn!=null)
            conn.close();
      }catch(SQLException se){
         se.printStackTrace();
      }//end finally try
   }//end try
   System.out.println("There are so thing wrong!");
}//end main
}//end FirstExample
Java

把上面代码存放到 F:\worksp\jdbc\FirstExample.java 文件中,并创建一个目录:F:\worksp\jdbc\libs,下载 mysql-connector-java-5.1.40-bin.jar 放入到F:\worksp\jdbc\libs 目录中。

使用命令行编译Java程序并加载指定目录中的Jar包(mysql-connector-java-5.1.40-bin.jar):

F:\worksp\jdbc> javac -Djava.ext.dirs=./libs FirstExample.java
##-- 或者
F:\worksp\jdbc> javac -Djava.ext.dirs=F:\worksp\jdbc\libs FirstExample.java
Shell

编译上面代码后,得到以下结果 -

## F:\worksp\jdbc>javac -Djava.ext.dirs=./libs FirstExample.java
## 运行程序 -
F:\worksp\jdbc>java -Djava.ext.dirs=./libs FirstExample
Connecting to database...
Tue May 30 22:43:18 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Creating statement...
ID: 100, Age: 28, First: Max, Last: Su
ID: 101, Age: 25, First: Wei, Last: Wang
ID: 102, Age: 30, First: Xueyou, Last: Zhang
ID: 103, Age: 28, First: Jack, Last: Ma
There are so thing wrong!
​
F:\worksp\jdbc>
Shell

完整的执行过程如下 -

或者使用 Eclipse 或其它IDE创建代码执行。



3.JDBC驱动程序类型

JDBC驱动程序是什么?

JDBC驱动程序在JDBC API中实现定义的接口,用于与数据库服务器进行交互。

例如,使用JDBC驱动程序,可以通过发送SQL或数据库命令,然后使用Java接收结果来打开数据库连接并与数据库进行交互。

JDK附带的Java.sql包包含各种类,其类的行为被定义,实现在第三方驱动程序中完成。 第三方供应商在其数据库驱动程序中实现java.sql.Driver接口。

JDBC驱动程序类型

JDBC驱动程序实现因Java运行的各种操作系统和硬件平台而异。 Sun将实现类型分为四种类型,分别为1,2,34类型,如下所述:

类型1:JDBC-ODBC桥驱动程序

类型1驱动程序中,JDBC桥接器用于访问安装在每台客户机上的ODBC驱动程序。 使用ODBC需要在系统上配置表示目标数据库的数据源名称(DSN)。

当Java第一次出现时,这是一个驱动程序,因为大多数数据库仅支持ODBC访问,但现在这种类型的驱动程序仅推荐用于实验性使用或没有其他替代方案时使用。

JDK 1.2附带的JDBC-ODBC桥接是这种驱动程序的一个很好的例子。

类型2:JDBC本地API

类型2驱动程序中,JDBC API调用将转换为本地C/C++ API调用,这是数据库唯一的。 这些驱动程序通常由数据库供应商提供,并以与JDBC-ODBC桥接相同的方式使用。 必须在每个客户机上安装供应商特定的驱动程序。

如果要更改数据库,则必须更改原生API,因为它特定于数据库,并且现在大部分已经过时,但是使用类型2驱动程序实现了一些扩展功能的开发,它消除了ODBC的开销。

Oracle调用接口(OCI)驱动程序是类型2驱动程序的示例。

类型3:JDBC-Net纯Java

类型3驱动程序中,使用三层方法访问数据库。 JDBC客户端使用标准网络套接字与中间件应用程序服务器进行通信。 套接字信息随后由中间件应用服务器转换成DBMS所需的调用格式,并转发到数据库服务器。

这种驱动程序是非常灵活的,因为它不需要在客户端上安装代码,一个驱动程序实际上可以提供多个数据库的访问。

可以将应用程序服务器视为JDBC“代理”,它会调用客户端应用程序。 因此,我们需要了解应用程序服务器的配置,才能有效地使用此驱动程序类型。

应用程序服务器可能会使用类型1,2或4驱动程序与数据库通信,了解细微差别对理解JDBC是有帮助的。

类型4:100%纯Java

类型4驱动程序中,基于纯Java的驱动程序通过套接字连接与供应商的数据库直接通信。 这是数据库可用的最高性能驱动程序,通常由供应商自己提供。

这种驱动是非常灵活的,不需要在客户端或服务器上安装特殊的软件。 此外,这些驱动程序可以动态下载。

MySQL Connector/J驱动程序是类型4驱动程序。 由于其网络协议的专有性质,数据库供应商通常提供类型4驱动程序。

应该使用哪个驱动程序?

如果您正在访问一种类型的数据库,例如Oracle,Sybase或IBM DB2,则首选驱动程序类型为类型4

如果Java应用程序同时访问多种类型的数据库,则类型3是首选驱动程序。

类型2驱动程序在数据库不可用的类型3类型4驱动程序的情况下使用。

类型1驱动程序不被视为部署级驱动程序,通常仅用于开发和测试目的。

4.JDBC数据库连接

安装相应的驱动程序后,现在是时候来学习使用JDBC建立数据库连接了。

建立JDBC连接所涉及的编程相当简单。 以下是基本的四个步骤 -

  • 导入JDBC包:使用Java语言的import语句在Java代码开头位置导入所需的类。

  • 注册JDBC驱动程序:使JVM将所需的驱动程序实现加载到内存中,从而可以满足JDBC请求。

  • 数据库URL配置:创建一个正确格式化的地址,指向要连接到的数据库(如:MySQL,Oracle和MSSQL等等)。

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

1. 导入JDBC包

import语句告诉Java编译器在哪里找到在代码中引用的类,import语句一般放置在源代码的开头。 要使用标准的JDBC包,它允许在数据库表中执行选择,插入,更新和删除数据,请将以下导入添加到源代码中 -

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

2. 注册JDBC驱动程序

在使用程序之前,必须先注册该驱动程序。 注册驱动程序是将Oracle驱动程序的类文件加载到内存中的过程,因此可以将其用作JDBC接口的实现。

只需在程序中一次注册就可以。可以通过两种方式之一来注册驱动程序。

2.1 方法I - Class.forName()

注册驱动程序最常见的方法是使用Java的Class.forName()方法,将驱动程序的类文件动态加载到内存中,并将其自动注册。这个方法是推荐使用的方法,因为它使驱动程序注册可配置和便携。

以下示例使用Class.forName()注册Oracle驱动程序 -

try {
   Class.forName("oracle.jdbc.driver.OracleDriver");
}
catch(ClassNotFoundException ex) {
   System.out.println("Error: unable to load driver class!");
   System.exit(1);
}
Java

使用JDBC驱动程序连接MySQL数据库的示例代码片段 -

Class.forName("com.mysql.jdbc.Driver");
Connection conn = null;
conn = DriverManager.getConnection("jdbc:mysql://hostname:port/db_name","db_username", "db_password");
conn.close();
Java

使用getInstance()方法来解决不合规的JVM,但是必须编写两个额外的异常,如下所示:

try {
   Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
}
catch(ClassNotFoundException ex) {
   System.out.println("Error: unable to load driver class!");
   System.exit(1);
catch(IllegalAccessException ex) {
   System.out.println("Error: access problem while loading!");
   System.exit(2);
catch(InstantiationException ex) {
   System.out.println("Error: unable to instantiate driver!");
   System.exit(3);
}
Java

2.2 方法II - DriverManager.registerDriver()

第二种方法是使用静态DriverManager.registerDriver()方法来注册驱动程序。

如果使用的是非JDK兼容的JVM(如Microsoft提供的),则应使用registerDriver()方法。

以下示例使用registerDriver()注册Oracle驱动程序 -

try {
   Driver myDriver = new oracle.jdbc.driver.OracleDriver();
   DriverManager.registerDriver( myDriver );
}
catch(ClassNotFoundException ex) {
   System.out.println("Error: unable to load driver class!");
   System.exit(1);
}
Java

5.JDBC 数据库交互

当获得了与数据库的连接后,就可以与数据库进行交互了。 JDBC StatementCallableStatementPreparedStatement接口定义了可用于发送SQL或PL/SQL命令,并从数据库接收数据的方法和属性。

它们还定义了有助于在Java和SQL数据类型的数据类型差异转换的方法。 下表提供了每个接口定义,以及使用这些接口的目的的总结。

接口 推荐使用
Statement 用于对数据库进行通用访问,在运行时使用静态SQL语句时很有用。 Statement接口不能接受参数。
PreparedStatement 当计划要多次使用SQL语句时使用。PreparedStatement接口在运行时接受输入参数。
CallableStatement 当想要访问数据库存储过程时使用。CallableStatement接口也可以接受运行时输入参数。

1. Statement对象

1.1. 创建Statement对象

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

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

在创建Statement对象后,可以使用它来执行一个SQL语句,它有三个执行方法可以执行。它们分别是 -

  • boolean execute (String SQL) : 如果可以检索到ResultSet对象,则返回一个布尔值true; 否则返回false。使用此方法执行SQLDDL语句或需要使用真正的动态SQL,可使用于执行创建数据库,创建表的SQL语句等等。

  • int executeUpdate (String SQL): 返回受SQL语句执行影响的行数。使用此方法执行预期会影响多行的SQL语句,例如:INSERTUPDATEDELETE语句。

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

1.2. 关闭Statement对象

就像关闭一个Connection对象一样,以保存数据库资源一样,由于同样的原因,还应该关闭Statement对象。

一个简单的调用close()方法将执行该作业(工作)。 如果先关闭Connection对象,它也会关闭Statement对象。 但是,应该始终显式关闭Statement对象,以确保正确的清理顺序。

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

为了更好的理解,建议学习Statment示例教程

2. PreparedStatement对象

PreparedStatement接口扩展了Statement接口,它添加了比Statement对象更好一些优点的功能。

此语句可以动态地提供/接受参数。

2.1 创建PreparedStatement对象

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

JDBC中的所有参数都由 ? 符号作为占位符,这被称为参数标记。 在执行SQL语句之前,必须为每个参数(占位符)提供值。

setXXX()方法将值绑定到参数,其中XXX表示要绑定到输入参数的值的Java数据类型。 如果忘记提供绑定值,则将会抛出一个SQLException

每个参数标记是它其顺序位置引用。第一个标记表示位置1,下一个位置2等等。 该方法与Java数组索引不同(它不从0开始)。

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

2.2. 关闭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();
}
Java

为了更好的理解,建议学习PreparedStatement示例代码

3. CallableStatement对象

类似Connection对象创建StatementPreparedStatement对象一样,它还可以使用同样的方式创建CallableStatement对象,该对象将用于执行对数据库存储过程的调用。

3.1. 创建CallableStatement对象

假设需要执行以下Oracle存储过程 -

CREATE OR REPLACE PROCEDURE getEmpName 
   (EMP_ID IN NUMBER, EMP_FIRST OUT VARCHAR) AS
BEGIN
   SELECT first INTO EMP_FIRST
   FROM Employees
   WHERE ID = EMP_ID;
END;
SQL

注意:上面的存储过程是针对Oracle编写的,但是如果您使用MySQL数据库,可使用以下方式来编写MySQL相同的存储过程,如下在EMP数据库中创建它 -

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

存在三种类型的参数:INOUTINOUTPreparedStatement对象只使用IN参数。CallableStatement对象可以使用上面三个参数类型。

以下是上面三种类型参数的定义 -

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

以下代码片段显示了如何使用Connection.prepareCall()方法根据上述存储过程来实例化一个CallableStatement对象 -

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

String变量strSQL表示存储过程,带有两个参数占位符。

使用CallableStatement对象就像使用PreparedStatement对象一样。 在执行语句之前,必须将值绑定到所有参数,否则将抛出一个SQLException异常。

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

使用OUTINOUT参数时,必须使用一个额外的CallableStatement对象方法registerOutParameter()registerOutParameter()方法将JDBC数据类型绑定到存储过程并返回预期数据类型。

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

关闭CallableStatement对象

就像关闭其他Statement对象一样,由于同样的原因(节省数据库系统资源),还应该关闭CallableStatement对象。

简单的调用close()方法将执行关闭CallableStatement对象。 如果先关闭Connection对象,它也会关闭CallableStatement对象。 但是,应该始终显式关闭CallableStatement对象,以确保按正确顺序的清理资源。

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

6.JDBC结果集

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

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

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

  • 浏览方法:用于移动光标。

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

  • 更新方法:用于更新当前行的列中的数据。 然后在基础数据库中更新数据。

光标可以基于ResultSet的属性移动。当创建生成ResultSet的相应Statement时,将指定这些属性。

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

  • createStatement(int RSType, int RSConcurrency);

  • prepareStatement(String SQL, int RSType, int RSConcurrency);

  • prepareCall(String sql, int RSType, int RSConcurrency);

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

ResultSet类型

可能的RSType值如下。如果不指定任何ResultSet类型,将自动分配一个TYPE_FORWARD_ONLY值。

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

ResultSet的并发性

可能的RSConcurrency如下。 如果不指定任何并发类型,将自动获得一个CONCUR_READ_ONLY值。

并发 描述
ResultSet.CONCUR_READ_ONLY 创建只读结果集,这是默认值。
ResultSet.CONCUR_UPDATABLE 创建可更新的结果集

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

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

浏览结果集

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

编号 方法 描述
1 public void beforeFirst() throws SQLException 将光标移动到第一行之前
2 public void afterLast() throws SQLException 将光标移动到最后一行之后。
3 public boolean first() throws SQLException 将光标移动到第一行。
4 public void last() throws SQLException 将光标移动到最后一行。
5 public boolean absolute(int row) throws SQLException 将光标移动到指定的行。
6 public boolean relative(int row) throws SQLException 从当前指向的位置,将光标向前或向后移动给定行数。
7 public boolean previous() throws SQLException 将光标移动到上一行。 如果上一行关闭结果集,此方法返回false
8 public boolean next() throws SQLException 将光标移动到下一行。 如果结果集中没有更多行,则此方法返回false
9 public int getRow() throws SQLException 返回光标指向的行号。
10 public void moveToInsertRow() throws SQLException 将光标移动到结果集中的特殊行,该行可用于将新行插入数据库。当前光标位置被记住。
11 public void moveToCurrentRow() throws SQLException 如果光标当前位于插入行,则将光标移回当前行; 否则,此方法什么也不做

查看结果集

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

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

  • 一个是采用列名称。

  • 另一个采用列索引。

例如,如果对查看感兴趣的列包含一个int,则需要使用ResultSet的其中一个getInt()方法 -

序号 方法 描述
1 public int getInt(String columnName) throws SQLException 返回名为columnName的列中当前行中的int值。
2 public int getInt(int columnIndex) throws SQLException 返回指定列索引当前行中的int值。列索引从1开始,意味着行的第一列为1,行的第二列为2,依此类推。

类似地,在八个Java基元类型中的每一个的ResultSet接口中都有get方法,以及常见的类型,如java.lang.Stringjava.lang.Objectjava.net.URL等。

还有一些方法可以获取SQL数据类型java.sql.Date,java.sql.Timejava.sql.TimeStampjava.sql.Clobjava.sql.Blob

更新结果集

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

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

  • 一个是采用列名称。

  • 另一个采用列索引。

例如,要更新结果集当前行的String列,可以使用以下updateString()方法之一:

序号 方法 描述
1 public void updateString(int columnIndex, String s) throws SQLException 将指定列中的String值更改为指定的s值。
2 public void updateString(String columnName, String s) throws SQLException 与前前的方法类似,除了使用列的名称而不是列的索引指定。

有八种基本数据类型的更新方法,以及java.sql包中的StringObjectURL和SQL数据类型。

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

序号 方法 描述
1 public void updateRow() 更新数据库中当前行
2 public void deleteRow() 从数据库中删除当前行
3 public void refreshRow() 刷新结果集中的数据以反映数据库中最近的任何更改。
4 public void cancelRowUpdates() 取消对当前行所做的任何更新。
5 public void insertRow() 在数据库中插入一行。 只有当光标指向插入行时,才能调用此方法。

7.JDBC数据类型

JDBC驱动程序将Java数据类型转换为适当的JDBC类型,然后将其发送到数据库。 它为大多数数据类型提供并使用默认映射。 例如,Java int类型会被转换为SQL INTEGER。 创建默认映射以提供到驱动程序时保持一致性。

下表总结了当调用PreparedStatementCallableStatement对象或ResultSet.updateXXX()方法的setXXX()方法时,将Java数据类型转换为的默认JDBC数据类型。

SQL类型 JDBC/Java类型 setXXX updateXXX
VARCHAR java.lang.String setString updateString
CHAR java.lang.String setString updateString
LONGVARCHAR java.lang.String setString updateString
BIT boolean setBoolean updateBoolean
NUMERIC java.math.BigDecimal setBigDecimal updateBigDecimal
TINYINT byte setByte updateByte
SMALLINT short setShort updateShort
INTEGER int setInt updateInt
BIGINT long setLong updateLong
REAL float setFloat updateFloat
FLOAT float setFloat updateFloat
DOUBLE double setDouble updateDouble
VARBINARY byte[ ] setBytes updateBytes
BINARY byte[ ] setBytes updateBytes
DATE java.sql.Date setDate updateDate
TIME java.sql.Time setTime updateTime
TIMESTAMP java.sql.Timestamp setTimestamp updateTimestamp
CLOB java.sql.Clob setClob updateClob
BLOB java.sql.Blob setBlob updateBlob
ARRAY java.sql.Array setARRAY updateARRAY
REF java.sql.Ref SetRef updateRef
STRUCT java.sql.Struct SetStruct updateStruct

JDBC 3.0增强了对BLOBCLOBARRAYREF数据类型的支持。 ResultSet对象现在具有updateBLOB()updateCLOB()updateArray()updateRef()方法,使您能够直接操作数据库服务器上的相应数据。

setXXX()updateXXX()方法可以将特定的Java类型转换为特定的JDBC数据类型。 方法setObject()updateObject()可以将几乎任何Java类型映射到JDBC数据类型。

ResultSet对象为每个数据类型提供相应的getXXX()方法来检索列值。每个方法都可以使用列名或其序数位置来检索列值。

SQL类型 JDBC/Java类型 setXXX updateXXX
VARCHAR java.lang.String setString getString
CHAR java.lang.String setString getString
LONGVARCHAR java.lang.String setString getString
BIT boolean setBoolean getBoolean
NUMERIC java.math.BigDecimal setBigDecimal getBigDecimal
TINYINT byte setByte getByte
SMALLINT short setShort getShort
INTEGER int setInt getInt
BIGINT long setLong getLong
REAL float setFloat getFloat
FLOAT float setFloat getFloat
DOUBLE double setDouble getDouble
VARBINARY byte[ ] setBytes getBytes
BINARY byte[ ] setBytes getBytes
DATE java.sql.Date setDate getDate
TIME java.sql.Time setTime getTime
TIMESTAMP java.sql.Timestamp setTimestamp getTimestamp
CLOB java.sql.Clob setClob getClob
BLOB java.sql.Blob setBlob getBlob
ARRAY java.sql.Array setARRAY getARRAY
REF java.sql.Ref SetRef getRef
STRUCT java.sql.Struct SetStruct getStruct

日期和时间数据类型

java.sql.Date类映射到SQL DATE类型,java.sql.Timejava.sql.Timestamp类分别映射到SQL TIME和SQL TIMESTAMP数据类型。

以下示例显示了DateTime类如何格式化为标准Java日期和时间值以匹配SQL数据类型要求。

import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.*;
​
public class SqlDateTime {
   public static void main(String[] args) {
      //Get standard date and time
      java.util.Date javaDate = new java.util.Date();
      long javaTime = javaDate.getTime();
      System.out.println("The Java Date is:" + 
             javaDate.toString());
​
      //Get and display SQL DATE
      java.sql.Date sqlDate = new java.sql.Date(javaTime);
      System.out.println("The SQL DATE is: " + 
             sqlDate.toString());
​
      //Get and display SQL TIME
      java.sql.Time sqlTime = new java.sql.Time(javaTime);
      System.out.println("The SQL TIME is: " + 
             sqlTime.toString());
      //Get and display SQL TIMESTAMP
      java.sql.Timestamp sqlTimestamp =
      new java.sql.Timestamp(javaTime);
      System.out.println("The SQL TIMESTAMP is: " + 
             sqlTimestamp.toString());
     }//end main
}//end SqlDateTime
Java

编译并执行上面代码,得到以下结果 -

F:\worksp\jdbc>javac SqlDateTime.java
​
F:\worksp\jdbc>java SqlDateTime
The Java Date is:Wed May 31 23:54:57 CST 2017
The SQL DATE is: 2017-05-31
The SQL TIME is: 23:54:57
The SQL TIMESTAMP is: 2017-05-31 23:54:57.937
​
F:\worksp\jdbc>
Shell

处理NULL值

SQL使用NULL值和Java使用null是不同的概念。 所以,要在Java中处理SQL NULL值,可以使用三种策略 -

  • 避免使用返回原始数据类型的getXXX()方法。

  • 对原始数据类型使用包装类,并使用ResultSet对象的wasNull()方法来测试接收getXXX()方法的返回值的包装器类变量是否应设置为null

  • 使用原始数据类型和ResultSet对象的wasNull()方法来测试接收到由getXXX()方法返回的值的原始变量是否应设置为表示NULL的可接受值。

下面是一个用来处理NULL值的例子 -

Statement stmt = conn.createStatement( );
String sql = "SELECT id, first, last, age FROM Employees";
ResultSet rs = stmt.executeQuery(sql);
​
int id = rs.getInt(1);
if( rs.wasNull( ) ) {
   id = 0;
}

8.JDBC事务

如果JDBC连接处于自动提交模式,默认情况下,则每个SQL语句在完成后都会提交到数据库。

对于简单的应用程序可能没有问题,但是有三个原因需要考虑是否关闭自动提交并管理自己的事务 -

  • 提高性能

  • 保持业务流程的完整性

  • 使用分布式事务

事务能够控制何时更改提交并应用于数据库。 它将单个SQL语句或一组SQL语句视为一个逻辑单元,如果任何语句失败,整个事务将失败。

要启用手动事务支持,而不是使用JDBC驱动程序默认使用的自动提交模式,请调用Connection对象的setAutoCommit()方法。 如果将布尔的false传递给setAutoCommit(),则关闭自动提交。 也可以传递一个布尔值true来重新打开它。

例如,如果有一个名为connConnection对象,请将以下代码关闭自动提交 -

conn.setAutoCommit(false);
Java

提交和回滚

完成更改后,若要提交更改,那么可在连接对象上调用commit()方法,如下所示:

conn.commit( );
Java

否则,要使用连接名为conn的数据库回滚更新,请使用以下代码 -

conn.rollback( );
Java

以下示例说明了如何使用提交和回滚对象 -

try{
   //Assume a valid connection object conn
   conn.setAutoCommit(false);
   Statement stmt = conn.createStatement();
​
   String SQL = "INSERT INTO Employees  " +
                "VALUES (106, 20, 'Rita', 'Tez')";
   stmt.executeUpdate(SQL);  
   //Submit a malformed SQL statement that breaks
   String SQL = "INSERTED IN Employees  " +
                "VALUES (107, 22, 'Sita', 'Singh')";
   stmt.executeUpdate(SQL);
   // If there is no error.
   conn.commit();
}catch(SQLException se){
   // If there is any error.
   conn.rollback();
}
Java

在这种情况下,上述INSERT语句不会成功执行,因为所有操作都被回滚了。

使用保存点

新的JDBC 3.0新添加了Savepoint接口提供了额外的事务控制能力。大多数现代DBMS支持其环境中的保存点,如Oracle的PL/SQL。

设置保存点(Savepoint)时,可以在事务中定义逻辑回滚点。 如果通过保存点(Savepoint)发生错误时,则可以使用回滚方法来撤消所有更改或仅保存保存点之后所做的更改。

Connection对象有两种新的方法可用来管理保存点 -

  • setSavepoint(String savepointName): - 定义新的保存点,它还返回一个Savepoint对象。

  • releaseSavepoint(Savepoint savepointName): - 删除保存点。要注意,它需要一个Savepoint对象作为参数。 该对象通常是由setSavepoint()方法生成的保存点。

有一个rollback (String savepointName)方法,它将使用事务回滚到指定的保存点。

以下示例说明了使用Savepoint对象 -

try{
   //Assume a valid connection object conn
   conn.setAutoCommit(false);
   Statement stmt = conn.createStatement();
​
   //set a Savepoint
   Savepoint savepoint1 = conn.setSavepoint("Savepoint1");
   String SQL = "INSERT INTO Employees " +
                "VALUES (106, 24, 'Curry', 'Stephen')";
   stmt.executeUpdate(SQL);  
   //Submit a malformed SQL statement that breaks
   String SQL = "INSERTED IN Employees " +
                "VALUES (107, 32, 'Kobe', 'Bryant')";
   stmt.executeUpdate(SQL);
   // If there is no error, commit the changes.
   conn.commit();
​
}catch(SQLException se){
   // If there is any error.
   conn.rollback(savepoint1);
}
Java

在这种情况下,上述INSERT语句都不会成功,因为所有操作都被回滚了。

猜你喜欢

转载自blog.csdn.net/m0_63324772/article/details/123046511