【计理01组07号】JDBC入门教程

database

博客推行版本更新,成果积累制度,已经写过的博客还会再次更新,不断地琢磨,高质量高数量都是要追求的,工匠精神是学习必不可少的精神。因此,大家有何建议欢迎在评论区踊跃发言,你们的支持是我最大的动力,你们敢投,我就敢肝

认识JDBC

JDBC 简介

JDBC 的全称是 Java Database Connectivity,叫做 Java 数据库连接。它包括了一组与数据库交互的 api,还有与数据库进行通信的驱动程序。

我们要写涉及到数据库的程序,是通过 C 语言或者 C++ 语言直接访问数据库的接口,如下图所示。

对于不同的数据库,我们需要知道不同数据库对外提供的系统 API,这就影响了我们程序的扩展和跨平台的实现。

那么有没有一种方法来对不同的数据库接口进行统一呢?那么这里木木就要向大家介绍分层的思想。我们只需要和最上层接口进行交互,剩下的部分就交给其他各层去处理,我们的任务就变的轻松简单许多。

ODBC 是 Open Database Connect 即开放数据库互连的简称,它是微软于 1991 年提出的一个用于访问数据库的统一接口标准,是应用程序和数据库系统之间的中间层。我们的应用程序在调用数据的时候,就无需去管具体的数据库,直接由应用程序访问 ODBC 就可以了。

而在 Java 上面只有一种数据库连接统一接口——JDBC。JDBC 为数据库开发人员提供了一个标准的 API,据此可以构建更高级的工具和接口使数据库开发人员能够用纯 Java API 编写数据库应用程序。

JDBC SQL 语法

请参考博客【计理01组05号】MySql基础课程

JDBC 环境设置

在本教程中,我们将使用 MySQL 数据库。实验楼已经为大家安装好了 mysql,无需大家再次安装。如需系统学习 mysql 请参考实验楼 mysql 的教程。在此我们回顾一下 mysql 的一些基本操作。

启动 mysql 服务器

sudo service mysql start 

连接与断开数据库

连接数据库(实验楼中密码环境为空):

mysql -u root 

退出数据库:

mysql> exit

创建 JDBC 应用程序

接下来我们来学习如何编写一个真正的 JDBC 程序。我们先来浏览一下它的步骤,然后我们在后面的代码中作详细地讲解:

1、导入 JDBC 驱动 打开 terminal,输入命令获取驱动包

wget https://labfile.oss.aliyuncs.com/courses/110/mysql-connector-java-5.1.47.jar 

有了驱动就可以与数据库打开一个通信通道

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

3、执行查询:需要使用类型声明的对象建立并提交一个 SQL 语句到数据库

4、从结果集中提取数据:要求使用适当的关于 ResultSet.getXXX() 方法来检索结果集的数据

5、处理结果集:对得到的结果集进行相关的操作

6、清理环境:需要明确地关闭所有的数据库资源,释放内存

例子:

1、先创建数据库和相应的内容:

sudo service mysql start

mysql -u root

create database EXAMPLE;

use EXAMPLE

create table Students

(

id int not null,

age int not null,

name varchar(255),

primary key(id)

);

insert into Students values(1,18,"Tom"),

(2,20,"Aby"),(4,20,"Tomson");

2、java 程序访问数据库

我们在project目录下创建文件JdbcTest.java

import java.sql.*;

public class JdbcTest {

// JDBC 驱动器名称 和数据库地址

static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";

//数据库的名称为 EXAMPLE

static final String DB_URL = "jdbc:mysql://localhost/EXAMPLE";

// 数据库用户和密码

static final String USER = "root";

static final String PASS = "";

public static void main(String[] args) {

Connection conn = null;

Statement stmt = null;

try{

//注册 JDBC 驱动程序

Class.forName("com.mysql.jdbc.Driver");

//打开连接

System.out.println("Connecting to database...");

conn = DriverManager.getConnection(DB_URL,USER,PASS);

//执行查询

System.out.println("Creating statement...");

stmt = conn.createStatement();

String sql;

sql = "SELECT id, name, age FROM Students";

ResultSet rs = stmt.executeQuery(sql);

//得到和处理结果集

while(rs.next()){

//检索

int id = rs.getInt("id");

int age = rs.getInt("age");

String name = rs.getString("name");

//显示

System.out.print("ID: " + id);

System.out.print(", Age: " + age);

System.out.print(", Name: " + name);

System.out.println();

}

//清理环境

rs.close();

stmt.close();

conn.close();

}catch(SQLException se){

// JDBC 操作错误

se.printStackTrace();

}catch(Exception e){

// Class.forName 错误

e.printStackTrace();

}finally{

//这里一般用来关闭资源的

try{

if(stmt!=null)

stmt.close();

}catch(SQLException se2){

}

try{

if(conn!=null)

conn.close();

}catch(SQLException se){

se.printStackTrace();

}

}

System.out.println("Goodbye!");

}

}

3、最后我们来看看结果吧:

使用命令编译并运行

javac -cp .:mysql-connector-java-5.1.47.jar JdbcTest.java

java -cp .:mysql-connector-java-5.1.47.jar JdbcTest

JDBC基础

JDBC 结构

首先我们先来回顾一下上节实验课的内容。JDBC 全称为 Java Database Connectivity,中文名称为 Java 数据库连接,它是一种用于执行 SQL 语句的 Java API, 它由一组用 Java 编程语言编写的类和接口组成。JDBC 为数据库开发人员提供了一个标准的 API, 使他们能够用纯 Java API 来编写数据库应用程序。

JDBC API 是 Java 开发工具包 (JDK) 的组成部份,由三部分组成:

  • JDBC 驱动程序管理器
  • JDBC 驱动程序测试工具包

  • JDBC-ODBC 桥

a. JDBC 驱动程序管理器是 JDBC 体系结构的支柱,其主要作 用是把 Java 应用程序连接到正确的 JDBC 驱动程序上。

b. JDBC 驱动程序测试工具包为 JDBC 驱动程序的运行提供一定的可信度,只有通过 JDBC 驱动程序测试包的驱动程序才被认为是符合 JDBC 标准的。

c. JDBC-ODBC 桥使 ODBC 驱动程序可被用作 JDBC 驱动程序。其目标是为方便实现访问某些不常见的 DBMS(数据库管理系统), 它的实现为 JDBC 的快速发展提供了一条途径。

JDBC 既支持数据库访问的两层模型,也支持三层模型。

1、数据库访问的两层模型

2、数据库访问的三层模型

JDBC 驱动类型

JDBC 驱动程序实现 JDBC API 中定义的接口,用于与数据库服务器进行交互。JDBC 驱动程序可以打开数据库连接,并通过发送 SQL 或数据库命令,然后在收到结果与 Java 进行交互。

JDBC 驱动程序的实现因为各种各样的操作系统和 Java 运行在不同的硬件平台上而不同。JDBC 驱动类型可以归结为以下几类:

  • JDBC-ODBC 桥接 ODBC 驱动程序:它是将 JDBC 翻译成 ODBC, 然后使用一个 ODBC 驱动程序与数据库进行通信。当 Java 刚出来时,这是一个有用的驱动程序,因为大多数的数据库只支持 ODBC 访问,但现在建议使用此类型的驱动程序仅用于实验用途或在没有其他选择的情况(注意:从 JDK1.8 开始 ODBC 已经被移除)。

  • 本地 API 用 Java 来编写的驱动程序:这种类型的驱动程序把客户机 API 上的 JDBC 调用转换为 Oracle、Sybase、 Informix、DB2 或其它 DBMS 的调用。

  • JDBC 网络纯 Java 驱动程序:这种驱动程序将 JDBC 转换为与 DBMS 无关的网络协议,这是最为灵活的 JDBC 驱动程序。它是一个三层的方法来访问数据库,在 JDBC 客户端使用标准的网络套接字与中间件应用服务器进行通信。然后由中间件应用服务器进入由 DBMS 所需要的的调用格式转换,并转发到数据库服务器。

  • 本地协议纯 Java 驱动程序:这种类型的驱动程序将 JDBC 调用直接转换为 DBMS 所使用的专用网络协议。是 Intranet 访问的一个很实用的解决方法。它是直接与供应商的数据库进行通信,通过 socket 连接一个纯粹的基于 Java 的驱动程序。这是可用于数据库的最高性能的驱动程序,并且通常由供应商本身提供。

MySQL 的 Connector/Java 的驱动程序是一个类型 4 驱动程序。因为他们的网络协议的专有性的,数据库厂商通常提供类型 4 的驱动程序。

通常情况下如果正在访问一个类型的数据库,如 Oracle,Sybase 或 IBM,首选驱动程序是类型 4。

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

第 2 类驱动程序是在类型 3 或类型 4 驱动程序还没有提供数据库的情况下显得非常有用。

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

JDBC 连接数据库

涉及到建立一个 JDBC 连接的编程主要有四个步骤:

  1. 导入 JDBC 驱动: 只有拥有了驱动程序我们才可以注册驱动程序完成连接的其他步骤。
  2. 注册 JDBC 驱动程序:这一步会导致 JVM 加载所需的驱动类实现到内存中,然后才可以实现 JDBC 请求。

  1. 数据库 URL 指定:创建具有正确格式的地址,指向到要连接的数据库。
  2. 创建连接对象:最后,代码调用 DriverManager 对象的 getConnection() 方法来建立实际的数据库连接。

接下来我们便详细讲解这四步。

导入 JDBC 驱动

我们已经在上一节课为同学们就相应的方法做了介绍,不清楚的同学可以查看上一节实验课的内容。

注册 JDBC 驱动程序

我们在使用驱动程序之前,必须注册你的驱动程序。注册驱动程序的本质就是将我们将要使用的数据库的驱动类文件动态的加载到内存中,然后才能进行数据库。比如我们使用的 Mysql 数据库。我们可以通过以下两种方式来注册我们的驱动程序。

1、方法 1——Class.forName():

动态加载一个类最常用的方法是使用 Java 的 Class.forName() 方法,通过使用这个方法来将数据库的驱动类动态加载到内存中,然后我们就可以使用。

使用 Class.forName() 来注册 Mysql 驱动程序:

try {

Class.forName("com.mysql.jdbc.Driver");

}

catch(ClassNotFoundException ex) {

System.out.println("Error: unable to load driver class!");

System.exit(1);

}

2、方法 2——DriverManager.registerDriver():

   Driver driver = new com.mysql.jdbc.Driver();

DriverManager.registerDriver(driver);

指定数据库连接 URL

当加载了驱动程序,便可以使用 DriverManager.getConnection() 方法连接到数据库了。

这里给出 DriverManager.getConnection() 三个重载方法:

getConnection(String url)

getConnection(String url, Properties prop)

getConnection(String url, String user, String password)

数据库的 URL 是指向数据库地址。下表列出了下来流行的 JDBC 驱动程序名和数据库的 URL。

RDBMS

JDBC 驱动程序的名称

URL

Mysql

com.mysql.jdbc.Driver

jdbc:mysql://hostname/ databaseName

Oracle

oracle.jdbc.driver.OracleDriver

jdbc:oracle:thin:@hostname:port Number:databaseName

DB2

COM.ibm.db2.jdbc.net.DB2Driver

jdbc:db2:hostname:port Number/databaseName

Sybase

com.sybase.jdbc.SybDriver

jdbc:sybase:Tds:hostname: port Number/databaseName

创建连接对象

下面三种形式 DriverManager.getConnection() 方法来创建一个连接对象,以 Mysql 为例。getConnection() 最常用形式要求传递一个数据库 URL,用户名 username 和密码 password。

1、使用数据库 URL 的用户名和密码

String URL = "jdbc:mysql://localhost/EXAMPLE";

String USER = "username";

String PASS = "password"

Connection conn = DriverManager.getConnection(URL, USER, PASS);

2、只使用一个数据库 URL

然而,在这种情况下,数据库的 URL,包括用户名和密码。

String URL = "jdbc:mysql://localhost/EXAMPLE?user=root&password=0909";

//Mysql URL 的参数设置详细可以查阅相关资料

Connection conn = DriverManager.getConnection(URL);

3、使用数据库的 URL 和一个 Properties 对象

import java.util.*;

String URL = "jdbc:mysql://localhost/EXAMPLE";

Properties pro = new Properties( );

//Properties 对象,保存一组关键字-值对

pro.put( "user", "root" );

pro.put( "password", "" );

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

4、关闭 JDBC 连接

conn.close();

JDBC接口

JDBC 接口概述

我们上节课学习了如何连接数据库,当我们连接上了数据库后,就需要通过 sql 语句对数据库进行操作。随着 Java 语言应用面的逐步拓宽,Sun 公司开发了一个标准的 SQL 数据库访问接口———JDBC API。它可以使 Java 编程人员通过一个一致的接口,访问多种关系数据库。而今天我们就来学习一下,如何利用 JDBC 的一些核心 API 与数据库进行交互。

通过使用 JDBC Statement, CallableStatement 和 PreparedStatement 接口定义的方法和属性,使可以使用 SQL 或 PL/SQL 命令和从数据库接收数据。它们还定义了许多方法,帮助消除 Java 和数据库之间数据类型的差异。

接口

应用场景

Statement

当在运行时使用静态 SQL 语句时(Statement 接口不能接收参数)

CallableStatement

当要访问数据库中的存储过程时(CallableStatement 对象的接口还可以接收运行时输入参数)

PreparedStatement

当计划多次使用 SQL 语句时(PreparedStatement 接口接收在运行时输入参数)

Statement

我们要使用 Statement 接口,第一步肯定是创建一个 Statement 对象了。我们需要使用 Connection 对象的 createStatement() 方法进行创建。

Statement stmt = null;

try {

stmt = conn.createStatement( );

. . .

}

catch (SQLException e) {

. . .

}

finally {

. . .

}

一旦创建了一个 Statement 对象,我们就可以用它来执行 SQL 语句了,首先我们先来看看 Statement 里面有哪些方法吧!

方法

说明

boolean execute(String SQL)

如果 ResultSet 对象可以被检索返回布尔值 true,否则返回 false。使用这个方法来执行 SQL DDL 语句,或当需要使用真正的动态 SQL

int executeUpdate(String SQL)

用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQLDDL(数据定义语言)语句。返回值是一个整数,指示受影响的行数(即更新计数)

ResultSet executeQuery(String SQL)

返回 ResultSet 对象。用于产生单个结果集的语句,例如 SELECT 语句

正如关闭一个 Connection 对象来释放数据库连接资源,出于同样的原因,也应该关闭 Statement 对象。

Statement stmt = null;

try {

stmt = conn.createStatement( );

. . .

}

catch (SQLException e) {

. . .

}

finally {

stmt.close();

}

注:如果关闭了 Connection 对象首先它会关闭 Statement 对象,然而应该始终明确关闭 Statement 对象,以确保正确的清除。

PreparedStatement

PreparedStatement 接口扩展了 Statement 接口,有利于高效地执行多次使用的 SQL 语句。我们先来创建一个 PreparedStatement 对象。 Statement 为一条 SQL 语句生成执行计划。如果要执行两条 SQL 语句,会生成两个执行计划。一万个查询就生成一万个执行计划!

select colume from table where colume=1;

select colume from table where colume=2;

PreparedStatement 用于使用绑定变量重用执行计划。

select colume from table where colume=:x;

通过 set 不同数据,只需要生成一次执行计划,并且可以重用。

PreparedStatement pstmt = null;

try {

/*

在 JDBC 中所有的参数都被代表?符号,这是已知的参数标记。在执行 SQL 语句之前,必须提供值的每一个参数。

*/

String SQL = "Update Students SET age = ? WHERE id = ?";

pstmt = conn.prepareStatement(SQL);

. . .

}

/*

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

*/

catch (SQLException e) {

. . .

}

finally {

//同理,我们需要关闭 PreparedStatement 对象

pstmt.close();

}

说了这么多,我们还是来看代码吧。即上一次我们创建的数据库 EXAMPLE,我们继续在 Test 项目下修改 JdbcTest.java:

import java.sql.*;

public class JdbcTest {

// JDBC 驱动器的名称和数据库地址

static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";

static final String DB_URL = "jdbc:mysql://localhost/EXAMPLE";

static final String USER = "root";

static final String PASS = "";

public static void main(String[] args) {

Connection conn = null;

PreparedStatement stmt = null;

try{

//注册 JDBC 驱动器

Class.forName("com.mysql.jdbc.Driver");

//打开连接

System.out.println("Connecting to database...");

conn = DriverManager.getConnection(DB_URL,USER,PASS);

//执行查询

System.out.println("Creating statement...");

//这里我们要更改一个同学的年龄,参数待定

String sql = "UPDATE Students set age=? WHERE id=?";

stmt = conn.prepareStatement(sql);

//将值绑定到参数,参数从左至右序号为 1,2...

stmt.setInt(1, 22); // 绑定 age 的值(序号为 1)

stmt.setInt(2, 1); // 绑定 ID 的值

// 更新 ID 为 1 的同学的年龄

int rows = stmt.executeUpdate();

System.out.println("被影响的行数 : " + rows );

// 查询所有记录,并显示。

sql = "SELECT id, name, age FROM Students";

ResultSet rs = stmt.executeQuery(sql);

//处理结果集

while(rs.next()){

//检索

int id = rs.getInt("id");

int age = rs.getInt("age");

String name = rs.getString("name");

//显示

System.out.print("ID: " + id);

System.out.print(", Age: " + age);

System.out.print(", Name: " + name);

System.out.println();

}

//清理

rs.close();

stmt.close();

conn.close();

}catch(SQLException se){

se.printStackTrace();

}catch(Exception e){

e.printStackTrace();

}finally{

try{

if(stmt!=null)

stmt.close();

}catch(SQLException se2){

}

try{

if(conn!=null)

conn.close();

}catch(SQLException se){

se.printStackTrace();

}

}

System.out.println("Goodbye!");

}

}

编译运行:

javac -cp .:mysql-connector-java-5.1.47.jar JdbcTest.java

java -cp .:mysql-connector-java-5.1.47.jar JdbcTest

运行结果:

CallableStatement

CallableStatement 对象为所有的 DBMS 提供了一种以标准形式调用存储过程的方法。存储过程储存在数据库中。对储存过程的调用是 CallableStatement 对象所含的内容。三种类型的参数有:IN,OUT 和 INOUT。PreparedStatement 对象只使用 IN 参数。 CallableStatement 对象可以使用所有三个

参数

描述

IN

它的值是在创建 SQL 语句时未知的参数,将 IN 参数传给 CallableStatement 对象是通过 setXXX() 方法完成的

OUT

其值由它返回的 SQL 语句提供的参数。从 OUT 参数的 getXXX() 方法检索值

INOUT

同时提供输入和输出值的参数,绑定的 setXXX() 方法的变量,并使用 getXXX() 方法检索值

在 JDBC 中调用存储过程的语法如下所示。注意,方括号表示其间的内容是可选项;方括号本身并不是语法的组成部份。

{call 存储过程名 [(?, ?, ...)]} 

返回结果参数的过程的语法为:

{? = call 存储过程名 [(?, ?, ...)]} 

不带参数的存储过程的语法类似:

{call 存储过程名} 

CallableStatement 对象是用 Connection 方法 prepareCall 创建的。

CallableStatement cstmt = null;

try {

String SQL = "{call getEXAMPLEName (?, ?)}";

cstmt = conn.prepareCall (SQL);

. . .

}

catch (SQLException e) {

. . .

}

finally {

cstmt.close();

}

好了,CallableStatement 接口就不再详细地讲解了,同学们可以自己查阅相关的资料,对 CallableStatement 进行深入学习。

JDBC结果集

ResultSet 介绍

结果集通常是通过执行查询数据库的语句生成,表示数据库查询结果的数据表。ResultSet 对象具有指向其当前数据行的光标。最初,光标被置于第一行之前。next 方法将光标移动到下一行;因为该方法在 ResultSet 对象没有下一行时返回 false,所以可以在 while 循环中使用它来迭代结果集。光标可以方便我们对结果集进行遍历。默认的 ResultSet 对象不可更新,仅有一个向前移动的光标。因此,只能迭代它一次,并且只能按从第一行到最后一行的顺序进行。

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

  • 导航方法:用于移动光标
  • 获取方法:用于查看当前行的光标所指向的列中的数据

  • 更新方法:用于更新当前行的列中的数据

JDBC 提供下列连接方法来创建所需的 ResultSet 语句:

createStatement(int RSType, int RSConcurrency);

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

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

RSType 表示 ResultSet 对象的类型,RSConcurrency 是 ResultSet 常量,用于指定一个结果集是否为只读或可更新。

ResultSet 的类型,如果不指定 ResultSet 类型,将自动获得一个是 TYPE_FORWARD_ONLY:

类型

描述

ResultSet.TYPE_FORWARD_ONLY

游标只能向前移动的结果集

ResultSet.TYPE_SCROLL_INSENSITIVE

游标可以向前和向后滚动,但不及时更新,就是如果数据库里的数据修改过,并不在 ResultSet 中反应出来

ResultSet.TYPE_SCROLL_SENSITIVE

游标可以向前和向后滚动,并及时跟踪数据库的更新,以便更改 ResultSet 中的数据

并发性的 ResultSet,如果不指定任何并发类型,将自动获得一个为 CONCUR_READ_ONLY

并发

描述

ResultSet.CONCUR_READ_ONLY

创建结果集只读。这是默认的

ResultSet.CONCUR_UPDATABLE

创建一个可更新的结果集

如初始化一个 Statement 对象来创建一个双向、可更新的 ResultSet 对象:

try {

Statement stmt = conn.createStatement(

ResultSet.TYPE_SCROLL_INSENSITIVE,

ResultSet.CONCUR_UPDATABLE);

}

catch(Exception ex) {

....

}

finally {

....

}

导航

我们在上面已经知道了,导航方法是用于移动光标的。我们先来看一看,在 ResultSet 接口中有哪些方法会涉及光标的移动。

方法

说明

public void beforeFirst() throws SQLException

将光标移动到正好位于第一行之前

public void afterLast() throws SQLException

将光标移动到刚刚结束的最后一行

public boolean first() throws SQLException

将光标移动到第一行

public void last() throws SQLException

将光标移动到最后一行

public boolean absolute(int row) throws SQLException

将光标移动到指定的行

public boolean relative(int row) throws SQLException

从它目前所指向向前或向后移动光标行的给定数量

public boolean previous() throws SQLException

将光标移动到上一行。上一行关闭的结果集此方法返回 false

public boolean next() throws SQLException

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

public int getRow() throws SQLException

返回的行号,该光标指向的行

public void moveToInsertRow() throws SQLException

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

public void moveToCurrentRow() throws SQLException

移动光标返回到当前行,如果光标在当前插入行,否则,这个方法不执行任何操作

什么也不说了,我们还是看代码吧,代码继续再上节实验的基础上修改!

import java.sql.*;

public class JdbcTest {

// JDBC 驱动器名称 和数据库地址

static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";

//数据库的名称为 EXAMPLE

static final String DB_URL = "jdbc:mysql://localhost/EXAMPLE";

// 数据库用户和密码

static final String USER = "root";

static final String PASS = "";

public static void main(String[] args) {

Connection conn = null;

Statement stmt = null;

try{

//注册 JDBC 驱动程序

Class.forName("com.mysql.jdbc.Driver");

//打开连接

System.out.println("Connecting to database...");

conn = DriverManager.getConnection(DB_URL,USER,PASS);

System.out.println("Creating statement...");

//创建所需的 ResultSet,双向,只读

stmt = conn.createStatement(

ResultSet.TYPE_SCROLL_INSENSITIVE,

ResultSet.CONCUR_READ_ONLY);

String sql;

sql = "SELECT id, name, age FROM Students";

ResultSet rs = stmt.executeQuery(sql);

// 将光标移到最后一行

System.out.println("Moving cursor to the last...");

rs.last();

//处理结果集

System.out.println("Displaying record...");

int id = rs.getInt("id");

int age = rs.getInt("age");

String name = rs.getString("name");

//显示

System.out.print("ID: " + id);

System.out.print(", Age: " + age);

System.out.print(", Name: " + name);

System.out.println();

// 将光标移到第一行

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

rs.first();

System.out.println("Displaying record...");

id = rs.getInt("id");

age = rs.getInt("age");

name = rs.getString("name");

//显示

System.out.print("ID: " + id);

System.out.print(", Age: " + age);

System.out.print(", Name: " + name);

//将光标移至下一行

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

rs.next();

System.out.println("Displaying record...");

id = rs.getInt("id");

age = rs.getInt("age");

name = rs.getString("name");

// 显示

System.out.print("ID: " + id);

System.out.print(", Age: " + age);

System.out.print(", Name: " + name);

rs.close();

stmt.close();

conn.close();

}catch(SQLException se){

se.printStackTrace();

}catch(Exception e){

e.printStackTrace();

}finally{

try{

if(stmt!=null)

stmt.close();

}catch(SQLException se2){

}

try{

if(conn!=null)

conn.close();

}catch(SQLException se){

se.printStackTrace();

}

}

System.out.println("Goodbye!");

}

}

编译运行:

javac -cp .:mysql-connector-java-5.1.47.jar JdbcTest.java

java -cp .:mysql-connector-java-5.1.47.jar JdbcTest

运行结果:

获取

ResultSet 接口中我们经常使用 get 方法来查看结果集。

方法

说明

public int getInt(String columnName) throws SQLException

当前行中名为 ColumnName 列的值

public int getInt(int columnIndex) throws SQLException

当前行中指定列的索引的值。列索引从 1 开始,意味着一个行的第一列是 1,行的第二列是 2,依此类推

当然还有 getString() 等等。

代码示例参看上面的示例。

更新

更新的方法如下:

方法

说明

public void updateString(int columnIndex, String s) throws SQLException

指定列中的字符串更改为 s 的值

public void updateString(String columnName, String s) throws SQLException

类似于前面的方法,不同之处在于由它的名称,而不是它的索引指定的列

类似的还有 updateDouble() 等等。

我们在更新了结果集中的内容,当然需要更新一下数据库了。我们可以调用下面的方法更新数据库。

方法

说明

public void updateRow()

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

public void deleteRow()

从数据库中删除当前行

public void refreshRow()

刷新在结果集的数据,以反映最新变化在数据库中

public void cancelRowUpdates()

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

public void insertRow()

插入一行到数据库中。当光标指向插入行此方法只能被调用

具体的例子我们便留在作业里吧,我们这里对上面的方法做一个小小的举例:

Statement stmt = conn.createStatement(

ResultSet.TYPE_SCROLL_INSENSITIVE,

ResultSet.CONCUR_UPDATABLE);

String sql = "SELECT id, name, age FROM Students";

ResultSet rs = stmt.executeQuery(sql);

//结果集中插入新行

rs.moveToInsertRow();

rs.updateInt("id",5);

rs.updateString("name","John");

rs.updateInt("age",21);

//更新数据库

rs.insertRow();

JDBC数据类型与事务

JDBC 数据类型

我们知道 Java 语言中的数据类型和 SQL 语言的数据类型有一定的差别,我们编写的 Java 程序在与数据库交互的时候,往往需要利用 JDBC 驱动程序将 Java 数据类型转换为相应的 JDBC 类型。这种转换过程默认情况下采用映射的方式。比如一个 Java 整型转换为 SQL INTEGER 类型。

下表总结了 Java 数据类型转换为调用 PreparedStatement 中的 setXXX() 方法或 CallableStatement 对象或 ResultSet.updateXXX() 方法的默认 JDBC 数据类型。同时我们在上一节实验课中知道,ResultSet 对象为每个数据类型来检索列值对应了一个 getter 方法,我们将它一并列在下面:

SQL

JDBC/Java

setter

updater

getter

VARCHAR

java.lang.String

setString

updateString

getString

CHAR

java.lang.String

setString

updateString

getString

LONGVARCHAR

java.lang.String

setString

updateString

getString

BIT

boolean

setBoolean

updateBoolean

getBoolean

NUMERIC

java.math.BigDecimal

setBigDecimal

updateBigDecimal

getBigDecimal

TINYINT

byte

setByte

updateByte

getByte

SMALLINT

short

setShort

updateShort

getShort

INTEGER

int

setInt

updateInt

getInt

BIGINT

long

setLong

updateLong

getLong

REAL

float

setFloat

updateFloat

getFloat

FLOAT

float

setFloat

updateFloat

getFloat

DOUBLE

double

setDouble

updateDouble

getDouble

VARBINARY

byte[]

setBytes

updateBytes

getBytes

BINARY

byte[]

setBytes

updateBytes

getBytes

DATE

java.sql.Date

setDate

updateDate

getDate

TIME

java.sql.Time

setTime

updateTime

getTime

TIMESTAMP

java.sql.Timestamp

setTimestamp

updateTimestamp

getTimestamp

CLOB

java.sql.Clob

setClob

updateClob

getClob

BLOB

java.sql.Blob

setBlob

updateBlob

getBlob

ARRAY

java.sql.Array

setARRAY

updateARRAY

getARRAY

REF

java.sql.Ref

setRef

updateRef

getRef

STRUCT

java.sql.Struct

setStruct

updateStruct

getStruct

java.sql.Date,以及 java.sql.Time 和 java.sql.Timestamp 类映射分别到 SQL DATE、SQL TIME 和 SQL TIMESTAMP 数据类型:

project目录下新建一个类Test.java

public class Test {

public static void main(String[] args) {

//获取日期和时间格式

//为了和下面 SQL 的日期做对比所以直接写明是 java.util.Date 类

//我们也可以引入 java.util.Date 包,然后声明为 Date 类

java.util.Date javaDate = new java.util.Date();

long javaTime = javaDate.getTime();

System.out.println("The Java Date is:" +

javaDate.toString());

//获取 SQL 的日期

java.sql.Date sqlDate = new java.sql.Date(javaTime);

System.out.println("The SQL DATE is: " +

sqlDate.toString());

//获取 SQL 的时间

java.sql.Time sqlTime = new java.sql.Time(javaTime);

System.out.println("The SQL TIME is: " +

sqlTime.toString());

//获取 SQL 的时间戳

java.sql.Timestamp sqlTimestamp =

new java.sql.Timestamp(javaTime);

System.out.println("The SQL TIMESTAMP is: " +

sqlTimestamp.toString());

}

}

编译运行:

javac -cp .:mysql-connector-java-5.1.47.jar Test.java

java -cp .:mysql-connector-java-5.1.47.jar Test

运行结果:

上面表格中的方法同学们可以参看我们之前的所有实例,理解数据库中的数据类型与 java 中数据类型的异同。

JDBC 事务

我们在编写 java 程序的时候,在默认情况下,JDBC 连接是在自动提交模式下,即每个 SQL 语句都是在其完成时提交到数据库。但有时候我们为了提高程序运行的性能或者保持业务流程的完整性,以及使用了分布式事务管理方式,这个时候我们可能想关闭自动提交而自己管理和控制自己的事务。

让多条 SQL 在一个事务中执行,并且保证这些语句是在同一时间共同执行的时候,我们就应该为这多条语句定义一个事务。一个事务是把单个 SQL 语句或一组 SQL 语句作为一个逻辑单元,并且如果事务中任何语句失败,则整个事务失败。

如果我们要启动一个事务,而不是让 JDBC 驱动程序默认使用 auto-commit 模式支持。这个时候我们就要使用 Connection 对象的 setAutoCommit() 方法。我们传递一个布尔值 false 到 setAutoCommit() 中,就可以关闭自动提交。反之我们传入一个 true 便将其重新打开。

例如:

Connection conn = null;

conn = DriverManager.getConnection(URL);

//关闭自动提交

conn.setAutoCommit(false);

我们关闭了自动提交后,如果我们要提交数据库更改怎么办呢?这时候就要用到我们的提交和回滚了。我们要提交更改,可以调用 commit() 方法:

conn.commit(); 

尤其不要忘记,在 catch 块内添加回滚事务,表示操作出现异常,撤销事务:

conn.rollback();

JDBC处理

JDBC 异常处理

我们写了这么多的代码了同学们对异常处理是不是已经很熟悉了呢?

异常处理,顾名思义可以处理在受控制的方式下的异常情况。当程序在运行的过程中并没有按照我们的预期情况执行,将会引发异常。当程序异常的时候,当前执行的程序就会立即停止,并且重定向到最近的适用的 catch 子句中,如果没有适用的 catch 子句存在,那么程序结束。

JDBC 的异常处理非常类似于 Java Exception 处理。JDBC 最常见的异常处理的是 java.sql.SQLException,所以今天我们就来学习 SQLException 方法。

方法

描述

getErrorCode()

获取此 SQLException 对象的特定于供应商的异常代码

getNextException()

通过 setNextException(SQLException ex) 获取链接到此 SQLException 对象的异常

getSQLState()

获取此 SQLException 对象的 SQLState。对于 JDBC 驱动程序的错误,没有有用的信息从该方法返回。对于一个数据库错误,则返回五位 XOPEN SQLSTATE 代码。这种方法可以返回 null

iterator()

返回在链接的 SQLExceptions 上进行迭代的迭代器

setNextException(SQLException ex)

将 SQLException 对象添加到链接的末尾

通过利用从 Exception 对象捕获异常的信息,适当地继续运行程序。示例这里就不给出了,同学们可以去参看以前的代码。

JDBC 批量处理

批处理允许将相关的 SQL 语句组合成一个批处理和一个调用数据库提交。还记得我们学习 JDBC 事务的知识吗?今天的课程实质上和事务是一致的。

当一次发送多个 SQL 语句到数据库,可以减少通信开销的数额,从而提高了性能。不过 JDBC 驱动程序不需要支持此功能。应该使用 DatabaseMetaData.supportsBatchUpdates() 方法来确定目标数据库支持批量更新处理。如果你的 JDBC 驱动程序支持此功能的方法返回 true。

接下来我们来看看如何进行批处理操作:

  1. 使用 createStatement() 方法创建一个 Statement 对象
  2. 设置使用自动提交为 false

  1. 添加任意多个 SQL 语句到批量处理,使用 addBatch() 方法
  2. 使用 executeBatch() 方法,将返回一个整数数组,数组中的每个元素代表了各自的更新语句的更新计数

  1. 最后,提交使用 commit() 方法的所有更改

我们来看看示例:

// 创建 statement 对象

Statement stmt = conn.createStatement();

// 关闭自动提交

conn.setAutoCommit(false);

// 创建 SQL 语句

String SQL = "INSERT INTO Students (id, name, age) VALUES(6,"Mike", 21)";

// 将 SQL 语句添加到批处理中

stmt.addBatch(SQL);

// 创建更多的 SQL 语句

String SQL = "INSERT INTO Students (id, name, age) VALUES(7, "Angle", 23)";

// 将 SQL 语句添加到 批处理中

stmt.addBatch(SQL);

// 创建整数数组记录更新情况

int[] count = stmt.executeBatch();

//提交更改

conn.commit();

当然我们也可以使用 prepareStatement 对象进行批处理操作,SQL 语句依然可以使用占位符,示例如下:

// 创建 SQL 语句

String SQL = "INSERT INTO Employees (id, name, age) VALUES(?, ?, ?)";

// 创建 PrepareStatement 对象

PreparedStatemen pstmt = conn.prepareStatement(SQL);

//关闭自动连接

conn.setAutoCommit(false);

// 绑定参数

pstmt.setInt( 1, 8 );

pstmt.setString( 2, "Cindy" );

pstmt.setInt( 3, 17 );

// 添入批处理

pstmt.addBatch();

// 绑定参数

pstmt.setInt( 1, 9 );

pstmt.setString( 2, "Jeff" );

pstmt.setInt( 3, 22 );

// 添入批处理

pstmt.addBatch();

//创建数组记录更改

int[] count = pstmt.executeBatch();

//提交更改

conn.commit();

在黑夜里梦想着光,心中覆盖悲伤,在悲伤里忍受孤独,空守一丝温暖。

我的泪水是无底深海,对你的爱已无言,相信无尽的力量,那是真爱永在。

我的信仰是无底深海,澎湃着心中火焰,燃烧无尽的力量,那是忠诚永在

以上是 【计理01组07号】JDBC入门教程 的全部内容, 来源链接: utcz.com/z/536314.html

回到顶部