[java] Creating a CachedRowSet Object
使用這一行來 create cachedrowset 不知道為何,有時會失敗:
crs = RowSetProvider.newFactory().createCachedRowSet();
最底層會丟出這個 Error:
cachedrowset org.apache.catalina.loader.WebappClassLoaderBase.findResources
使用範例:
常見的比較:
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"
<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。