JDBC面试问题
什么是JDBC API,何時使用它?
Java DataBase Connectivity API允許我們使用關系數據庫。JDBC API接口和類是part java.sql和javax.sqlpackage的一部分。我們可以使用JDBC API來獲取數據庫連接,在數據庫服務器中運行SQL查詢和存儲過程并處理結果。
JDBC API的編寫方式允許我們的Java程序和實際的JDBC驅動程序之間的松散耦合,這使我們可以輕松地從一個數據庫切換到另一個數據庫服務器。
JDBC驅動程序有哪幾種類型?
有四種類型的JDBC驅動程序。任何與數據庫一起工作的java程序都有兩個部分,第一部分是JDBC API,第二部分是執行實際工作的驅動程序。
JDBC-ODBC Bridge加ODBC驅動程序(類型1):它使用ODBC驅動程序連接到數據庫。我們應該安裝ODBC驅動程序來連接數據庫,這就是為什么這個驅動程序幾乎已經過時的原因。
Native API部分支持Java技術的驅動程序(類型2):此驅動程序將JDBC類轉換為數據庫服務器的客戶端API。我們應該安裝數據庫客戶端API。由于對數據庫客戶端API驅動程序的額外依賴性,這也不是首選驅動程序。
用于數據庫中間件的純Java驅動程序(類型3):此驅動程序將JDBC調用發送到可以連接到不同類型數據庫的中間件服務器。我們應該安裝一個中間件服務器來使用這個驅動程序。這增加了額外的網絡調用和性能降低,這就是為什么不廣泛使用JDBC驅動程序。
直接到數據庫的純Java驅動程序(類型4):此驅動程序將JDBC調用轉換為數據庫服務器可以理解的網絡協議。該解決方案簡單,適用于網絡上的數據庫連接。但是對于此解決方案,我們應該使用特定于數據庫的驅動程序,例如Oracle for Oracle DB的OJDBC jar和MySQL Connector的MySQL Connector / J.
JDBC API如何幫助我們實現Java程序和JDBC驅動程序API之間的松散耦合?
JDBC API使用Java Reflection API實現java程序和JDBC驅動程序之間的松散耦合。如果你看一個簡單的JDBC例子,你會發現所有的編程都是用JDBC API完成的,而驅動程序只有在通過反射使用Class.forName()方法加載時才會出現。
我認為這是在核心java類中使用Reflection的最佳示例之一,以確保我們的應用程序不能直接使用Drivers API,這使得從一個數據庫移動到另一個數據庫變得非常容易。
什么是JDBC連接?解釋在簡單的java程序中獲取數據庫連接的步驟。
JDBC Connection就像使用數據庫服務器創建的Session。您還可以將Connection 視為來自數據庫服務器的Socket連接。
創建JDBC連接非常簡單,需要兩個步驟:
注冊并加載驅動程序:使用Class.forName(),驅動程序類注冊到DriverManager并加載到內存中。
使用DriverManager獲取Connection對象:我們DriverManager.getConnection()通過傳遞數據庫URL字符串,用戶名和密碼作為參數來獲取連接對象。
Connection?con?=?null;try{????//?加載驅動類????Class.forName("com.mysql.jdbc.Driver");????//?創建連接????con?=?DriverManager.getConnection("jdbc:mysql://localhost:3306/UserDB",????????????????????"pankaj",????????????????????"pankaj123");????}catch?(SQLException?e)?{????????????System.out.println("Check?database?is?UP?and?configs?are?correct");????????????e.printStackTrace();????}catch?(ClassNotFoundException?e)?{????????????System.out.println("Please?include?JDBC?MySQL?jar?in?classpath");????????????e.printStackTrace();????}JDBC DriverManager類有什么用?
JDBC DriverManager是我們通過它獲取數據庫連接對象的工廠類。當我們加載JDBC Driver類時,它將自己注冊到DriverManager,您可以查找JDBC Driver類源代碼來檢查它。
當我們通過傳遞數據庫配置細節來調用方法DriverManager.getConnection()時,DriverManager使用已注冊的驅動程序來獲取Connection并將其返回給調用者程序。
如何在java程序中獲取數據庫服務器的詳細信息?
我們可以使用DatabaseMetaDataobject來獲取數據庫服務器的詳細信息。成功創建數據庫連接后,我們可以通過調用getMetaData()方法獲取元數據對象。我們可以使用DatabaseMetaData中的方法來獲取數據庫產品名稱,版本和詳細的配置信息。
DatabaseMetaData?metaData?=?con.getMetaData();String?dbProduct?=?metaData.getDatabaseProductName();什么是JDBC Statement?
JDBC API Statement用于在數據庫中執行SQL查詢。我們可以通過調用Connection createStatement()方法來創建Statement對象。我們可以使用Statement通過不同的執行方法傳遞查詢來執行靜態SQL查詢,例如execute(),executeQuery(),executeUpdate()等。
由于查詢是在java程序中生成的,如果未正確驗證用戶輸入,則可能導致SQL注入問題,可以在SQL注入示例中找到更多詳細信息。
默認情況下,每個Statement對象只能同時打開一個ResultSet對象。因此,如果我們想要使用多個ResultSet對象,則每個對象必須由不同的Statement對象生成。Statement接口中的所有execute()方法都隱式關閉一個statment的當前ResultSet對象(如果存在open對象)。
execute,executeQuery,executeUpdate有什么區別?
Statement execute(String query)用于執行任何SQL查詢,如果結果是ResultSet(如運行Select查詢),則返回TRUE。當沒有ResultSet對象(如運行Insert或Update查詢)時,輸出為FALSE。我們可以使用getResultSet()獲取ResultSet和getUpdateCount()方法來檢索更新計數。
Statement executeQuery(String query)用于執行Select查詢并返回ResultSet。即使沒有與查詢匹配的記錄,返回的ResultSet也永遠不會為null。執行select查詢時,我們應該使用executeQuery方法,這樣如果有人試圖執行insert / update語句,它將拋出java.sql.SQLException,并顯示消息“executeQuery方法不能用于更新”。
語句executeUpdate(String query)用于執行不返回任何內容的Insert / Update / Delete(DML)語句或DDL語句。輸出為int,等于SQL數據操作語言(DML)語句的行數。對于DDL語句,輸出為0。
只有在不確定語句類型時才應使用execute()方法,否則使用executeQuery或executeUpdate方法。
什么是JDBC PreparedStatement?
JDBC PreparedStatement對象表示預編譯的SQL語句。我們可以使用它的setter方法來設置查詢的變量。
由于PreparedStatement是預編譯的,因此可以使用它多次有效地執行此語句。PreparedStatement是Statement的更好選擇,因為它會自動轉義特殊字符并避免SQL注入攻擊。
如何在JDBC PreparedStatement中設置NULL值?
我們可以使用PreparedStatement setNull()方法將null變量綁定到參數。例如,setNull方法將index和SQL Types作為參數 ps.setNull(10, java.sql.Types.INTEGER);。
Statement中的getGeneratedKeys()方法有什么用?
有時,表可以使用自動生成的鍵來插入主鍵的唯一列值。我們可以使用Statement getGeneratedKeys()方法獲取此自動生成密鑰的值。
PreparedStatement對Statement有什么好處?
PreparedStatement對Statement的一些好處是:
PreparedStatement幫助我們防止SQL注入攻擊,因為它會自動轉義特殊字符。
PreparedStatement允許我們使用參數輸入執行動態查詢。
PreparedStatement比Statement快。當我們重用PreparedStatement或使用它的批處理方法執行多個查詢時,它變得更加明顯。
PreparedStatement幫助我們使用setter方法編寫面向對象的代碼,而使用Statement我們必須使用String Concatenation來創建查詢。如果要設置多個參數,則使用字符串連接編寫查詢看起來非常難看并且容易出錯。
PreparedStatement的限制是什么以及如何克服它?
PreparedStatement的一個限制是我們不能直接在IN子句中使用它。將PreparedStatement與IN子句一起使用的一些替代方法是:
執行單一查詢 性能非常慢,不推薦使用
使用存儲過程 特定于數據庫,因此不適用于多個數據庫應用程序。
動態創建PreparedStatement查詢 良好的方法但失去了緩存的PreparedStatement的好處。
在PreparedStatement查詢中使用NULL 當您知道變量輸入的最大數量時,這是一種很好的方法,可以通過部分執行來擴展以允許無限制的參數。 可以在JDBC PreparedStatement IN子句替代中找到更詳細的分析。
什么是JDBC ResultSet?
JDBC ResultSet就像一個表示數據庫結果集的數據表,通常通過執行查詢數據庫的語句來生成。
ResultSet對象維護指向其當前數據行的游標。最初,光標位于第一行之前。next()方法將光標移動到下一行。如果沒有更多行,則next()方法返回false,并且可以在while循環中使用它來迭代結果集。
默認的ResultSet對象不可更新,并且只有一個向前移動的游標。因此,您只能迭代一次,并且只能從第一行到最后一行。可以使用以下語法生成可滾動和/或可更新的ResultSet對象。
Statement?stmt?=?con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,???????????????????????????????ResultSet.CONCUR_UPDATABLE);當生成它的Statement對象關閉,重新執行或用于從多個結果序列中檢索下一個結果時,ResultSet對象將自動關閉。
我們可以使用ResultSet getter方法,列名或索引號從1開始檢索列數據。
ResultSet有哪些不同的類型?
在創建Statement時,我們可以根據用戶輸入獲得不同類型的ResultSet對象。如果您將查看Connection方法,您將看到createStatement()和prepareStatement()方法被重載以提供ResultSet類型和并發作為輸入參數。
ResultSet對象有三種類型。
ResultSet.TYPEFORWARDONLY:這是默認類型,游標只能在結果集中向前移動。
ResultSet.TYPESCROLLINSENSITIVE:游標可以前后移動,結果集對創建結果集后其他人對數據庫所做的更改不敏感。
ResultSet.TYPESCROLLSENSITIVE:游標可以向前和向后移動,結果集對創建結果集后其他人對數據庫所做的更改很敏感。 基于并發性,有兩種類型的ResultSet對象。
ResultSet.CONCURREADONLY:結果集是只讀的,這是默認的并發類型。
ResultSet.CONCUR_UPDATABLE:我們可以使用ResultSet更新方法來更新行數據。
Statement中的setFetchSize()和setMaxRows()方法有什么用?
我們可以使用setMaxRows(int i)方法來限制數據庫從查詢返回的行數。您可以使用SQL查詢本身實現相同的功能。例如,在MySQL中,我們可以使用LIMIT子句來設置查詢返回的最大行數。
理解fetchSize可能很棘手,因為你應該知道Statement和ResultSet是如何工作的。當我們在數據庫中執行查詢時,將在數據庫緩存中獲取并維護結果,并返回ResultSet。ResultSet是具有對數據庫中結果的引用的游標。
假設我們有一個返回100行的查詢,并且我們將fetchSize設置為10,因此在每次數據庫訪問時,JDBC驅動程序將只獲取10行,因此將有10次訪問以獲取所有行。如果每行需要大量處理時間并且結果中的行數很大,那么設置最佳fetchSize會很有幫助。
我們可以通過Statement對象設置fetchSize,但可以通過ResultSet對象setFetchSize()方法覆蓋它。
如何使用JDBC API調用存儲過程?
存儲過程是一組SQL查詢,它們在數據庫中編譯,可以從JDBC API執行。JDBC CallableStatement可用于在數據庫中執行存儲過程。初始化CallableStatement的語法是;
CallableStatement?stmt?=?con.prepareCall("{call?insertEmployee(?,?,?,?,?,?)}");stmt.setInt(1,?id);stmt.setString(2,?name);stmt.setString(3,?role);stmt.setString(4,?city);stmt.setString(5,?country);//我們需要在調用存儲過程之前注冊外部參數stmt.registerOutParameter(6,?java.sql.Types.VARCHAR);stmt.executeUpdate();我們需要在執行CallableStatement之前注冊OUT參數。
什么是JDBC批處理,它有什么好處?
有時我們需要為數據庫運行類似的批量查詢,例如將數據從CSV文件加載到關系數據庫表。我們知道我們可以選擇使用Statement或PreparedStatement來執行查詢。除此之外,JDBC API還提供了批處理功能,通過該功能,我們可以一次性為數據庫執行大量查詢。
JDBC API支持通過Statement和PreparedStatement addBatch()以及executeBatch()方法進行批處理。
批處理比一次執行一個語句更快,因為數據庫調用的數量較少。
什么是JDBC事務管理?我們為什么需要它?
默認情況下,當我們創建數據庫連接時,它以自動提交模式運行。這意味著無論何時執行查詢并完成查詢,都會自動觸發提交。因此,我們觸發的每個SQL查詢都是一個事務,如果我們運行一些DML或DDL查詢,則每個SQL語句完成后,更改都會保存到數據庫中。
有時我們希望一組SQL查詢成為事務的一部分,以便我們可以在所有查詢運行正常時提交它們,如果我們得到任何異常,我們可以選擇回滾作為事務的一部分執行的所有查詢。
JDBC API提供了一種方法,setAutoCommit(boolean flag)通過該方法我們可以禁用連接的自動提交功能。我們應該僅在需要時禁用自動提交,因為除非我們在連接上調用commit()方法,否則不會提交事務。數據庫服務器使用表鎖來實現事務管理,這是資源密集型過程。所以我們應該在完成交易后立即提交交易。
如何回滾JDBC事務?
我們可以使用Connection對象rollback()方法來回滾事務。它將回滾事務所做的所有更改,并釋放此Connection對象當前持有的所有數據庫鎖。
什么是JDBC Savepoint?如何使用它?
有時,事務可以是多個語句的組,我們希望回滾到事務中的特定點。JDBC Savepoint幫助我們在事務中創建檢查點,并且我們可以回滾到該特定檢查點。
為事務創建的任何保存點都會自動釋放,并在提交事務時或在回滾整個事務時變為無效。將事務滾動回保存點會自動釋放并使在相關保存點之后創建的任何其他保存點無效。
什么是JDBC DataSource?它的好處是什么?
JDBC DataSource是javax.sql包中定義的接口,它比DriverManager更強大,可用于數據庫連接。我們可以使用DataSource來創建數據庫連接,而Driver實現類可以用來獲取連接的實際工作。除了獲取數據庫連接外,DataSource還提供了一些其他功能,例如:
緩存PreparedStatement以加快處理速度 連接超時設置 記錄功能 ResultSet最大大小閾值 使用JNDI支持在servlet容器中連接池 在JDBC DataSource上閱讀有關DataSource的更多信息。
如何在Apache Tomcat Server中使用JDBC DataSource和JNDI實現JDBC連接池?
對于部署在servlet容器中的Web應用程序,創建JDBC連接池非常簡單,只需要幾個步驟。
在容器配置文件中創建JDBC JNDI資源,通常是server.xml或context.xml。例如
在Web應用程序中,使用InitialContext查找在第一步中配置的JNDI資源,然后獲取連接。
Context?ctx?=?new?InitialContext();DataSource?ds?=?(DataSource)?ctx.lookup("java:/comp/env/jdbc/MyLocalDB");什么是Apache DBCP API?
如果您使用DataSource獲取數據庫連接,通常用于獲取連接的代碼與特定于驅動程序的DataSource實現緊密耦合。除了選擇DataSource實現類之外,大多數代碼都是樣板代碼。
Apache DBCP通過提供DataSource實現來幫助我們擺脫這些問題,DataSource實現充當我們的程序和不同JDBC驅動程序之間的抽象層。Apache DBCP庫依賴于Commons Pool庫,因此請確保它們都在構建路徑中。
什么是JDBC連接隔離級別?
當我們使用JDBC事務來實現數據完整性時,DBMS使用鎖來阻止其他人訪問事務所訪問的數據。DBMS使用鎖來防止臟讀,不可重復讀和幻像讀問題。
DBMS使用JDBC事務隔離級別來使用鎖定機制,我們可以通過Connection getTransactionIsolation()方法獲取隔離級別信息,并使用setTransactionIsolation()方法設置它。
什么是JDBC RowSet?RowSet有哪些類型?
JDBC RowSet以更靈活的方式保存表格數據,即ResultSet。所有RowSet對象都是從ResultSet派生的,因此它們具有ResultSet的所有功能以及一些其他功能。RowSet接口在javax.sql包中定義。
RowSet提供的一些附加功能包括:
具有屬性的Java Bean及其getter-setter方法。RowSet使用JavaBeans事件模型,它們可以向任何已注冊的組件發送通知,用于事件,例如光標移動,更新/插入/刪除行以及更改為RowSet內容。
默認情況下,RowSet對象是可滾動和可更新的,因此如果DBMS不支持可滾動或可更新的ResultSet,我們可以使用RowSet來獲取這些功能。
RowSet大致分為兩種類型:
已連接的RowSet對象 - 這些對象連接到數據庫,與ResultSet對象最相似。JDBC API僅提供一個連接的RowSet對象javax.sql.rowset.JdbcRowSet,它的標準實現類是com.sun.rowset.JdbcRowSetImpl 斷開連接的RowSet對象 - 這些RowSet對象不需要連接到數據庫,因此它們更輕量級且可序列化。它們適合通過網絡發送數據。有四種類型的斷開連接的RowSet實現。
CachedRowSet - 它們可以獲取連接并執行查詢并讀取ResultSet數據以填充RowSet數據。我們可以在數據斷開連接時操作和更新數據,并重新連接到數據庫并寫入更改。 WebRowSet派生自CachedRowSet - 它們可以讀寫XML文檔。 JoinRowSet派生自WebRowSet - 它們可以形成SQL JOIN而無需連接到數據源。 從WebRowSet派生的FilteredRowSet - 我們可以應用過濾條件,以便只有選定的數據可見。
ResultSet和RowSet有什么不同?
RowSet對象派生自ResultSet,因此它們具有ResultSet的所有功能以及一些附加功能。RowSet的一大好處是它們可以斷開連接,使其輕量級,并且易于通過網絡傳輸。
是否使用ResultSet或RowSet取決于您的要求,但如果您計劃使用ResultSet更長的持續時間,則斷開連接的RowSet是釋放數據庫資源的更好選擇。
常見的JDBC異常有哪些?
一些常見的JDBC異常是:
java.sql.SQLException - 這是JDBC異常的基本異常類。 java.sql.BatchUpdateException - 當Batch操作失敗時拋出此異常,但它依賴于JDBC驅動程序是否拋出此異常或基本SQLException。 java.sql.SQLWarning - 用于SQL操作中的警告消息。 java.sql.DataTruncation - 當數據值因超出MaxFieldSize而被意外截斷時。
JDBC中的CLOB和BLOB數據類型是什么?
字符大對象(CLOB)是由具有關聯代碼頁的單字節字符組成的字符串。此數據類型適用于存儲面向文本的信息,其中信息量可能超出常規VARCHAR數據類型的限制(上限為32K字節)。
二進制大對象(BLOB)是由字節組成的二進制字符串,沒有關聯的代碼頁。此數據類型可以存儲大于VARBINARY(32K限制)的二進制數據。此數據類型適用于存儲圖像,語音,圖形和其他類型的業務或特定于應用程序的數據。
什么是JDBC中的“臟讀”?哪個隔離級別可防止臟讀?
當我們處理事務時,有可能更新行,同時其他查詢可以讀取更新的值。這會導致臟讀,因為更新后的值不是永久性的,已更新行的事務可以回滾到先前的值,從而導致無效數據。
隔離級別TRANSACTIONREADCOMMITTED,TRANSACTION_REPEATABLEREAD和TRANSACTIONSERIALIZABLE阻止了臟讀。
什么是2階段提交?
當我們在涉及多個數據庫的分布式系統中工作時,我們需要使用2階段提交協議。2階段提交協議是分布式系統的原子承諾協議。在第一階段,事務管理器向所有事務資源發送commit-request。如果所有事務資源都正常,則事務管理器將為所有資源提交事務更改。如果任何事務資源響應為Abort,則事務管理器可以回滾所有事務更改。
JDBC中有哪些不同類型的鎖定?
從廣義上講,有兩種類型的鎖定機制可以防止數據損壞,因為多個用戶使用相同的數據。
樂觀鎖定 - 使用代碼實現此鎖定。表中引入了一個額外的列以保持更新計數。當您選擇該行時,您也會閱讀此列,比如“version”。現在,當您嘗試更新/刪除行時,將在where子句中傳遞此“version”。因此,如果在其間執行其他線程的更新,則更新將失敗。這是避免數據損壞的好方法,但如果有人錯過更新其更新語句中的“version”,則可能容易出錯。通過這種鎖定方式,更新查詢看起來如下所示。
悲觀鎖定 - 將記錄從選擇鎖定到讀取,更新和提交階段。這通常由數據庫供應商軟件完成,并通過使用SELECT FOR UPDATE查詢觸發。如果線程處理鎖定較長時間,則這種鎖定行的方式可能導致性能降低和死鎖。
除此之外,一些DBMS系統提供鎖定機制來鎖定單行,表或數據庫。
你對DDL和DML語句有什么了解?
數據定義語言(DDL)語句用于定義數據庫模式。創建,更改,刪除,截斷,重命名語句屬于DDL語句,通常它們不返回任何結果。
數據操作語言(DML)語句用于操縱數據庫模式中的數據。選擇,插入,更新,刪除,調用等是DML語句的示例。
java.util.Date和java.sql.Date有什么區別?
java.util.Date包含有關日期和時間的信息,而java.sql.Date包含僅有關日期的信息,它沒有時間信息。因此,如果您必須在數據庫中保留時間信息,建議使用Timestamp或DateTime字段。
如何將圖像或原始數據插入數據庫?
我們可以使用BLOB將圖像或原始二進制數據插入數據庫。
什么是幻像讀取以及哪種隔離級別阻止了它?
虛擬讀取是指事務多次執行查詢并獲取不同數據的情況。假設事務正在執行查詢以根據條件獲取數據,然后另一個事務插入與條件匹配的行。現在,當同一事務再次執行查詢時,新行將成為結果集的一部分。這個新行被稱為Phantom Row,這種情況稱為Phantom Read。
只有使用TRANSACTION_SERIALIZABLE隔離級別才能阻止幻像讀取。
什么是SQL警告?如何在JDBC程序中檢索SQL警告?
SQLWarning是SQLException的子類,我們可以通過在Connection,Statement和ResultSet對象上調用getWarnings()方法來檢索它。SQL警告不會停止腳本的執行,但會警告用戶警告。
如何使用數據庫對象作為IN / OUT調用Oracle存儲過程?
如果Oracle存儲過程具有作為數據庫對象的IN / OUT參數,那么我們需要在程序中創建相同大小的Object數組,然后使用它來創建Oracle STRUCT對象。然后我們可以通過調用setSTRUCT()方法為數據庫對象設置此STRUCT對象并使用它。
我們什么時候得到java.sql.SQLException:找不到合適的驅動程序?
當SQL URL字符串格式不正確時,您將得到沒有合適的驅動程序發現異常。您可以在使用DriverManager的簡單Java應用程序或使用DataSource的JNDI資源中獲取此異常。異常堆棧跟蹤如下所示。
在調試此異常時,只需檢查日志中打印的URL,如上面的日志中URL URL是'jdbc:mysql:// localhost:3306 / UserDB,而它應該是jdbc:mysql:// localhost:3306 / UserDB 。
JDBC有哪些最佳實踐?
一些JDBC最佳實踐是:
數據庫資源很重,因此請確保在完成后立即關閉它。Connection,Statement,ResultSet和所有其他JDBC對象都定義了close()方法來關閉它們。?
始終在代碼中顯式關閉結果集,語句和連接,因為如果您在連接池環境中工作,則可能會將連接返回到池,從而導致打開的結果集和語句對象導致資源泄漏。?
關閉finally塊中的資源,以確保即使在異常情況下它們也會關閉。?
使用批處理進行類似的批量操作。?
始終對Statement使用PreparedStatement以避免SQL注入并獲得PreparedStatement的預編譯和緩存優勢。?
如果要將批量數據檢索到結果集中,則為fetchSize設置最佳值有助于獲得良好的性能。?
數據庫服務器可能不支持所有隔離級別,因此請在假設之前進行檢查。?
更嚴格的隔離級別會導致性能降低,因此請確保為數據庫連接設置了最佳隔離級別。?
如果要在Web應用程序中創建數據庫連接,請嘗試使用JNDI上下文使用JDBC DataSource資源來重用連接。?
當您需要長時間使用ResultSet時,請嘗試使用斷開連接的RowSet。
總結
- 上一篇: editplus html格式化,Edi
- 下一篇: Java游戏聊斋聂小倩_《聊斋倩女幽魂》