JDBC常見面試題集錦(二)

deepinmind發表於2014-03-19

  JDBC的儲存點(Savepoint)是什麼,如何使用?

  有時候事務包含了一組語句,而我們希望回滾到這個事務的某個特定的點。JDBC的儲存點可以用來生成事務的一個檢查點,使得事務可以回滾到這個檢查點。

  一旦事務提交或者回滾了,它生成的任何儲存點都會自動釋放並失效。回滾事務到某個特定的儲存點後,這個儲存點後所有其它的儲存點會自動釋放並且失效。可以讀下這個瞭解更多關於JDBC Savepoint的資訊。

  JDBC的DataSource是什麼,有什麼好處?

  DataSource即資料來源,它是定義在javax.sql中的一個介面,跟DriverManager相比,它的功能要更強大。我們可以用它來建立資料庫連線,當然驅動的實現類會實際去完成這個工作。除了能建立連線外,它還提供瞭如下的特性:

  • 快取PreparedStatement以便更快的執行
  • 可以設定連線超時時間
  • 提供日誌記錄的功能
  • ResultSet大小的最大閾值設定
  • 通過JNDI的支援,可以為servlet容器提供連線池的功能

  關於JDBC資料來源的示例請看下這裡

  如何通過JDBC的DataSource和Apache Tomcat的JNDI來建立連線池?

  對部署在servlet容器中的WEB程式而言,建立資料庫連線池非常簡單,僅需要以下幾步。

  • 在容器的配置檔案中建立JDBC的JNDI資源,通常在server.xml或者context.xml裡面。像這樣:
    <Resource name="jdbc/MyDB"
          global="jdbc/MyDB"
          auth="Container"
          type="javax.sql.DataSource"
          driverClassName="com.mysql.jdbc.Driver"
          url="jdbc:mysql://localhost:3306/UserDB"
          username="pankaj"
          password="pankaj123"
          maxActive="100"
          maxIdle="20"
          minIdle="5"
          maxWait="10000"/>
    
    <ResourceLink name="jdbc/MyLocalDB"
                    global="jdbc/MyDB"
                    auth="Container"
                    type="javax.sql.DataSource" />
    
  • 在WEB應用程式中,先用InitialContext來查詢JNDI資源,然後獲取連線。
    Context ctx = new InitialContext();
    DataSource ds = (DataSource) ctx.lookup("java:/comp/env/jdbc/MyLocalDB");
    
    完整的示例請看這裡

  Apache的DBCP是什麼?

  如果用DataSource來獲取連線的話,通常獲取連線的程式碼和驅動特定的DataSource是緊耦合的。另外,除了選擇DataSource的實現類,剩下的程式碼基本都是一樣的。

  Apache的DBCP就是用來解決這些問題的,它提供的DataSource實現成為了應用程式和不同JDBC驅動間的一個抽象層。Apache的DBCP庫依賴commons-pool庫,所以要確保它們都在部署路徑下。

  完整的使用示例請看這裡

  什麼是資料庫的隔離級別?

  當我們為了資料的一致性使用事務時,資料庫系統用鎖來防止別人訪問事務中用到的資料。資料庫通過鎖來防止髒讀,不可重複讀(Non-Repeatable Reads)及幻讀(Phantom-Read)的問題。

  資料庫使用JDBC設定的隔離級別來決定它使用何種鎖機制,我們可以通過Connection的getTransactionIsolation和setTransactionIsolation方法來獲取和設定資料庫的隔離級別。

隔離級別 事務 髒讀 不可重複讀 幻讀
TRANSACTION_NONE 不支援 不可用 不可用 不可用
TRANSACTION_READ_COMMITTED 支援 阻止 允許 允許
TRANSACTION_READ_UNCOMMITTED 支援 允許 允許 允許
TRANSACTION_REPEATABLE_READ 支援 阻止 阻止 允許
TRANSACTION_SERIALIZABLE 支援 阻止 阻止 阻止

  JDBC的RowSet是什麼,有哪些不同的RowSet?

  RowSet用於儲存查詢的資料結果,和ResultSet相比,它更具靈活性。RowSet繼承自ResultSet,因此ResultSet能幹的,它們也能,而ResultSet做不到的,它們還是可以。RowSet介面定義在javax.sql包裡。

  RowSet提供的額外的特性有:

  • 提供了Java Bean的功能,可以通過settter和getter方法來設定和獲取屬性。RowSet使用了JavaBean的事件驅動模型,它可以給註冊的元件傳送事件通知,比如遊標的移動,行的增刪改,以及RowSet內容的修改等。
  • RowSet物件預設是可滾動,可更新的,因此如果資料庫系統不支援ResultSet實現類似的功能,可以使用RowSet來實現。

  RowSet分為兩大類:

  A. 連線型RowSet——這類物件與資料庫進行連線,和ResultSet很類似。JDBC介面只提供了一種連線型RowSet,javax.sql.rowset.JdbcRowSet,它的標準實現是com.sun.rowset.JdbcRowSetImpl。 B. 離線型RowSet——這類物件不需要和資料庫進行連線,因此它們更輕量級,更容易序列化。它們適用於在網路間傳遞資料。有四種不同的離線型RowSet的實現。

  • CachedRowSet——可以通過他們獲取連線,執行查詢並讀取ResultSet的資料到RowSet裡。我們可以在離線時對資料進行維護和更新,然後重新連線到資料庫裡,並回寫改動的資料。
  • WebRowSet繼承自CachedRowSet——他可以讀寫XML文件。
  • JoinRowSet繼承自WebRowSet——它不用連線資料庫就可以執行SQL的join操作。
  • FilteredRowSet繼承自WebRowSet——我們可以用它來設定過濾規則,這樣只有選中的資料才可見。

  RowSet和ResultSet的區別是什麼?

  RowSet繼承自ResultSet,因此它有ResultSet的全部功能,同時它自己新增了些額外的特性。RowSet一個最大的好處是它可以是離線的,這樣使得它更輕量級,同時便於在網路間進行傳輸。

  具體使用哪個取決於你的需求,不過如果你操作ResultSet物件的時間較長的話,最好選擇一個離線的RowSet,這樣可以釋放資料庫連線。

  常見的JDBC異常有哪些?

  有以下這些:

  • java.sql.SQLException——這是JDBC異常的基類。
  • java.sql.BatchUpdateException——當批處理操作執行失敗的時候可能會丟擲這個異常。這取決於具體的JDBC驅動的實現,它也可能直接丟擲基類異常java.sql.SQLException。
  • java.sql.SQLWarning——SQL操作出現的警告資訊。
  • java.sql.DataTruncation——欄位值由於某些非正常原因被截斷了(不是因為超過對應欄位型別的長度限制)。

  JDBC裡的CLOB和BLOB資料型別分別代表什麼?

  CLOB意思是Character Large OBjects,字元大物件,它是由單位元組字元組成的字串資料,有自己專門的內碼表。這種資料型別適用於儲存超長的文字資訊,那些可能會超出標準的VARCHAR資料型別長度限制(上限是32KB)的文字。

  BLOB是Binary Larget OBject,它是二進位制大物件,由二進位制資料組成,沒有專門的內碼表。它能用於儲存超過VARBINARY限制(32KB)的二進位制資料。這種資料型別適合儲存圖片,聲音,圖形,或者其它業務程式特定的資料。

  JDBC的髒讀是什麼?哪種資料庫隔離級別能防止髒讀?

  當我們使用事務時,有可能會出現這樣的情況,有一行資料剛更新,與此同時另一個查詢讀到了這個剛更新的值。這樣就導致了髒讀,因為更新的資料還沒有進行持久化,更新這行資料的業務可能會進行回滾,這樣這個資料就是無效的。

  資料庫的TRANSACTIONREADCOMMITTED,TRANSACTIONREPEATABLEREAD,和TRANSACTION_SERIALIZABLE隔離級別可以防止髒讀。

  什麼是兩階段提交?

  當我們在分散式系統上同時使用多個資料庫時,這時候我們就需要用到兩階段提交協議。兩階段提交協議能保證是分散式系統提交的原子性。在第一個階段,事務管理器發所有的事務參與者傳送提交的請求。如果所有的參與者都返回OK,它會向參與者正式提交該事務。如果有任何一個參與方返回了中止訊息,事務管理器會回滾所有的修改動作。

  JDBC中存在哪些不同型別的鎖?

  從廣義上講,有兩種鎖機制來防止多個使用者同時操作引起的資料損壞。

  樂觀鎖——只有當更新資料的時候才會鎖定記錄。 悲觀鎖——從查詢到更新和提交整個過程都會對資料記錄進行加鎖。

  不僅如此,一些資料庫系統還提供了行鎖,表鎖等鎖機制。

  DDL和DML語句分別代表什麼?

  DDL(資料定義語言,Data Definition Language)語句用來定義資料庫模式。Create,Alter, Drop, Truncate, Rename都屬於DDL語句,一般來說,它們是不返回結果的。

  DML(資料操作語言,Data Manipulation Language)語句用來運算元據庫中的資料。select, insert, update, delete, call等,都屬於DML語句。

  java.util.Date和java.sql.Date有什麼區別?

  java.util.Date包含日期和時間,而java.sql.Date只包含日期資訊,而沒有具體的時間資訊。如果你想把時間資訊儲存在資料庫裡,可以考慮使用Timestamp或者DateTime欄位。

  如何把圖片或者原始資料插入到資料庫中?

  可以使用BLOB型別將圖片或者原始的二進位制資料儲存到資料庫裡。

  什麼是幻讀,哪種隔離級別可以防止幻讀?

  幻讀是指一個事務多次執行一條查詢返回的卻是不同的值。假設一個事務正根據某個條件進行資料查詢,然後另一個事務插入了一行滿足這個查詢條件的資料。之後這個事務再次執行了這條查詢,返回的結果集中會包含剛插入的那條新資料。這行新資料被稱為幻行,而這種現象就叫做幻讀。

  只有TRANSACTION_SERIALIZABLE隔離級別才能防止產生幻讀。

  SQLWarning是什麼,在程式中如何獲取SQLWarning?

  SQLWarning是SQLException的子類,通過Connection, Statement, Result的getWarnings方法都可以獲取到它。 SQLWarning不會中斷查詢語句的執行,只是用來提示使用者存在相關的警告資訊。

  如果Oracle的儲存過程的入參出參中包含資料庫物件,應該如何進行呼叫?

  如果Oracle的儲存過程的入參出參中包含資料庫物件,我們需要在程式建立一個同樣大小的物件陣列,然後用它來生成Oracle的STRUCT物件。然後可以通過資料庫物件的setSTRUCT方法傳入這個struct物件,並對它進行使用。

  如果java.sql.SQLException: No suitable driver found該怎麼辦?

  如果你的SQL URL串格式不正確的話,就會丟擲這樣的異常。不管是使用DriverManager還是JNDI資料來源來建立連線都有可能丟擲這種異常。它的異常棧看起來會像下面這樣。

org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot create JDBC driver of class 'com.mysql.jdbc.Driver' for connect URL ''jdbc:mysql://localhost:3306/UserDB'
    at org.apache.tomcat.dbcp.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1452)
    at org.apache.tomcat.dbcp.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1371)
    at org.apache.tomcat.dbcp.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
java.sql.SQLException: No suitable driver found for 'jdbc:mysql://localhost:3306/UserDB
    at java.sql.DriverManager.getConnection(DriverManager.java:604)
    at java.sql.DriverManager.getConnection(DriverManager.java:221)
    at com.journaldev.jdbc.DBConnection.getConnection(DBConnection.java:24)
    at com.journaldev.jdbc.DBConnectionTest.main(DBConnectionTest.java:15)
Exception in thread "main" java.lang.NullPointerException
    at com.journaldev.jdbc.DBConnectionTest.main(DBConnectionTest.java:16)

  解決這類問題的方法就是,檢查下日誌檔案,像上面的這個日誌中,URL串是'jdbc:mysql://localhost:3306/UserDB,只要把它改成jdbc:mysql://localhost:3306/UserDB就好了。

  什麼是JDBC的最佳實踐?

  下面列舉了其中的一些:

  • 資料庫資源是非常昂貴的,用完了應該儘快關閉它。Connection, Statement, ResultSet等JDBC物件都有close方法,呼叫它就好了。
  • 養成在程式碼中顯式關閉掉ResultSet,Statement,Connection的習慣,如果你用的是連線池的話,連線用完後會放回池裡,但是沒有關閉的ResultSet和Statement就會造成資源洩漏了。
  • 在finally塊中關閉資源,保證即便出了異常也能正常關閉。
  • 大量類似的查詢應當使用批處理完成。
  • 儘量使用PreparedStatement而不是Statement,以避免SQL隱碼攻擊,同時還能通過預編譯和快取機制提升執行的效率。
  • 如果你要將大量資料讀入到ResultSet中,應該合理的設定fetchSize以便提升效能。
  • 你用的資料庫可能沒有支援所有的隔離級別,用之前先仔細確認下。
  • 資料庫隔離級別越高效能越差,確保你的資料庫連線設定的隔離級別是最優的。
  • 如果在WEB程式中建立資料庫連線,最好通過JNDI使用JDBC的資料來源,這樣可以對連線進行重用。
  • 如果你需要長時間對ResultSet進行操作的話,儘量使用離線的RowSet。

  譯註:終於翻譯完了,希望能對你的面試有所幫助。拿個好offer!

  相關文件:JDBC常見面試題集錦(一)

  英文來源:http://www.journaldev.com/2529/jdbc-interview-questions-and-answers

相關文章