JDBC 指 Java 数据库连接,是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库。
JDBC API 库包含下面提到的每个任务,都是与数据库相关的常用用法。
从根本上来说,JDBC 是一种规范,它提供了一套完整的接口,允许便携式访问到底层数据库,因此可以用 Java 编写不同类型的可执行文件,例如:
所有这些不同的可执行文件就可以使用 JDBC 驱动程序来访问数据库,这样可以方便的访问数据。
JDBC 具有 ODBC 一样的性能,允许 Java 程序包含与数据库无关的代码。

JDBC API: 提供了应用程序对 JDBC 管理器的连接。
1.下载JDBC-MySQL官方驱动

2.将JDBC驱动加入到环境变量中

3.示例代码
package com.company;
//第一步:导入必须的包
import java.sql.*;
public class Main {
//第二步:说明JDBC驱动的名称和数据库的地址
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://localhost:3306/test";
//第三步:说明数据库的认证账户及密码
static final String USER = "root";
static final String PASS = "123456";
public static void main(String[] args) {
//第四步:注册JDBC驱动
try {
Class.forName(JDBC_DRIVER);
} catch (ClassNotFoundException e) {
//这里会发生类没有找到的异常!
e.printStackTrace();
}
//第五步:获得数据库连接
try {
Connection connection = DriverManager.getConnection(DB_URL,USER,PASS);
//第六步:执行查询语句
Statement statement = connection.createStatement();
String sql = "SELECT * FROM crawler_article";
ResultSet rs =statement.executeQuery(sql);
while (rs.next())
{
String title = rs.getString("title");
String author = rs.getString("author");
System.out.println(title+":"+author);
}
//第七步:关闭连接资源
rs.close();
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
//这里会发生SQL异常,因为我们提供的的账户和密码不一定能连接成功
}
}
}
Java数据类型与SQL数据类型的转换:
| SQL | JDBC/Java | setXXX | getXXX |
|---|---|---|---|
| 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 |
SQL 语句从数据库查询中获取数据,并将数据返回到结果集中。SELECT 语句是一种标准的方法,它从一个数据库中选择行记录,并显示在一个结果集中。 java.sql.ResultSet 接口表示一个数据库查询的结果集。一个 ResultSet 对象控制一个光标指向当前行的结果集。术语“结果集”是指包含在 ResultSet 对象中的行和列的数据。
ResultSet 接口的方法可细分为三类-
光标的移动基于 ResultSet 的属性。用相应的语句生成 ResultSet 对象时,同时生成 ResultSet 的属性。
JDBC 提供了连接方法通过下列创建语句来生成你所需的 ResultSet 对象:
第一个参数表示 ResultSet 对象的类型,第二个参数是两个 ResultSet 常量之一,该常量用于判断该结果集是只读的还是可修改的。
在 ResultSet 接口中包括如下几种方法涉及移动光标-
| S.N. | 方法 & 描述 |
|---|---|
| 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
将光标移动到指定的第 row 行。 |
| 6 | public boolean relative(int row) throws SQLException
将光标移动到当前指向的位置往前或往后第 row 行的位置。 |
| 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()方法-
| S.N. | 方法 & 描述 |
|---|---|
| 1 | public int getInt(String columnName) throws SQLException
返回当前行中名为 columnName 的列的 int 值。 |
| 2 | public int getInt(int columnIndex) throws SQLException
返回当前行中指定列的索引的 int 值。列索引从 1 开始,意味着行中的第一列是 1 ,第二列是 2 ,以此类推。 |
同样的,在 ResultSet 接口中还有获取八个 Java 原始类型的 get 方法,以及常见的类型,比如 java.lang.String,java.lang.Object 和 java.net.URL。
也有用于获取 SQL 数据类型 java.sql.Date, java.sql.Time, java.sql.Timestamp, java.sql.Clob,java.sql.Blob 中的方法。查看文档可以了解使用这些 SQL 数据类型的更多的信息。
ResultSet 接口包含了一系列的更新方法,该方法用于更新结果集中的数据。
用 get 方法可以有两个更新方法来更新任一数据类型-
例如,要更新一个结果集的当前行的 String 列,你可以使用任一如下所示的 updateString()方法-
| S.N. | 方法 & 描述 |
|---|---|
| 1 | public void updateString(int columnIndex, String s) throws SQLException
将指定列的字符串的值改为 s。 |
| 2 | public void updateString(String columnName, String s) throws SQLException
类似于前面的方法,不同之处在于指定的列是用名字来指定的,而不是它的索引。 |
八个原始数据类型都有其更新方法,比如 String,Object,URL,和在 java.sql 包中的 SQL 数据类型。
更新结果集中的行将改变当前行的列中的 ResultSet 对象,而不是基础数据库中的数据。要更新数据库中一行的数据,你需要调用以下的任一方法-
| S.N. | 方法 & 描述 |
|---|---|
| 1 | public void updateRow()
通过更新数据库中相对应的行来更新当前行。 |
| 2 | public void deleteRow()
从数据库中删除当前行。 |
| 3 | public void refreshRow()
在结果集中刷新数据,以反映数据库中最新的数据变化。 |
| 4 | public void cancelRowUpdates()
取消对当前行的任何修改。 |
| 5 | public void insertRow()
在数据库中插入一行。本方法只有在光标指向插入行的时候才能被调用。 |
如果你的 JDBC 连接是处于自动提交模式下,该模式为默认模式,那么每句 SQL 语句都是在其完成时提交到数据库。
对简单的应用程序来说这种模式相当好,但有三个原因你可能想关闭自动提交模式,并管理你自己的事务-
你可以通过事务在任意时间来控制以及更改应用到数据库。它把单个 SQL 语句或一组 SQL 语句作为一个逻辑单元,如果其中任一语句失败,则整个事务失败。
若要启用手动事务模式来代替 JDBC 驱动程序默认使用的自动提交模式的话,使用 Connection 对象的的 setAutoCommit()方法。如果传递一个布尔值 false 到 setAutoCommit()方法,你就关闭自动提交模式。你也可以传递一个布尔值 true 将其再次打开。
例如,如果有一个名为 conn 的 Connection 对象,以下的代码将关闭自动提交模式-
conn.setAutoCommit(false);
当你完成了你的修改,并且要提交你的修改,可以在 connection 对象里调用 commit()方法,如下所示-
conn.commit( );
另外,用名为 conn 的连接回滚数据到数据库,使用如下所示的代码-
conn.rollback( );
下面的例子说明了如何使用提交和回滚对象-
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();
}
在这种情况下,之前的 INSERT 语句不会成功,一切都将被回滚到最初状态。
新的 JDBC 3.0 还原点接口提供了额外的事务控制。大部分现代的数据库管理系统的环境都支持设定还原点,例如 Oracle 的 PL/SQL。
当你在事务中设置一个还原点来定义一个逻辑回滚点。如果在一个还原点之后发生错误,那么可以使用 rollback 方法来撤消所有的修改或在该还原点之后所做的修改。
Connection 对象有两个新的方法来管理还原点-
setSavepoint(String savepointName): 定义了一个新的还原点。它也返回一个 Savepoint 对象。
有一个 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, 20, ‘Rita‘, ‘Tez‘)";
stmt.executeUpdate(SQL);
//Submit a malformed SQL statement that breaks
String SQL = "INSERTED IN Employees " +
"VALUES (107, 22, ‘Sita‘, ‘Tez‘)";
stmt.executeUpdate(SQL);
// If there is no error, commit the changes.
conn.commit();
}catch(SQLException se){
// If there is any error.
conn.rollback(savepoint1);
}
在这种情况下,之前的 INSERT 语句不会成功,一切都将被回滚到最初状态。
批处理是指你将关联的 SQL 语句组合成一个批处理,并将他们当成一个调用提交给数据库。
当你一次发送多个 SQL 语句到数据库时,可以减少通信的资源消耗,从而提高了性能。
JDBC 驱动程序不一定支持该功能。你可以使用 DatabaseMetaData.supportsBatchUpdates() 方法来确定目标数据库是否支持批处理更新。如果你的JDBC驱动程序支持此功能,则该方法返回值为 true。
Statement,PreparedStatement 和 CallableStatement 的 addBatch() 方法用于添加单个语句到批处理。
executeBatch() 方法用于启动执行所有组合在一起的语句。
executeBatch() 方法返回一个整数数组,数组中的每个元素代表了各自的更新语句的更新数目。
使用 Statement 对象来使用批处理所需要的典型步骤如下所示-
示例
下面的代码段提供了一个使用 Statement 对象批量更新的例子-
// Create statement object
Statement stmt = conn.createStatement();
// Set auto-commit to false
conn.setAutoCommit(false);
// Create SQL statement
String SQL = "INSERT INTO Employees (id, first, last, age) " +
"VALUES(200,‘Zia‘, ‘Ali‘, 30)";
// Add above SQL statement in the batch.
stmt.addBatch(SQL);
// Create one more SQL statement
String SQL = "INSERT INTO Employees (id, first, last, age) " +
"VALUES(201,‘Raj‘, ‘Kumar‘, 35)";
// Add above SQL statement in the batch.
stmt.addBatch(SQL);
// Create one more SQL statement
String SQL = "UPDATE Employees SET age = 35 " +
"WHERE id = 100";
// Add above SQL statement in the batch.
stmt.addBatch(SQL);
// Create an int[] to hold returned values
int[] count = stmt.executeBatch();
//Explicitly commit statements to apply changes
conn.commit();
使用 prepareStatement 对象来使用批处理需要的典型步骤如下所示-
下面的代码段提供了一个使用 PrepareStatement 对象批量更新的示例-
// Create SQL statement
String SQL = "INSERT INTO Employees (id, first, last, age) " +
"VALUES(?, ?, ?, ?)";
// Create PrepareStatement object
PreparedStatemen pstmt = conn.prepareStatement(SQL);
//Set auto-commit to false
conn.setAutoCommit(false);
// Set the variables
pstmt.setInt( 1, 400 );
pstmt.setString( 2, "Pappu" );
pstmt.setString( 3, "Singh" );
pstmt.setInt( 4, 33 );
// Add it to the batch
pstmt.addBatch();
// Set the variables
pstmt.setInt( 1, 401 );
pstmt.setString( 2, "Pawan" );
pstmt.setString( 3, "Singh" );
pstmt.setInt( 4, 31 );
// Add it to the batch
pstmt.addBatch();
//add more batches
.
.
.
.
//Create an int[] to hold returned values
int[] count = stmt.executeBatch();
//Explicitly commit statements to apply changes
conn.commit();
假设,你需要执行下面的 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;
注意:上面的存储过程是在 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 ;
当前有三种类型的参数:IN,OUT 和 INOUT。PreparedStatement 对象只能使用 IN 参数。CallableStatement 对象可以使用所有的三种类型。
下面是三种类型参数的定义-
| 参数 | 描述 |
|---|---|
| IN | 当 SQL 语句创建的时候,该参数的值是未知的。你可以用 setXXX() 方法将值绑定到 IN 参数里。 |
| OUT | 该参数的值是由 SQL 语句的返回值。你可以用 getXXX() 方法从 OUT 参数中检索值。 |
| INOUT | 该参数同时提供输入和输出值。你可以用 setXXX() 方法将值绑定到 IN 参数里,并且也可以用 getXXX() 方法从 OUT 参数中检索值。 |
下面的代码片段展示了如何使用 Connection.prepareCall() 方法实现一个基于上述存储过程的 CallableStatement 对象-
CallableStatement cstmt = null;
try {
String SQL = "{call getEmpName (?, ?)}";
cstmt = conn.prepareCall (SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
. . .
}
字符串变量 SQL 使用参数占位符来表示存储过程。
使用 CallableStatement 对象就像使用 PreparedStatement 对象。在执行该语句前,你必须将值绑定到所有的参数,否则你将收到一个 SQL 异常。
如果你有 IN 参数,只要按照适用于 PreparedStatement 对象相同的规则和技巧;用 setXXX()方法来绑定对应的 Java 数据类型。
当你使用 OUT 和 INOUT 参数就必须采用额外的 CallableStatement 方法:registerOutParameter()。registerOutParameter() 方法将 JDBC 数据类型绑定到存储过程返回的数据类型。
一旦你调用了存储过程,你可以用适当的 getXXX()方法从 OUT 参数参数中检索数值。这种方法将检索出来的 SQL 类型的值映射到 Java 数据类型。
正如你关闭其它的 Statement 对象,出于同样的原因,你也应该关闭 CallableStatement 对象。
close()方法简单的调用就可以完成这项工作。如果你先关闭了 Connection 对象,那么它也会关闭 CallableStatement 对象。然而,你应该始终明确关闭 CallableStatement 对象,以确保该对象被彻底关闭。
CallableStatement cstmt = null;
try {
String SQL = "{call getEmpName (?, ?)}";
cstmt = conn.prepareCall (SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
cstmt.close();
}
PreparedStatement 对象必须具备使用输入和输出流来提供参数数据的能力。这使你能够将整个文件存储到数据库列中,这样数据库就能存储大型数据,例如 CLOB 和 BLOB 数据类型。
用于流数据有下列几种方法-
setXXXStream()方法需要一个额外的参数,该参数是除了参数占位符的文件大小。这个参数通知驱动程序通过使用流有多少数据被发送到数据库中。
示例
假如我们到要上传一个名为 XML_Data.xml 的 XML 文件到数据库的表中。下面是该 XML 文件的内容-
<?xml version="1.0"?> <Employee> <id>100</id> <first>Zara</first> <last>Ali</last> <Salary>10000</Salary> <Dob>18-08-1978</Dob> <Employee>
将该 XML 文件和你要运行的示例保存在相同的目录的。
这个示例将创建一个数据库表 XML_Data ,然后 XML_Data.xml 将被上传到该表中。
将下面的示例拷贝并粘帖到 JDBCExample.java 中,编译并运行它,如下所示-
// Import required packages
import java.sql.*;
import java.io.*;
import java.util.*;
public class JDBCExample {
// 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 = "username";
static final String PASS = "password";
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
Statement stmt = null;
ResultSet rs = null;
try{
// Register JDBC driver
Class.forName("com.mysql.jdbc.Driver");
// Open a connection
System.out.println("Connecting to database...");
conn = DriverManager.getConnection(DB_URL,USER,PASS);
//Create a Statement object and build table
stmt = conn.createStatement();
createXMLTable(stmt);
//Open a FileInputStream
File f = new File("XML_Data.xml");
long fileLength = f.length();
FileInputStream fis = new FileInputStream(f);
//Create PreparedStatement and stream data
String SQL = "INSERT INTO XML_Data VALUES (?,?)";
pstmt = conn.prepareStatement(SQL);
pstmt.setInt(1,100);
pstmt.setAsciiStream(2,fis,(int)fileLength);
pstmt.execute();
//Close input stream
fis.close();
// Do a query to get the row
SQL = "SELECT Data FROM XML_Data WHERE id=100";
rs = stmt.executeQuery (SQL);
// Get the first row
if (rs.next ()){
//Retrieve data from input stream
InputStream xmlInputStream = rs.getAsciiStream (1);
int c;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while (( c = xmlInputStream.read ()) != -1)
bos.write(c);
//Print results
System.out.println(bos.toString());
}
// Clean-up environment
rs.close();
stmt.close();
pstmt.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(pstmt!=null)
pstmt.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("Goodbye!");
}//end main
public static void createXMLTable(Statement stmt)
throws SQLException{
System.out.println("Creating XML_Data table..." );
//Create SQL Statement
String streamingDataSql = "CREATE TABLE XML_Data " +
"(id INTEGER, Data LONG)";
//Drop table first if it exists.
try{
stmt.executeUpdate("DROP TABLE XML_Data");
}catch(SQLException se){
}// do nothing
//Build table.
stmt.executeUpdate(streamingDataSql);
}//end createXMLTable
}//end JDBCExample
现在,让我们用下面的命令编译上面的代码-
C:\>javac JDBCExample.java C:\>
当你运行 JDBCExample 时,它将展示下面的结果-
C:\>java JDBCExample Connecting to database... Creating XML_Data table... <?xml version="1.0"?> <Employee> <id>100</id> <first>Zara</first> <last>Ali</last> <Salary>10000</Salary> <Dob>18-08-1978</Dob> <Employee> Goodbye!
原文:https://www.cnblogs.com/MrSaver/p/9028620.html