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!