JDBC 指 Java 數據庫鏈接,是一種標準Java應用編程接口( JAVA API),用來鏈接 Java 編程語言和普遍的數據庫。html
JDBC API 庫包含下面提到的每一個任務,都是與數據庫相關的經常使用用法。java
從根本上來講,JDBC 是一種規範,它提供了一套完整的接口,容許便攜式訪問到底層數據庫,所以能夠用 Java 編寫不一樣類型的可執行文件,例如:mysql
全部這些不一樣的可執行文件就可使用 JDBC 驅動程序來訪問數據庫,這樣能夠方便的訪問數據。JDBC 具備 ODBC 同樣的性能,容許 Java 程序包含與數據庫無關的代碼。sql
JDBC API: 提供了應用程序對 JDBC 管理器的鏈接。數據庫
以下所示爲JDBC開發中主要用到的類。編程
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 語句從數據庫查詢中獲取數據,並將數據返回到結果集中。SELECT 語句是一種標準的方法,它從一個數據庫中選擇行記錄,並顯示在一個結果集中。 java.sql.ResultSet 接口表示一個數據庫查詢的結果集。一個 ResultSet 對象控制一個光標指向當前行的結果集。術語「結果集」是指包含在 ResultSet 對象中的行和列的數據。服務器
ResultSet 接口的方法可細分爲三類-架構
光標的移動基於 ResultSet 的屬性。用相應的語句生成 ResultSet 對象時,同時生成 ResultSet 的屬性。併發
JDBC 提供了鏈接方法經過下列建立語句來生成你所需的 ResultSet 對象:
第一個參數表示 ResultSet 對象的類型,第二個參數是兩個 ResultSet 常量之一,該常量用於判斷該結果集是隻讀的仍是可修改的。
在 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 對象可使用全部的三種類型。
下面是三種類型參數的定義
CallableStatement cstmt = null;下面的代碼片斷展現瞭如何使用 Connection.prepareCall() 方法實現一個基於上述存儲過程的 CallableStatement 對象-
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!