什么是JDBC,在什么時候會用到它?
JDBC的全稱是Java DataBase Connection,也就是Java數據庫連接,我們可以用它來操作關系型數據庫。JDBC接口及相關類在java.sql包和javax.sql包里。我們可以用它來連接數據庫,執行SQL查詢,存儲過程,並處理返回的結果。
JDBC接口讓Java程序和JDBC驅動實現了松耦合,使得切換不同的數據庫變得更加簡單。
有哪些不同類型的JDBC驅動?
有四類JDBC驅動。和數據庫進行交互的Java程序分成兩個部分,一部分是JDBC的API,實際工作的驅動則是另一部分。

A JDBC-ODBC Bridge plus ODBC Driver(類型1):它使用ODBC驅動連接數據庫。需要安裝ODBC以便連接數據庫,正因為這樣,這種方式現在已經基本淘汰了。
B Native API partly Java technology-enabled driver(類型2):這種驅動把JDBC調用適配成數據庫的本地接口的調用。
C Pure Java Driver for Database Middleware(類型3):這個驅動把JDBC調用轉發給中間件服務器,由它去和不同的數據庫進行連接。用這種類型的驅動需要部署中間件服務器。這種方式增加了額外的網絡調用,導致性能變差,因此很少使用。
D Direct-to-Database Pure Java Driver(類型4):這個驅動把JDBC轉化成數據庫使用的網絡協議。這種方案最簡單,也適合通過網絡連接數據庫。不過使用這種方式的話,需要根據不同數據庫選用特定的驅動程序,比如OJDBC是Oracle開發的Oracle數據庫的驅動,而MySQL Connector/J是MySQL數據庫的驅動。
JDBC是如何實現Java程序和JDBC驅動的松耦合的?
JDBC API使用Java的反射機制來實現Java程序和JDBC驅動的松耦合。隨便看一個簡單的JDBC示例,你會發現所有操作都是通過JDBC接口完成的,而驅動只有在通過Class.forName反射機制來加載的時候才會出現。
我覺得這是Java核心庫里反射機制的最佳實踐之一,它使得應用程序和驅動程序之間進行了隔離,讓遷移數據庫的工作變得更簡單。在這里可以看到更多JDBC的使用示例。
什么是JDBC連接,在Java中如何創建一個JDBC連接?
JDBC連接是和數據庫服務器建立的一個會話。你可以想像成是一個和數據庫的Socket連接。
創建JDBC連接很簡單,只需要兩步:
A. 注冊並加載驅動:使用Class.forName(),驅動類就會注冊到DriverManager里面並加載到內存里。 B. 用DriverManager獲取連接對象:調用DriverManager.getConnnection()方法並傳入數據庫連接的URL,用戶名及密碼,就能獲取到連接對象。
1 Connection con = null; 2 try{ 3 // load the Driver Class 4 Class.forName("com.mysql.jdbc.Driver"); 5 // create the connection now 6 con = DriverManager.getConnection("jdbc:mysql://localhost:3306/DBName", 7 "username", 8 "password"); 9 }catch (SQLException e) { 10 System.out.println("Check database is UP and configs are correct"); 11 e.printStackTrace(); 12 }catch (ClassNotFoundException e) { 13 System.out.println("Please include JDBC MySQL jar in classpath"); 14 e.printStackTrace(); 15 } 16 }
JDBC的DriverManager是用來做什么的?
JDBC的DriverManager是一個工廠類,我們通過它來創建數據庫連接。當JDBC的Driver類被加載進來時,它會自己注冊到DriverManager類里面,你可以看下JDBC Driver類的源碼來了解一下。
然后我們會把數據庫配置信息傳成DriverManager.getConnection()方法,DriverManager會使用注冊到它里面的驅動來獲取數據庫連接,並返回給調用的程序。
在Java程序中,如何獲取數據庫服務器的相關信息?
使用DatabaseMetaData可以獲取到服務器的信息。當和數據庫的連接成功建立了之后,可以通過調用getMetaData()方法來獲取數據庫的元信息。DatabaseMetaData里面有很多方法,通過它們可以獲取到數據庫的產品名稱,版本號,配置信息等。
DatabaseMetaData metaData = con.getMetaData();
String dbProduct = metaData.getDatabaseProductName();
JDBC的Statement是什么?
Statement是JDBC中用來執行數據庫SQL查詢語句的接口。通過調用連接對象的getStatement()方法我們可以生成一個Statement對象。我們可以通過調用它的execute(),executeQuery(),executeUpdate()方法來執行靜態SQL查詢。
由於SQL語句是程序中傳入的,如果沒有對用戶輸入進行校驗的話可能會引起SQL注入的問題,如果想了解更多關於SQL注入的,可以看下這里。
默認情況下,一個Statement同時只能打開一個ResultSet。如果想操作多個ResultSet對象的話,需要創建多個Statement。Statement接口的所有execute方法開始執行時都默認會關閉當前打開的ResultSet。
execute,executeQuery,executeUpdate的區別是什么?
Statement的execute(String query)方法用來執行任意的SQL查詢,如果查詢的結果是一個ResultSet,這個方法就返回true。如果結果不是ResultSet,比如insert或者update查詢,它就會返回false。我們可以通過它的getResultSet方法來獲取ResultSet,或者通過getUpdateCount()方法來獲取更新的記錄條數。
Statement的executeQuery(String query)接口用來執行select查詢,並且返回ResultSet。即使查詢不到記錄返回的ResultSet也不會為null。我們通常使用executeQuery來執行查詢語句,這樣的話如果傳進來的是insert或者update語句的話,它會拋出錯誤信息為 “executeQuery method can not be used for update”的java.util.SQLException。
Statement的executeUpdate(String query)方法用來執行insert或者update/delete(DML)語句,或者 什么也不返回DDL語句。返回值是int類型,如果是DML語句的話,它就是更新的條數,如果是DDL的話,就返回0。
只有當你不確定是什么語句的時候才應該使用execute()方法,否則應該使用executeQuery或者executeUpdate方法。
JDBC的PreparedStatement是什么?
PreparedStatement對象代表的是一個預編譯的SQL語句。用它提供的setter方法可以傳入查詢的變量。
由於PreparedStatement是預編譯的,通過它可以將對應的SQL語句高效的執行多次。由於PreparedStatement自動對特殊字符轉義,避免了SQL注入攻擊,因此應當盡量的使用它。
PreparedStatement中如何注入NULL值?
可以使用它的setNull方法來把null值綁定到指定的變量上。setNull方法需要傳入參數的索引以及SQL字段的類型,像這樣:
ps.setNull(10, java.sql.Types.INTEGER);.
Statement中的getGeneratedKeys方法有什么用?
有的時候表會生成主鍵,這時候就可以用Statement的getGeneratedKeys()方法來獲取這個自動生成的主鍵的值了。
相對於Statement,PreparedStatement的優點是什么?
它和Statement相比優點在於:
- PreparedStatement有助於防止SQL注入,因為它會自動對特殊字符轉義。
- PreparedStatement可以用來進行動態查詢。
- PreparedStatement執行更快。尤其當你重用它或者使用它的拼量查詢接口執行多條語句時。
- 使用PreparedStatement的setter方法更容易寫出面向對象的代碼,而Statement的話,我們得拼接字符串來生成查詢語句。如果參數太多了,字符串拼接看起來會非常丑陋並且容易出錯。
PreparedStatement的缺點是什么,怎么解決這個問題?
PreparedStatement的一個缺點是,我們不能直接用它來執行in條件語句;需要執行IN條件語句的話,下面有一些解決方案:
- 分別進行單條查詢——這樣做性能很差,不推薦。
- 使用存儲過程——這取決於數據庫的實現,不是所有數據庫都支持。
- 動態生成PreparedStatement——這是個好辦法,但是不能享受PreparedStatement的緩存帶來的好處了。
- 在PreparedStatement查詢中使用NULL值——如果你知道輸入變量的最大個數的話,這是個不錯的辦法,擴展一下還可以支持無限參數。
關於這個問題更詳細的分析可以看下這篇文章。
JDBC的ResultSet是什么?
在查詢數據庫后會返回一個ResultSet,它就像是查詢結果集的一張數據表。
ResultSet對象維護了一個游標,指向當前的數據行。開始的時候這個游標指向的是第一行。如果調用了ResultSet的next()方法游標會下移一行,如果沒有更多的數據了,next()方法會返回false。可以在for循環中用它來遍歷數據集。
默認的ResultSet是不能更新的,游標也只能往下移。也就是說你只能從第一行到最后一行遍歷一遍。不過也可以創建可以回滾或者可更新的ResultSet,像下面這樣。
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
當生成ResultSet的Statement對象要關閉或者重新執行或是獲取下一個ResultSet的時候,ResultSet對象也會自動關閉。
可以通過ResultSet的getter方法,傳入列名或者從1開始的序號來獲取列數據。
有哪些不同的ResultSet?
根據創建Statement時輸入參數的不同,會對應不同類型的ResultSet。如果你看下Connection的方法,你會發現createStatement和prepareStatement方法重載了,以支持不同的ResultSet和並發類型。
一共有三種ResultSet對象。
- ResultSet.TYPE_FORWARD_ONLY:這是默認的類型,它的游標只能往下移。
- ResultSet.TYPE_SCROLL_INSENSITIVE:游標可以上下移動,一旦它創建后,數據庫里的數據再發生修改,對它來說是透明的。
- ResultSet.TYPE_SCROLL_SENSITIVE:游標可以上下移動,如果生成后數據庫還發生了修改操作,它是能夠感知到的。
ResultSet有兩種並發類型。
- ResultSet.CONCUR_READ_ONLY:ResultSet是只讀的,這是默認類型。
- ResultSet.CONCUR_UPDATABLE:我們可以使用ResultSet的更新方法來更新里面的數據。
Statement中的setFetchSize和setMaxRows方法有什么用處?
setMaxRows可以用來限制返回的數據集的行數。當然通過SQL語句也可以實現這個功能。比如在MySQL中我們可以用LIMIT條件來設置返回結果的最大行數。
setFetchSize理解起來就有點費勁了,因為你得知道Statement和ResultSet是怎么工作的。當數據庫在執行一條查詢語句時,查詢到的數據是在數據庫的緩存中維護的。ResultSet其實引用的是數據庫中緩存的結果。
假設我們有一條查詢返回了100行數據,我們把fetchSize設置成了10,那么數據庫驅動每次只會取10條數據,也就是說得取10次。當每條數據需要處理的時間比較長的時候並且返回數據又非常多的時候,這個可選的參數就變得非常有用了。
我們可以通過Statement來設置fetchSize參數,不過它會被ResultSet對象設置進來的值所覆蓋掉。
如何使用JDBC接口來調用存儲過程?
存儲過程就是數據庫編譯好的一組SQL語句,可以通過JDBC接口來進行調用。我們可以通過JDBC的CallableStatement接口來在數據庫中執行存儲過程。初始化CallableStatement的語法是這樣的:
1 CallableStatement stmt = con.prepareCall("{call insertEmployee(?,?,?,?,?,?)}"); 2 stmt.setInt(1, id); 3 stmt.setString(2, name); 4 stmt.setString(3, role); 5 stmt.setString(4, city); 6 stmt.setString(5, country); 7 //register the OUT parameter before calling the stored procedure 8 stmt.registerOutParameter(6, java.sql.Types.VARCHAR); 9 stmt.executeUpdate();
我們得在執行CallableStatement之前注冊OUT參數。關於這個更詳細的資料可以看這里。
JDBC的批處理是什么,有什么好處?
有時候類似的查詢我們需要執行很多遍,比如從CSV文件中加載數據到關系型數據庫的表里。我們也知道,執行查詢可以用Statement或者PreparedStatement。除此之外,JDBC還提供了批處理的特性,有了它,我們可以在一次數據庫調用中執行多條查詢語句。
JDBC通過Statement和PreparedStatement中的addBatch和executeBatch方法來支持批處理。
批處理比一條條語句執行的速度要快得多,因為它需要很少的數據庫調用,想進一步了解請點這里。
JDBC的事務管理是什么,為什么需要它?
默認情況下,我們創建的數據庫連接,是工作在自動提交的模式下的。這意味着只要我們執行完一條查詢語句,就會自動進行提交。因此我們的每條查詢,實際上都是一個事務,如果我們執行的是DML或者DDL,每條語句完成的時候,數據庫就已經完成修改了。
有的時候我們希望由一組SQL查詢組成一個事務,如果它們都執行OK我們再進行提交,如果中途出現異常了,我們可以進行回滾。
JDBC接口提供了一個setAutoCommit(boolean flag)方法,我們可以用它來關閉連接自動提交的特性。我們應該在需要手動提交時才關閉這個特性,不然的話事務不會自動提交,每次都得手動提交。數據庫通過表鎖來管理事務,這個操作非常消耗資源。因此我們應當完成操作后盡快的提交事務。在這里有更多關於事務的示例程序。
如何回滾事務?
通過Connection對象的rollback方法可以回滾事務。它會回滾這次事務中的所有修改操作,並釋放當前連接所持有的數據庫鎖。
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里面。像這樣:
1 <Resource name="jdbc/MyDB" 2 global="jdbc/MyDB" 3 auth="Container" 4 type="javax.sql.DataSource" 5 driverClassName="com.mysql.jdbc.Driver" 6 url="jdbc:mysql://localhost:3306/UserDB" 7 username="pankaj" 8 password="pankaj123" 9 maxActive="100" 10 maxIdle="20" 11 minIdle="5" 12 maxWait="10000"/> 13 <ResourceLink name="jdbc/MyLocalDB" 14 global="jdbc/MyDB" 15 auth="Container" 16 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。
