jdbc pdf_JDBC教程– ULTIMATE指南(PDF下载)
jdbc pdf
在本文中,我們提供了全面的JDBC教程(Java數(shù)據(jù)庫連接性),這是Oracle提供的API,允許程序員處理Java應(yīng)用程序中的不同數(shù)據(jù)庫:它允許開發(fā)人員建立與數(shù)據(jù)庫的連接,定義特定客戶端如何訪問給定的客戶端。數(shù)據(jù)庫,提供了用于讀取,插入,更新和刪除數(shù)據(jù)庫中數(shù)據(jù)條目的機(jī)制,并負(fù)責(zé)處理由不同SQL語句組成的事務(wù)。
在本文中,我們將解釋主要的JDBC組件,例如語句,結(jié)果集或存儲過程。
JDBC需要程序員可能要使用的不同數(shù)據(jù)庫的驅(qū)動程序。
我們將對此進(jìn)行詳細(xì)說明,并提供一些示例。
JDBC從一開始就與Java一起出現(xiàn)。 第一個(gè)發(fā)行版于1997年2月隨JDK 1.1一起發(fā)布,此后,JDBC一直是Java的重要組成部分。 包含JDBC的主要軟件包是http://docs.oracle.com/javase/8/docs/api/java/sql/package-summary.html和http://docs.oracle.com/javase/8/ docs / api / javax / sql / package-summary.html 。
有關(guān)最新的JDBC版本(4.2)及其開發(fā)和維護(hù)的所有信息,可以在JSR 221中找到。
本文顯示的所有示例都是使用Java 8更新0_25和Eclipse SDK版本Luna 4.4實(shí)現(xiàn)的。 在本文末尾,您可以下載所有這些示例以及更多示例!
目錄
1.組成 2.連接 3.數(shù)據(jù)類型 4.驅(qū)動程序 5.數(shù)據(jù)庫 6.結(jié)果集 7.存儲過程 8.陳述 9.批處理命令 10.交易 11. CRUD命令 12. Java 8 13.基于JDBC構(gòu)建的Sql庫 14.單元測試 15.總結(jié) 16.下載 17.鏈接1.組成
JDBC API允許程序員和Java應(yīng)用程序與數(shù)據(jù)庫進(jìn)行交互。 它支持執(zhí)行不同SQL語句并處理來自不同數(shù)據(jù)源的結(jié)果。
在本節(jié)中,我們將嘗試總結(jié)并列出每個(gè)Java應(yīng)用程序中最重要的JDBC組件,所有這些組件將在下一章中進(jìn)行詳細(xì)說明。
- 首先,Java應(yīng)用程序需要創(chuàng)建和建立特定數(shù)據(jù)庫的連接。 使用驅(qū)動程序管理器(例如,接口java.sql.DriverManager一個(gè)實(shí)例)或直接通過JDBC數(shù)據(jù)源完成此操作。 為此,可以使用接口javax.sql.DataSource 。 如前所述,我們將在下一章中更詳細(xì)地解釋這些組件。
- 一旦與數(shù)據(jù)庫連接,就可以使用java.sql.Connection執(zhí)行CRUD(創(chuàng)建,讀取,更新,刪除)SQL語句或操作。 這些說明將在本教程中進(jìn)行解釋。
- 為了執(zhí)行這些操作,程序員可以使用基于java.sql.Statement和java.sql.PreparedStatement的類。 最后幾次在多次執(zhí)行同一條語句時(shí)效率更高,并提供了我們將在本教程中列出的其他好處。
JDBC接口連接提供了創(chuàng)建語句實(shí)例的機(jī)制:
- 諸如插入,更新或刪除之類的操作將返回修改后的行數(shù),而不會返回其他任何內(nèi)容:
- 選擇操作(查詢)以java.sql.ResultSet內(nèi)部的行java.sql.ResultSet返回結(jié)果。 按名稱或數(shù)字檢索行; 結(jié)果元數(shù)據(jù)也可用:
- 通常,JDBC使用連接池來管理連接。 連接池(例如C3P0或DBCP)有不同的實(shí)現(xiàn)。 這些是JDBC連接組,在需要時(shí)從應(yīng)用程序使用或借用它們,并在任務(wù)完成時(shí)釋放。 關(guān)于如何在JDBC中使用和配置連接池的文檔很多,可以在以下鏈接中找到很好的教程: http://docs.oracle.com/cd/E13222_01/wls/docs81/ConsoleHelp/jdbc_connection_pools.html 。
- 使用JDBC時(shí),還可以使用其他功能:存儲過程,可調(diào)用語句,批處理……所有這些功能都將在本教程中進(jìn)行描述。
2.連接
為了連接到數(shù)據(jù)庫,我們需要使用java.sql.Connection對象。 我們可以使用java.sql.DriverManager類的getConnection()方法來完成此操作。 此方法接收數(shù)據(jù)庫主機(jī)和憑據(jù)作為參數(shù)。
此代碼段顯示了如何為本地MySQL數(shù)據(jù)庫創(chuàng)建連接。
//MySQL driver is loaded Class.forName( "com.mysql.jdbc.Driver" ); //Connection object is created using the db host and credentials Connection connect = DriverManager.getConnection("jdbc:mysql://localhost/countries?"+ "user=root&password=root" );連接對象允許程序員執(zhí)行以下操作:
- JDBC語句的創(chuàng)建:可以使用連接對象來創(chuàng)建Statement , PreparedStatement或CallableStatement實(shí)例,這些實(shí)例提供執(zhí)行不同SQL語句的方法。 這是創(chuàng)建PreparedStatement的示例:
該語句可以執(zhí)行作為參數(shù)傳遞的sql更新。
- 提供了提交或回滾給定事務(wù)的可能性。 JDBC連接支持兩種不同的工作方式: autocommit=true和autocommit=false 。 第一個(gè)將所有事務(wù)直接提交到數(shù)據(jù)庫,第二個(gè)需要特殊的命令來提交或回滾事務(wù)。 我們將在本教程的相關(guān)章節(jié)中看到更多詳細(xì)信息。 以下代碼段顯示了如何更改JDBC連接的自動提交模式:
- 可能獲取有關(guān)已使用數(shù)據(jù)庫的元信息。
- 其他選項(xiàng),例如批處理,存儲過程等。
我們將詳細(xì)解釋所有這些功能,目前最好知道什么是JDBC連接以及使用JDBC連接可以完成的操作。
3.數(shù)據(jù)類型
JDBC將Java數(shù)據(jù)類型轉(zhuǎn)換為適當(dāng)?shù)腏DBC類型,然后再在數(shù)據(jù)庫中使用它們。 Java和JDBC數(shù)據(jù)類型之間存在默認(rèn)映射,該映射提供了數(shù)據(jù)庫實(shí)現(xiàn)和驅(qū)動程序之間的一致性。
下表包含這些映射:
| VARCHAR | java.lang.String | setString | getString |
| 焦炭 | java.lang.String | setString | getString |
| LONGVARCHAR | java.lang.String | setString | getString |
| 比特 | 布爾值 | setBoolean | getBoolean |
| 數(shù)字 | 大十進(jìn)制 | setBigDecimal | getBigDecimal |
| 天音 | 字節(jié) | setByte | getByte |
| 小靈通 | 短 | setShort | getShort |
| 整數(shù) | 整型 | setInt | getInt |
| 比金特 | 長 | setLong | getLong |
| 真實(shí) | 浮動 | setFloat | getFloat |
| 浮動 | 浮動 | setFloat | getFloat |
| 雙 | 雙 | setDouble | getDouble |
| VARBINARY | 字節(jié)[] | setBytes | getBytes |
| 二進(jìn)制 | 字節(jié)[] | setBytes | getBytes |
| 日期 | java.sql.Date | 設(shè)置日期 | getDate |
| 時(shí)間 | java.sql.Time | 設(shè)置時(shí)間 | getTime |
| 時(shí)間戳 | java.sql.Timestamp | setTimestamp | getTimestamp |
| CLOB | java.sql.Clob | setClob | getClob |
| BLOB | java.sql.Blob | setBlob | getBlob |
| 陣列 | java.sql.Array | setARRAY | getARRAY |
| 參考 | java.sql.Ref | SetRef | getRef |
| 結(jié)構(gòu) | java.sql.Struct | SetStruct | getStruct |
在SQL和Java中,空值的處理方式有所不同。 在Java中使用SQL空值進(jìn)行處理時(shí),最好遵循一些最佳做法,例如避免使用基本類型,因?yàn)樗鼈儾荒転榭?#xff0c;但可以轉(zhuǎn)換為默認(rèn)值,例如int為0,布爾值為false等。
取而代之的是,建議對原始類型使用包裝器類。 ResultSet類包含一個(gè)名為wasNull()的方法,在這些情況下非常有用。 這是一個(gè)用法示例:
Statement stmt = conn.createStatement( ); String sql = "SELECT NAME, POPULATION FROM COUNTRIES"; ResultSet rs = stmt.executeQuery(sql);int id = rs.getInt(1); if( rs.wasNull( ) ) {id = 0; }4.驅(qū)動程序
JDBC驅(qū)動程序管理器java.sql.DriverManager是JDBC API的最重要元素之一。 它是處理JDBC驅(qū)動程序列表的基本服務(wù)。 它包含允許Java應(yīng)用程序連接到所需JDBC驅(qū)動程序的機(jī)制和對象。 它負(fù)責(zé)管理不同類型的JDBC數(shù)據(jù)庫驅(qū)動程序。 總結(jié)驅(qū)動程序管理器的主要任務(wù)是了解可用驅(qū)動程序的列表,并處理特定選定驅(qū)動程序和數(shù)據(jù)庫之間的連接。
此類中最常用的方法是DriverManager.getConnetion() 。 此方法建立與數(shù)據(jù)庫的連接。
這是一個(gè)用法示例:
// Create the connection with the default credentials java.sql.Connection conn = DriverManager.getConnection("jdbc:hsqldb:mem:mydb", "SA", "" );我們可以使用DriverManager.registerDriver().方法注冊驅(qū)動程序DriverManager.registerDriver(). :
new org.hsqldb.jdbc.JDBCDriver(); DriverManager.registerDriver( new org.hsqldb.jdbc.JDBCDriver() );我們還可以通過調(diào)用Class.forName()方法來加載驅(qū)動程序:
// Loading the HSQLDB JDBC driver Class.forName( "org.hsqldb.jdbc.JDBCDriver" );...// connection to JDBC using mysql driver Class.forName( "com.mysql.jdbc.Driver" );主要區(qū)別在于方法registerDriver()需要驅(qū)動程序在編譯時(shí)可用,加載驅(qū)動程序類不需要驅(qū)動程序在編譯時(shí)可用。 在JDBC 4之后,不需要真正調(diào)用這些方法,并且應(yīng)用程序不需要單獨(dú)注冊驅(qū)動程序,也不需要加載驅(qū)動程序類。 也建議不要使用registerDriver()方法手動注冊驅(qū)動程序。
DriverManager類的其他有趣方法是getDriver(String url) ,它嘗試通過給定的字符串查找驅(qū)動程序,而getDrivers()返回先前已在Driver Manager中注冊的所有驅(qū)動程序的枚舉:
Enumeration drivers = DriverManager.getDrivers(); while( drivers.hasMoreElements() ) {Driver driver = drivers.nextElement();System.out.println( driver.getClass() ); }5.數(shù)據(jù)庫
JDBC支持大量數(shù)據(jù)庫。 它使用不同的驅(qū)動程序來抽象其差異和工作方式。 DriverManager類負(fù)責(zé)加載正確的數(shù)據(jù)庫,在加載正確的數(shù)據(jù)庫之后,用于訪問數(shù)據(jù)庫以查詢和修改數(shù)據(jù)的代碼將保持(或多或少)不變。
這是JDBC(在Oracle中正式注冊)受支持的數(shù)據(jù)庫的列表: http : //www.oracle.com/technetwork/java/index-136695.html 。
在本章中,我們將展示如何使用不同的數(shù)據(jù)庫:MySQL和HSQLDB。 第一個(gè)是程序員眾所周知的且已被廣泛使用,第二個(gè)是HSQLDB,它是一個(gè)非常有用的測試數(shù)據(jù)庫,具有內(nèi)存功能。 我們將看到如何同時(shí)使用這兩種方法,并且會發(fā)現(xiàn),除了加載適當(dāng)?shù)腏DBC驅(qū)動程序之外,應(yīng)用程序的其余部分保持不變:
MySQL示例:
public static void main( String[] args ) throws ClassNotFoundException, SQLException{// connection to JDBC using mysql driverClass.forName( "com.mysql.jdbc.Driver" );Connection connect = DriverManager.getConnection("jdbc:mysql://localhost/countries?"+ "user=root&password=root" );selectAll( connect );// close resources, in case of exception resources are not properly cleared ...}/*** select statement and print out results in a JDBC result set* * @param conn* @throws SQLException*/private static void selectAll( java.sql.Connection conn ) throws SQLException{Statement statement = conn.createStatement();ResultSet resultSet = statement.executeQuery( "select * from COUNTRIES" );while( resultSet.next() ){String name = resultSet.getString( "NAME" );String population = resultSet.getString( "POPULATION" );System.out.println( "NAME: " + name );System.out.println( "POPULATION: " + population );}}內(nèi)存中(HSQLDB)示例:
public static void main( String[] args ) throws ClassNotFoundException, SQLException{// Loading the HSQLDB JDBC driverClass.forName( "org.hsqldb.jdbc.JDBCDriver" );// Create the connection with the default credentialsjava.sql.Connection conn = DriverManager.getConnection( "jdbc:hsqldb:mem:mydb", "SA", "" );// Create a table in memoryString countriesTableSQL = "create memory table COUNTRIES (NAME varchar(256) not null primary key, POPULATION varchar(256) not null);";// execute the statement using JDBC normal StatementsStatement st = conn.createStatement();st.execute( countriesTableSQL );// nothing is in the database because it is just in memory, non persistentselectAll( conn );// after some insertions, the select shows something different, in the next execution these// entries will not be thereinsertRows( conn );selectAll( conn );}.../*** select statement and print out results in a JDBC result set* * @param conn* @throws SQLException*/private static void selectAll( java.sql.Connection conn ) throws SQLException{Statement statement = conn.createStatement();ResultSet resultSet = statement.executeQuery( "select * from COUNTRIES" );while( resultSet.next() ){String name = resultSet.getString( "NAME" );String population = resultSet.getString( "POPULATION" );System.out.println( "NAME: " + name );System.out.println( "POPULATION: " + population );}}正如我們在最后的程序中看到的那樣, selectAll方法的代碼完全相同,只是JDBC驅(qū)動程序的加載和連接創(chuàng)建發(fā)生了變化。 您可以想象在不同環(huán)境下工作時(shí),它的功能多么強(qiáng)大。 HSQLDB版本的代碼還包含負(fù)責(zé)創(chuàng)建內(nèi)存數(shù)據(jù)庫并插入一些行的代碼,但這只是出于顯示和清晰目的,可以用不同的方式完成。
6.結(jié)果集
類java.sql.ResultSet表示數(shù)據(jù)庫表的結(jié)果集。 通常創(chuàng)建它; 通過執(zhí)行SQL查詢(使用Statement或PreparedStatement的select語句)。 它包含數(shù)據(jù)行,數(shù)據(jù)存儲在該行中。 這些數(shù)據(jù)可以通過索引(以1開頭)或?qū)傩悦Q進(jìn)行訪問:
// creating the result setResultSet resultSet = statement.executeQuery( "select * from COUNTRIES" );// iterating through the results rowswhile( resultSet.next() ){// accessing column values by index or nameString name = resultSet.getString( "NAME" );int population = resultSet.getInt( "POPULATION" );System.out.println( "NAME: " + name );System.out.println( "POPULATION: " + population );// accessing column values by index or nameString name = resultSet.getString( 1 );int population = resultSet.getInt( 2 );System.out.println( "NAME: " + name );System.out.println( "POPULATION: " + population );}如前所示,ResultSets包含用于獲取不同Java類型的列值的getter方法。 它還包含一個(gè)指向當(dāng)前數(shù)據(jù)行的光標(biāo)。 最初,光標(biāo)指向第一行之前。 next方法將光標(biāo)移動到下一行: java.sql.ResultSet.next() 。
可以使用默認(rèn)屬性(例如僅向前移動且不可更新的光標(biāo))創(chuàng)建ResultSets。 如果程序員想使用其他類型的屬性,則可以在創(chuàng)建Statement時(shí)指定,以便通過更改傳遞的參數(shù)來生成結(jié)果集:
/** * indicating result sets properties that will be created from this statement: type, * concunrrency and holdability */ Statement statement = conn.createStatement( ResultSet. TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.CLOSE_CURSORS_AT_COMMIT );使用這種結(jié)果集,可以在兩個(gè)方向上移動光標(biāo),并為此目的使用結(jié)果集將新數(shù)據(jù)更新或插入數(shù)據(jù)庫中。
7.存儲過程
在本章中,我們將解釋什么是存儲過程以及如何在JDBC中使用它們。 對于示例,我們將使用基于MySQL的存儲過程。
存儲過程是SQL語句集,作為執(zhí)行邏輯單元的一部分并執(zhí)行定義的任務(wù)。 當(dāng)封裝一組要在數(shù)據(jù)庫上執(zhí)行的操作時(shí),它們非常有用。
首先,我們將在MySQL數(shù)據(jù)庫中創(chuàng)建一個(gè)過程,以下腳本將幫助我們完成此任務(wù):
delimiter //CREATE PROCEDURE spanish (OUT population_out INT)BEGINSELECT COUNT(*) INTO population_out FROM countries;END//delimiter ;CALL simpleproc(@a);基本上,以上腳本創(chuàng)建了一個(gè)名為Spanish的過程,該過程具有一個(gè)類型為int且沒有輸入?yún)?shù)的輸出屬性。 該過程返回?cái)?shù)據(jù)庫中所有國家的計(jì)數(shù)。
一旦創(chuàng)建了過程,就可以從Java應(yīng)用程序中使用它。為了調(diào)用存儲過程,我們需要使用接口java.sql.CallableStatement特殊語句,這些語句允許程序員執(zhí)行存儲過程,以指示輸出屬性和要使用的輸入?yún)?shù)。 在我們的簡單示例中,僅配置了輸出屬性。 這是一個(gè)例子:
CallableStatement callableStatement = null;// the procedure should be created in the databaseString spanishProcedure = "{call spanish(?)}";// callable statement is usedcallableStatement = connect.prepareCall( spanishProcedure );// out parameters, also in parameters are possible, not in this casecallableStatement.registerOutParameter( 1, java.sql.Types.VARCHAR );// execute using the callable statement method executeUpdatecallableStatement.executeUpdate();// attributes are retrieved by indexString total = callableStatement.getString( 1 );System.out.println( "amount of spanish countries " + total );我們可以理解如何使用java.sql.PreparedStatement.executeUpdate()方法指示如何將過程的輸出存儲在何處以及如何執(zhí)行該過程。 大多數(shù)數(shù)據(jù)庫都支持存儲過程,但是它們的語法和行為可能有所不同,因此,根據(jù)存儲過程的數(shù)據(jù)庫,處理存儲過程的Java應(yīng)用程序可能會有所不同。
8.陳述
如本教程中已經(jīng)提到的,JDBC使用接口java.sql.Statement來執(zhí)行不同SQL查詢和操作,例如插入,更新或刪除。 這是基本接口,包含所有基本方法,例如java.sql.Statement.executeQuery(String)或java.sql.Statement.executeUpdate(String) 。
當(dāng)程序員不需要多次執(zhí)行相同的查詢或不需要對查詢和語句進(jìn)行參數(shù)化時(shí),建議使用此接口的實(shí)現(xiàn)。 通常,我們可以說此接口適合于執(zhí)行DDL語句(創(chuàng)建,更改,刪除)。 這些語句通常不會多次執(zhí)行,并且不需要支持不同的參數(shù)。
如果程序員在重復(fù)SQL查詢或參數(shù)化時(shí)需要更高的效率,則應(yīng)使用java.sql.PreparedStatement 。 該接口繼承了前面提到的基本語句接口,并提供了參數(shù)設(shè)置。 由于此功能,此接口可更安全地防止SQL注入攻擊。 這是一段代碼,顯示了此接口的示例:
System.out.println( "Updating rows for " + name + "..." );String sql = "UPDATE COUNTRIES SET POPULATION=? WHERE NAME=?";PreparedStatement updateStmt = conn.prepareStatement( sql );// Bind values into the parameters. updateStmt.setInt( 1, 10000000 ); // population updateStmt.setString( 2, name ); // name// update prepared statement using executeUpdate int numberRows = updateStmt.executeUpdate();System.out.println( numberRows + " rows updated..." );使用準(zhǔn)備好的語句的另一個(gè)好處是可以通過使用setObject()方法來處理非標(biāo)準(zhǔn)對象。 這是一個(gè)例子:
PreparedStatement updateStmt2 = conn.prepareStatement( sql );// Bind values into the parameters using setObject, can be used for any kind and type of// parameter.updateStmt2.setObject( 1, 10000000 ); // populationupdateStmt2.setObject( 2, name ); // name// update prepared statement using executeUpdatenumberRows = updateStmt2.executeUpdate();System.out.println( numberRows + " rows updated..." );updateStmt2.close();就像在與存儲過程有關(guān)的章節(jié)中提到的那樣,為此目的可以使用另一個(gè)接口,它稱為java.sql.CallableStatement并擴(kuò)展了PreparedStatement。
9.批處理命令
JDBC提供了批量執(zhí)行SQL語句列表的可能性,也就是說,可以全部執(zhí)行。 程序員使用代碼的方式取決于語句的類型,但總體思路是相同的。 在下一個(gè)代碼片段中,顯示了如何對java.sql.Statement使用批處理:
Statement statement = null;statement = connect.createStatement();// adding batchs to the statement statement.addBatch( "update COUNTRIES set POPULATION=9000000 where NAME='USA'" ); statement.addBatch( "update COUNTRIES set POPULATION=9000000 where NAME='GERMANY'" ); statement.addBatch( "update COUNTRIES set POPULATION=9000000 where NAME='ARGENTINA'" );// usage of the executeBatch method int[] recordsUpdated = statement.executeBatch();int total = 0; for( int recordUpdated : recordsUpdated ) {total += recordUpdated; }System.out.println( "total records updated by batch " + total );并使用java.sql.PreparedStatement :
String sql = "update COUNTRIES set POPULATION=? where NAME=?";PreparedStatement preparedStatement = null;preparedStatement = connect.prepareStatement( sql );preparedStatement.setObject( 1, 1000000 );preparedStatement.setObject( 2, "SPAIN" );// adding batchespreparedStatement.addBatch();preparedStatement.setObject( 1, 1000000 );preparedStatement.setObject( 2, "USA" );// adding batchespreparedStatement.addBatch();// executing all batchsint[] updatedRecords = preparedStatement.executeBatch();int total = 0;for( int recordUpdated : updatedRecords ){total += recordUpdated;}System.out.println( "total records updated by batch " + total );我們可以看到,這些區(qū)別基本上是使用SQL查詢參數(shù)的方式以及如何構(gòu)建查詢的,但是在一行上執(zhí)行多個(gè)語句的想法是相同的。 在第一種情況下,使用方法java.sql.Statement.executeBatch() ,在第二種情況下使用java.sql.PreparedStatement.addBatch()和java.sql.Statement.executeBatch() 。
10.交易
JDBC支持事務(wù),并包含實(shí)現(xiàn)基于事務(wù)的應(yīng)用程序的方法和功能。 我們將在本章中列出最重要的那些。
- java.sql.Connection.setAutoCommit(boolean) :此方法接收布爾值作為參數(shù),如果為true(這是默認(rèn)行為),則所有SQL語句將自動保存在數(shù)據(jù)庫中。 如果為false,將不會自動保留更改,這將通過使用java.sql.Connection.commit()方法來完成。
- java.sql.Connection.commit() 。 僅當(dāng)自動提交設(shè)置為false或禁用時(shí),才可以使用此方法。 也就是說,它僅適用于非自動提交模式。 執(zhí)行此方法時(shí),自上次提交/回滾以來的所有更改都將保留在數(shù)據(jù)庫中。
- java.sql.Connection.rollback() 。 僅當(dāng)禁用自動提交時(shí),才可以使用此方法。 它撤消或還原當(dāng)前事務(wù)中完成的所有更改。
這是一個(gè)用法示例,在此示例中,我們可以看到如何使用setAutoCommit(false)方法禁用自動提交模式。 調(diào)用commit()時(shí),所有更改都將commit()并且使用rollback()方法將當(dāng)前事務(wù)更改rollback() :
Class.forName( "com.mysql.jdbc.Driver" ); Connection connect = null; try {// connection to JDBC using mysql driverconnect = DriverManager.getConnection( "jdbc:mysql://localhost/countries?"+ "user=root&password=root" );connect.setAutoCommit( false );System.out.println( "Inserting row for Japan..." );String sql = "INSERT INTO COUNTRIES (NAME,POPULATION) VALUES ('JAPAN', '45000000')";PreparedStatement insertStmt = connect.prepareStatement( sql );// insert statement using executeUpdateinsertStmt.executeUpdate( sql );connect.rollback();System.out.println( "Updating row for Japan..." );// update statement using executeUpdate -> will cause an error, update will not be// executed becaues the row does not existsql = "UPDATE COUNTRIES SET POPULATION='1000000' WHERE NAME='JAPAN'";PreparedStatement updateStmt = connect.prepareStatement( sql );updateStmt.executeUpdate( sql );connect.commit();} catch( SQLException ex ) {ex.printStackTrace();//undoes all changes in current transactionconnect.rollback(); } finally {connect.close(); }11. CRUD命令
CRUD來自創(chuàng)建,讀取,更新和刪除。 JDBC支持所有這些操作和命令,在本章中,我們將展示執(zhí)行所有這些操作的Java代碼的不同片段:
創(chuàng)建語句。 可以使用JDBC創(chuàng)建數(shù)據(jù)庫,這是創(chuàng)建內(nèi)存數(shù)據(jù)庫的示例:
// Create a table in memory String countriesTableSQL = "create memory table COUNTRIES (NAME varchar(256) not null primary key, POPULATION varchar(256) not null);";// execute the statement using JDBC normal Statements Statement st = conn.createStatement(); st.execute( countriesTableSQL );插入語句。 JDBC支持插入。 程序員可以使用普通SQL語法,并將它們傳遞給JDBC提供的不同的語句類,例如Statement , PreparedStatement或CallableStatement 。 以下是幾個(gè)示例:
Statement insertStmt = conn.createStatement();String sql = "INSERT INTO COUNTRIES (NAME,POPULATION) VALUES ('SPAIN', '45Mill')"; insertStmt.executeUpdate( sql );sql = "INSERT INTO COUNTRIES (NAME,POPULATION) VALUES ('USA', '200Mill')"; insertStmt.executeUpdate( sql );sql = "INSERT INTO COUNTRIES (NAME,POPULATION) VALUES ('GERMANY', '90Mill')"; insertStmt.executeUpdate( sql );這些語句返回插入的行數(shù)。 這同樣適用于update語句,這是如何更新數(shù)據(jù)庫中的一組行的示例:
System.out.println( "Updating rows for " + name + "..." );Statement updateStmt = conn.createStatement();// update statement using executeUpdateString sql = "UPDATE COUNTRIES SET POPULATION='10000000' WHERE NAME='" + name + "'";int numberRows = updateStmt.executeUpdate( sql );System.out.println( numberRows + " rows updated..." );輸出為:
Updating rows for SPAIN... 4 rows updated...選擇對帳單。 可以使用JDBC語句執(zhí)行任何(幾乎)種類SQL查詢。 這是一個(gè)非常簡單的示例,該示例讀取給定表的所有行并在標(biāo)準(zhǔn)控制臺中將它們打印出來:
Statement statement = conn.createStatement();ResultSet resultSet = statement.executeQuery( "select * from COUNTRIES" );while( resultSet.next() ) {String name = resultSet.getString( "NAME" );String population = resultSet.getString( "POPULATION" );System.out.println( "NAME: " + name );System.out.println( "POPULATION: " + population ); }其輸出為(取決于數(shù)據(jù)庫狀態(tài)):
NAME: GERMANY POPULATION: 90Mill NAME: SPAIN POPULATION: 45Mill NAME: USA POPULATION: 200Mill刪除語句。 最后,JDBC支持刪除行以及刪除表和其他SQL元素。 這是一個(gè)片段,顯示刪除具有特定條件的所有行(在這種情況下,名稱必須為“ JAPAN”):
System.out.println( "Deleting rows for JAPAN..." ); String sql = "DELETE FROM COUNTRIES WHERE NAME='JAPAN'"; PreparedStatement deleteStmt = connect.prepareStatement( sql );// delete statement using executeUpdate int numberRows = deleteStmt.executeUpdate( sql );System.out.println( numberRows + " rows deleted..." );Delete語句返回受影響的行數(shù),在這種情況下,輸出將是(取決于數(shù)據(jù)庫狀態(tài)):
Deleting rows for JAPAN... 0 rows deleted...這些例子都是非常簡單的例子。 它們是出于學(xué)習(xí)目的而編寫的,但是您可以想象,只需更改傳遞給executeQuery()或executeUpdate()方法的參數(shù),就可以執(zhí)行更復(fù)雜SQL查詢。
12. Java 8
Java 8不包含與JDBC或JDBC框架相關(guān)的任何重大更改。 但是,在使用JDBC時(shí),可以應(yīng)用Java 8的多種功能,效果非常好。 我們將展示其中的一些。 例如,有可能以與過去非常不同的方式執(zhí)行選擇查詢。 這是一個(gè)沒有Java 8功能的情況下的示例,它與本文中所有示例中的操作大致相同:
// we always need to write this code System.out.println( "using Java 7" ); // connection to JDBC using mysql driver Class.forName( "com.mysql.jdbc.Driver" ); Connection connect = DriverManager.getConnection( "jdbc:mysql://localhost/countries?"+ "user=root&password=root" );// select query PreparedStatement statement = connect.prepareStatement( "select * from COUNTRIES" ); ResultSet resultSet = statement.executeQuery();// iterating results while( resultSet.next() ) {// access via nameObject name = resultSet.getObject( 1 );Object population = resultSet.getObject( 2 );System.out.println( "Name: " + name );System.out.println( "Population: " + population ); }// close resources, in case of exception resources are not properly cleared resultSet.close(); statement.close(); connect.close();這是一個(gè)使用Lambdas的相同版本。
// select method is called and lambda expression is provided, this expression will be used // in the handle method of the functional interface select( connect, "select * from COUNTRIES", ( resultSet ) -> {System.out.println( resultSet.getObject( 1 ) );System.out.println( resultSet.getObject( 2 ) ); } );上面顯示的這段代碼包含一個(gè)select方法調(diào)用,其中第一個(gè)參數(shù)是Connection對象,第二個(gè)參數(shù)是SQL查詢,第三個(gè)參數(shù)是Lambda表達(dá)式。 該Lambda表達(dá)式接收一個(gè)參數(shù)( ResultSet實(shí)例)并打印出其前兩個(gè)屬性,但是使用Lambda表達(dá)式主體中的該結(jié)果集可以完成任何操作。 這是select()方法的實(shí)現(xiàn):
public static void select( Connection connect, String sql, ResultSetHandler handler ) throws SQLException{PreparedStatement statement = connect.prepareStatement( sql );try (ResultSet rs = statement.executeQuery()){while( rs.next() ){handler.handle( rs );}}}和功能接口ResultSetHandler :
@FunctionalInterface public interface ResultSetHandler {/*** This method will be executed by the lambda expression* * @param resultSet* @throws SQLException*/public void handle( ResultSet resultSet ) throws SQLException;}我們在這里可以看到,使用某些Java 8新功能時(shí),代碼更加清晰,而且大大減少了(或沒有減少)。
13.基于JDBC構(gòu)建的Sql庫
幾個(gè)著名的Java庫使用JDBC來構(gòu)建它們的API。 在本節(jié)中,我們將列出其中一些:
- HSQLDB(超級SQL數(shù)據(jù)庫)是一種關(guān)系數(shù)據(jù)庫管理系統(tǒng),可提供內(nèi)存和持久性存儲。 它具有JDBC驅(qū)動程序(如某些示例所示)。 它具有非持久性功能,并且?guī)缀踔С炙蠸QL核心功能,因此對于測試目的非常有用。 有關(guān)更多信息,請?jiān)L問http://hsqldb.org/
- DBUnit是JUnit的擴(kuò)展。 當(dāng)涉及數(shù)據(jù)庫時(shí),它對于單元測試非常有用。 該框架負(fù)責(zé)測試之間的數(shù)據(jù)庫狀態(tài),并在測試時(shí)抽象出幾個(gè)數(shù)據(jù)庫屬性。 要下載源代碼和更多文檔,請?jiān)L問http://www.dbunit.org
- DBUtils是一個(gè)Apache Commons庫,旨在簡化JDBC的使用。 該庫包含的一些功能包括:清理資源,減少代碼量,更輕松和自動填充結(jié)果集。 該庫小巧,透明且快速,應(yīng)由希望直接使用JDBC的開發(fā)人員使用。 使用此庫需要Java 1.6或更高版本。 有關(guān)更多文檔,請?jiān)L問http://commons.apache.org/proper/commons-dbutils/
- Spring Data還包含與JDBC相關(guān)的模塊。 它被稱為Spring Data JDBC Extensions。 它提供了對JDBC最常用功能的支持。 它提供了用于處理Oracle數(shù)據(jù)庫的特殊功能。 如果您想了解有關(guān)此庫的更多信息,請?jiān)L問http://projects.spring.io/spring-data-jdbc-ext/
- JOOQ是使用JDBC的公司數(shù)據(jù)倉庫中非常有趣的框架。 它從SQL數(shù)據(jù)庫生成Java代碼,并提供API以建立JDBC連接,查詢數(shù)據(jù)并以簡單的方式處理結(jié)果。 有關(guān)更多信息,請?jiān)L問其git hub帳戶: https : //github.com/jOOQ/jOOL 。
14.單元測試
當(dāng)涉及到單元測試和數(shù)據(jù)庫時(shí),總是存在幾個(gè)問題:
- 我們使用什么環(huán)境進(jìn)行測試?
- 我們是否用真實(shí)數(shù)據(jù)進(jìn)行測試?
- 還是我們使用合成的生成數(shù)據(jù)?
- 如果沒有適當(dāng)?shù)膽{據(jù),我們?nèi)绾螠y試數(shù)據(jù)庫?
幾個(gè)庫可以幫助我們完成這些任務(wù)。 在本章中,我們將列出其中一些并提供一些有用的鏈接,在這些鏈接中可以找到更多信息:
- DBUnit:如前所述,DBUnit是一個(gè)與Junit協(xié)作的測試框架。 有關(guān)更多信息,請?jiān)L問http://dbunit.org
- TestNG:此測試框架涵蓋許多測試場景,例如單元測試,功能測試,集成測試等。它基于注釋。 有關(guān)此框架的更多信息,請?jiān)L問其網(wǎng)站: http : //testng.org/doc/index.html
- JOOQ。 該框架提供了JDBC模擬和測試功能。 它是非常有據(jù)可查的,易于使用。 有關(guān)更多信息,請?jiān)L問http://jooq.org
15.總結(jié)
JDBC(Java數(shù)據(jù)庫連接性)是用于Java與大量數(shù)據(jù)庫和數(shù)據(jù)源(從基于SQL的數(shù)據(jù)庫到Excel電子表格)之間的數(shù)據(jù)庫連接性的標(biāo)準(zhǔn)API。 在本教程中,我們試圖解釋JDBC體系結(jié)構(gòu)以及如何使用它。 我們列出了JDBC使用的主要組件,并且列出了一些用于廣泛使用的數(shù)據(jù)庫(例如MySql)的驅(qū)動程序。
要記住的最重要的幾點(diǎn)是:
- 驅(qū)動程序是使Java應(yīng)用程序能夠與數(shù)據(jù)庫一起使用的組件。 JDBC需要每個(gè)特定數(shù)據(jù)庫的驅(qū)動程序。 可以在http://www.oracle.com/technetwork/java/index-136695.html上找到JDBC可用驅(qū)動程序的列表。
- 每次都將SQL語句直接發(fā)送到數(shù)據(jù)庫服務(wù)器。 JDBC包含一種稱為PreparedStatement的機(jī)制,該機(jī)制具有預(yù)定的執(zhí)行路徑,該機(jī)制可提高效率并更好地利用資源。
- 結(jié)果集是用于查詢中的行的表示形式。
- 存儲過程是組合在一起的一組SQL語句,可以按名稱調(diào)用它們,而無需分別調(diào)用它們。
- 事務(wù)是一組SQL語句。 當(dāng)調(diào)用commit()或rollback()時(shí),事務(wù)結(jié)束。 這種分組允許不同的并行工作。
- CRUD命令是create , read , update和delete命令。 JDBC提供了執(zhí)行這些命令的機(jī)制。
本教程包含一些與Java 8有關(guān)的與JDBC有關(guān)的新可能性的信息,例如JOOQ。 我們還提到了一些使用JDBC實(shí)現(xiàn)的重要庫,例如Spring-Data或Apache DBUtils。
16.下載JDBC教程源代碼
下載您可以在此處下載本教程的完整源代碼: jdbc_ultimate_tutorial 。
17.鏈接
除了本文所指向的所有鏈接和資源之外,如果您想了解有關(guān)JDBC API及其功能和機(jī)制的更多信息,可以在Oracle官方網(wǎng)站上找到最新的最佳信息源:
- http://docs.oracle.com/javase/8/docs/api/javax/sql/package-summary.html
- http://docs.oracle.com/javase/8/docs/api/javax/sql/package-summary.html
翻譯自: https://www.javacodegeeks.com/2015/02/jdbc-tutorial.html
jdbc pdf
總結(jié)
以上是生活随笔為你收集整理的jdbc pdf_JDBC教程– ULTIMATE指南(PDF下载)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一只手可以拎走的电脑,打造一台8.4L的
- 下一篇: maf中anglearc_Oracle