目录html
参考连接:https://www.yiibai.com/jdbc/jdbc_quick_guide.htmljava
JDBC表明Java数据库链接(Java Database Connectivity),它是用于Java编程语言和数据库之间的数据库无关链接的标准Java API,换句话说:JDBC是用于在Java语言编程中与数据库链接的API。mysql
JDBC库包括一般与数据库使用相关,以下面提到的每一个任务的API -sql
JDBC API支持用于数据库访问的两层和三层处理模型,但一般,JDBC体系结构由两层组成:数据库
JDBC API使用驱动程序管理器并指定数据库的驱动程序来提供与异构数据库的透明链接。编程
JDBC驱动程序管理器确保使用正确的驱动程序来访问每一个数据源。 驱动程序管理器可以支持链接到多个异构数据库的多个并发驱动程序。数组
如下是架构图,它显示了驱动程序管理器相对于JDBC驱动程序和Java应用程序的位置服务器
JDBC API提供如下接口和类 -架构
DriverManager
:此类管理数据库驱动程序列表。 使用通讯子协议未来自java应用程序的链接请求与适当的数据库驱动程序进行匹配。在JDBC下识别某个子协议的第一个驱动程序将用于创建数据库链接。Driver
:此接口处理与数据库服务器的通讯。咱们不多会直接与Driver
对象进行交互。 但会使用DriverManager
对象来管理这种类型的对象。 它还提取与使用Driver
对象相关的信息。Connection
:此接口具备用于联系数据库的全部方法。 链接(Connection
)对象表示通讯上下文,即,与数据库的全部通讯仅经过链接对象。Statement
:使用今后接口建立的对象将SQL语句提交到数据库。 除了执行存储过程以外,一些派生接口还接受参数。ResultSet
:在使用Statement
对象执行SQL查询后,这些对象保存从数据库检索的数据。 它做为一个迭代器并可移动ResultSet
对象查询的数据。SQLException
:此类处理数据库应用程序中发生的任何错误。//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
创建JDBC链接所涉及的编程至关简单。 如下是基本的四个步骤 -并发
import
语句在Java代码开头位置导入所需的类。DriverManager
对象的getConnection()
方法来创建实际的数据库链接。Class.forName("com.mysql.jdbc.Driver"); Connection conn = null; conn = DriverManager.getConnection("jdbc:mysql://hostname:port/db_name","db_username", "db_password"); conn.close()
接口 | 推荐使用 |
---|---|
Statement |
用于对数据库进行通用访问,在运行时使用静态SQL语句时颇有用。 Statement 接口不能接受参数。 |
PreparedStatement |
当计划要屡次使用SQL语句时使用。PreparedStatement 接口在运行时接受输入参数。 |
CallableStatement |
当想要访问数据库存储过程时使用。CallableStatement 接口也能够接受运行时输入参数。 |
在使用Statement
对象执行SQL语句以前,须要使用Connection
对象的createStatement()
方法建立一个Statement
对象,如如下示例所示:
Statement stmt = null; try { stmt = conn.createStatement( ); . . . } catch (SQLException e) { . . . } finally { stmt.close(); }
在建立Statement
对象后,可使用它来执行一个SQL语句,它有三个执行方法能够执行。它们分别是 -
boolean execute (String SQL)
: 若是能够检索到ResultSet
对象,则返回一个布尔值true
; 不然返回false
。使用此方法执行SQLDDL
语句或须要使用真正的动态SQL,可以使用于执行建立数据库,建立表的SQL语句等等。int executeUpdate (String SQL):
返回受SQL语句执行影响的行数。使用此方法执行预期会影响多行的SQL语句,例如:INSERT
,UPDATE
或DELETE
语句。ResultSet executeQuery(String SQL):
返回一个ResultSet
对象。 当您但愿得到结果集时,请使用此方法,就像使用SELECT
语句同样。 PreparedStatement
接口扩展了Statement
接口,它添加了比Statement
对象更好一些优势的功能。
此语句能够动态地提供/接受参数。
PreparedStatement pstmt = null; try { String SQL = "Update Employees SET age = ? WHERE id = ?"; pstmt = conn.prepareStatement(SQL); . . . } catch (SQLException e) { . . . } finally { pstmt.close(); }
JDBC中的全部参数都由 ?
符号做为占位符,这被称为参数标记。 在执行SQL语句以前,必须为每一个参数(占位符)提供值。
setXXX()
方法将值绑定到参数,其中XXX
表示要绑定到输入参数的值的Java数据类型。 若是忘记提供绑定值,则将会抛出一个SQLException
。
每一个参数标记是它其顺序位置引用。第一个标记表示位置1
,下一个位置2
等等。 该方法与Java数组索引不一样(它不从0
开始)。
全部Statement
对象与数据库交互的方法(a)execute()
,(b)executeQuery()
和(c)executeUpdate()
也能够用于PreparedStatement
对象。 可是,这些方法被修改成可使用输入参数的SQL语句。
相似Connection
对象建立Statement
和PreparedStatement
对象同样,它还可使用一样的方式建立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;
存在三种类型的参数:IN
,OUT
和INOUT
。 PreparedStatement
对象只使用IN
参数。CallableStatement
对象可使用上面三个参数类型。
如下是上面三种类型参数的定义 -
参数 | 描述 |
---|---|
IN | 建立SQL语句时其参数值是未知的。 使用setXXX() 方法将值绑定到IN 参数。 |
OUT | 由SQL语句返回的参数值。可使用getXXX() 方法从OUT参数中检索值。 |
INOUT | 提供输入和输出值的参数。使用setXXX() 方法绑定变量并使用getXXX() 方法检索值。 |
如下代码片断显示了如何使用Connection.prepareCall()
方法根据上述存储过程来实例化一个CallableStatement
对象 -
CallableStatement cstmt = 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..."); String sql = "{call getEmpName (?, ?)}"; stmt = conn.prepareCall(sql); //Bind IN parameter first, then bind OUT parameter int empID = 102; stmt.setInt(1, empID); // This would set ID as 102 // Because second parameter is OUT so register it stmt.registerOutParameter(2, java.sql.Types.VARCHAR); //Use execute method to run stored procedure. System.out.println("Executing stored procedure..." ); stmt.execute(); //Retrieve employee name with getXXX method String empName = stmt.getString(2); System.out.println("Emp Name with ID:" + empID + " is " + empName); stmt.close(); conn.close(); } catch (SQLException e) { . . . } finally { . . . }
String变量strSQL
表示存储过程,带有两个参数占位符。
使用CallableStatement
对象就像使用PreparedStatement
对象同样。 在执行语句以前,必须将值绑定到全部参数,不然将抛出一个SQLException
异常。
若是有IN
参数,只需遵循适用于PreparedStatement
对象的相同规则和技术; 使用与绑定的Java数据类型相对应的setXXX()
方法。
使用OUT
和INOUT
参数时,必须使用一个额外的CallableStatement
对象方法registerOutParameter()
。 registerOutParameter()
方法将JDBC数据类型绑定到存储过程并返回预期数据类型。
当调用存储过程,可使用适当的getXXX()
方法从OUT
参数中检索该值。 此方法将检索到的SQL类型的值转换为对应的Java数据类型。
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);
可能的RSType
值以下。若是不指定任何ResultSet
类型,将自动分配一个TYPE_FORWARD_ONLY
值。
类型 | 描述 |
---|---|
ResultSet.TYPE_FORWARD_ONLY |
光标只能在结果集中向前移动。 |
ResultSet.TYPE_SCROLL_INSENSITIVE |
光标能够向前和向后滚动,结果集对建立结果集后发生的数据库所作的更改不敏感。 |
ResultSet.TYPE_SCROLL_SENSITIVE |
光标能够向前和向后滚动,结果集对建立结果集以后发生的其余数据库的更改敏感。 |
可能的RSConcurrency
以下。 若是不指定任何并发类型,将自动得到一个CONCUR_READ_ONLY
值。
并发 | 描述 |
---|---|
ResultSet.CONCUR_READ_ONLY |
建立只读结果集,这是默认值。 |
ResultSet.CONCUR_UPDATABLE |
建立可更新的结果集 |
try { Statement stmt = conn.createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); } catch(Exception ex) { .... } finally { .... }
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 ,依此类推。 |
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
包中的String
,Object
,URL
和SQL数据类型。
更新结果集中的一行会更改ResultSet
对象中当前行的列,但不会更改底层数据库中的列的值。 要更新数据库中的行,须要调用如下方法之一。
序号 | 方法 | 描述 |
---|---|---|
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);
完成更改后,若要提交更改,那么可在链接对象上调用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新添加了Savepoint
接口提供了额外的事务控制能力。大多数现代DBMS支持其环境中的保存点,如Oracle的PL/SQL。
设置保存点(Savepoint
)时,能够在事务中定义逻辑回滚点。 若是经过保存点(Savepoint
)发生错误时,则可使用回滚方法来撤消全部更改或仅保存保存点以后所作的更改。
Connection
对象有两种新的方法可用来管理保存点 -
Savepoint
对象。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); }
在这种状况下,上述INSERT
语句都不会成功,由于全部操做都被回滚了。
批量处理容许将相关的SQL语句分组到批处理中,并经过对数据库的一次调用来提交它们,一次执行完成与数据库之间的交互。
一次向数据库发送多个SQL语句时,能够减小通讯开销,从而提升性能。
DatabaseMetaData.supportsBatchUpdates()
方法来肯定目标数据库是否支持批量更新处理。若是JDBC驱动程序支持此功能,该方法将返回true
。Statement
,PreparedStatement
和CallableStatement
的addBatch()
方法用于将单个语句添加到批处理。 executeBatch()
用于执行组成批量的全部语句。executeBatch()
返回一个整数数组,数组的每一个元素表示相应更新语句的更新计数。clearBatch()
方法删除它们。此方法将删除全部使用addBatch()
方法添加的语句。 可是,没法指定选择某个要删除的语句。如下是使用Statement
对象的批处理的典型步骤序列 -
createStatement()
方法建立Statement
对象。setAutoCommit()
将自动提交设置为false
。addBatch()
方法在建立的Statement
对象上添加SQL语句到批处理中。Statement
对象上使用executeBatch()
方法执行全部SQL语句。commit()
方法提交全部更改。如下是使用PrepareStatement
对象进行批处理的典型步骤顺序 -
prepareStatement()
方法建立PrepareStatement
对象。setAutoCommit()
将自动提交设置为false
。addBatch()
方法在建立的Statement
对象上添加SQL语句到批处理中。Statement
对象上使用executeBatch()
方法执行全部SQL语句。commit()
方法提交全部更改。