Java JDBC基本使用方法詳解
本文例項講述了Java JDBC基本使用方法。分享給大家供大家參考,具體如下:
本文內容:
- 什麼是JDBC
- JDBC的使用
- 事務
- 連線池
- DbUtils
首發日期:2018-05-27
修改:
- 2018-07-19:增加了事務、連線池、DBUtils
- 2018-07-27:對特別情況下的事務進行了描述。對DBUtils增加了關閉資源、關閉流。連線池發現漏了釋放連線。
什麼是JDBC:
- JDBC全稱Java Database Connectivity
- JDBC可以通過載入不同的資料庫的“驅動程式”而與不同的資料庫進行連線。
JDBC的優點:
- 使用的驅動不同,即可連線不同的資料庫。
- 使用同一套操作來操作不同的資料庫
- 如果每一個數據庫java都制訂一套連線方式,那麼當不同的資料庫更新的時候,java也需要更新自己的程式碼,而使用jdbc,使用同一套程式碼來操作,使用不同的驅動程式(驅動程式由資料庫廠商提供)來連線,這使得可以連線不同的資料庫。
JDBC的使用:
匯入對應資料庫的驅動類:
- 1.在對應的資料庫廠商網站獲取對應的jar包
- 2.將對應的jar包新增到引用。
- 在eclipse中可以將jar包匯入一個資料夾後,右鍵Build Path -> add to path就可以將jar包新增到當前專案引用的庫裡面。
載入驅動:
PS:
- 在上面的forName中,執行了註冊驅動,註冊驅動這個程式碼被定義在驅動類的靜態程式碼塊中。
- 對於一些新手,使用的方法可能是,對於這種情況,那麼他可以使用driver或DriverManager.getConnection來獲取資料庫連線物件;而對於另外一些新手,他們可能會使用,然後再通過DriverManager.getConnection來獲取資料庫連線物件。但本質上,這是一種浪費,因為靜態程式碼塊中已經靜態生成了一個驅動物件並使用DriverManager.registerDriver註冊了,所以上面兩種都是浪費。使用forName後,可以使用DriverManager.getConnection來獲取資料庫連線物件。
獲取連線:
- 在考慮使用forName節省資源後,下面介紹的獲取連線的方法使用的是DriverManager.getConnection
- getConnection需要引數
- url:定義了連線的資料庫的路徑
- jdbc協議:資料庫子協議:主機[:埠][/連線的資料庫] 【[]代表可選的】
- 例如:jdbc:mysql://localhost:3306/test
- 配置流Properties:定義了連線資料庫的方式,一般至少包含user和password
- 不使用配置流時,傳入user和password
- 如果使用匿名登入,則只傳入url
- url:定義了連線的資料庫的路徑
執行SQL語句:
JDBC執行SQL語句的方式主要有三種:
1.使用Statement
執行sql語句
2.使用PreparedStatement執行sql語句
3.使用CallableStatement
執行sql語句
上面的Statement、PerPareStatement、Callalestatement都可以使用連線物件來獲取。
- 使用
Statement
執行語句Statement
物件的獲取可以使用createStatement()
來獲取- 獲取
Statement
物件後,對於查詢類的sql語句使用:executeQuery(sql)
,sql是一個字串sql語句,返回結果是一個結果集【如果獲取結果看下面的結果部分】 - 對於更新類(插入、修改、刪除、更新)的語句使用:
executeUpdate(sql)
,sql是一個字串sql語句,返回結果是一個整數(受影響的行數)
- 使用PreparedStatement執行語句
PreparedStatement
物件的獲取可以使用prepareStatement(sql)
來獲取,注意的是需要傳入一條sql語句- PreparedStatement的功能類似
Statement
,但不同的是PreparedStatement
可以使用佔位符,它是由佔位符標識需要輸入資料的位置,然後再逐一填入資料。當然,PreparedStatement
也可以執行沒有佔位符的sql語句- 使用佔位符後,使用
setString
或setInt
等方法來設定每一位的資料。【有各種對應資料型別的設定方法,比如還有setFloat
】setXXX
方法中,第一個引數是位置,第二個是資料
- 使用佔位符後,使用
- 獲取
Statement
物件後,對於查詢類的sql語句使用:executeQuery()
,返回結果是一個結果集【如果獲取結果看下面的結果部分】 - 對於更新類(插入、修改、刪除、更新)的語句使用:
executeUpdate()
,返回結果是一個整數(受影響的行數) - 補充:
- 對於有sql快取池的資料庫,
PreparedStatement
的效率要高於Statement
【有興趣的自查】
- 對於有sql快取池的資料庫,
- 使用
CallableStatement
執行語句CallableStatement
主要用來呼叫儲存過程- 對於輸出引數,需要使用registerOutParameter註冊,第一個引數是位置,第二個引數是引數型別(使用Types.xxx)
- 註冊之後,想要獲取輸出引數,可以使用
CallableStatement
物件自身的getXXX
方法來獲取
定義的儲存過程示例:
使用:
獲取返回:
- 返回結果是一個結果集,它有一個游標指向結果的每一行,最開始它不指向結果,第一次執行next()後,它指向第一行結果,繼續執行next(),他會繼續指向下一行。next的返回結果是布林值,它可以用來判斷是否有下一行。
- 對於每一行結果,可以使用getXXX方法(參照下面)來獲取某一列的結果,getXXX方法的引數可以為欄位名,也可以為索引號(從1開始)
關閉連線:
- 後開啟的需要先關閉,Statement、Connection、ResultSet都是需要關閉的
- 注意:關閉之前需要留心檢查是否為null
事務
不瞭解事務是什麼的,可以看一下我的另外一篇博文:mysql之事務管理
設定事務管理:
連線物件.setAutoCommit(boolean)【當引數為true時,代表允許自動提交(事務管理是關閉的,每一條命令都會自動提交);當為false時,代表不允許自動提交,命令會在執行commit之後再統一提交(開啟事務管理的)】
提交事務:
連線物件.commit()
回滾事務:
連線物件.rollback()
例子:
以銀行轉賬為例,張三轉給李四100元,執行事務後,如果執行出錯將不會提交資料到資料庫:
補充:
- 有些時候,在開發中是不會把兩個操作放到一個地方的(在Javaweb中開發中存在service層和dao層。可以這麼說,servlet是飯店前臺,service層就是包廂裡點菜的服務員(客戶需要什麼菜,他負責告訴後廚),dao層就是真正做菜的後廚(dao層通常是資料庫方面的操作)。服務員一次性把需要的菜告訴後廚),這樣耦合性較高,通常需要把它們放到單獨的地方去(就好比一個大廚做好幾樣菜會很忙,通常都會分工好),比如加錢是一個函式,減錢是一個函式。把他們分開後,兩個函式之間的Connection不同的話,就會無法統一進行事務管理。通常有兩個解決方法:1.把同一個Connection物件傳給這兩個引數。2.利用Threadlocal類,把Connection物件存進去,兩個要用的時候再取,取的是同一個物件。【這裡可能不容易理解,只是做個提醒,可以不理解。】
資料庫連線池
- 連線池的意義就是提前建立連線,避免需要使用時再申請連線造成的重複申請資源造成的浪費。
- 連線池負責在需要的時候分發連線,使用者釋放連線時需要放回到連線池中。
連線池可以自定義,當然常用的一般都是選擇採用第三方開源的連線池,想了解如何自定義連線池的可以自查,下面給出的是兩個常用的連線池的用法。
DBCP:
首先,使用DBCP連線池需要匯入包:commons-dbcp.jar和commons-pool.jar【如果需要日誌功能,還需要commons-logging-1.2.jar ,這裡不講述】
DBCP根據配置方式,下面給出兩種使用方法:
1.手動配置法:
- 建立BasicDataSource物件: BasicDataSource dataSource = new BasicDataSource();
- 配置BasicDataSource物件:(少用)呼叫對應函式配置,例如dataSource.setDriverClassName("com.mysql.jdbc.Driver");
- 得到連線物件:Connection conn = ds.getConnection();
- 操作資料庫。(得到資料庫連線物件後,就可以像以前一樣去操作資料庫了)
2.配置檔案配置法:
- 建立BasicDataSourceFactory物件:BasicDataSourceFactory factory = new BasicDataSourceFactory();
- 利用BasicDataSourceFactory物件的createDataSource函式讀取配置檔案配置DataSource物件:DataSource dataSource = factory.createDataSource(properties);【配置檔案能用哪些引數可以參考這個文件:http://commons.apache.org/proper/commons-dbcp/configuration.html】
- 得到連線物件:Connection conn = ds.getConnection();
- 操作資料庫。(得到資料庫連線物件後,就可以像以前一樣去操作資料庫了)
當使用完畢後,像往常一樣呼叫close關閉連線即可【這裡通過連線池獲取的Connection物件已經封裝過了,使用close函式相當於放回連線池中】
常用的dbcp.properties的配置資訊:
#連線設定
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc
username=root
password=#<!-- 初始化連線 -->
initialSize=10#最大連線數量
maxActive=50#<!-- 最大空閒連線 -->
maxIdle=20#<!-- 最小空閒連線 -->
minIdle=5#<!-- 超時等待時間以毫秒為單位 6000毫秒/1000等於60秒 -->
maxWait=60000
#JDBC驅動建立連線時附帶的連線屬性屬性的格式必須為這樣:[屬性名=property;]
#注意:"user" 與 "password" 兩個屬性會被明確地傳遞,因此這裡不需要包含他們。
connectionProperties=useUnicode=true;characterEncoding=gbk#指定由連線池所建立的連線的自動提交(auto-commit)狀態。
defaultAutoCommit=true#driver default 指定由連線池所建立的連線的事務級別(TransactionIsolation)。
#可用值為下列之一:(詳情可見javadoc。)NONE,READ_UNCOMMITTED,READ_COMMITTED,REPEATABLE_READ,SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
C3P0:
首先,使用C3P0連線池需要匯入包:c3p0-0.9.1.2.jar【還有擴充套件包如c3p0-oracle-thin-extras-0.9.1.2.jar,這裡不講】
手動配置法:
- 建立ComboPooledDataSource物件:ComboPooledDataSource dataSource = new ComboPooledDataSource();
- 呼叫對應函式配置對應屬性
配置檔案配置法:
- 建立配置檔案,c3p0的配置檔名字是固定的,必須是c3p0.properties或c3p0-config.xml,否則識別不了。配置檔案的寫法看下面【配置檔案儲存的位置:1.能在classpath中獲取到的目錄(比如工程的src目錄)、2.WEB-INF/classes、3.某些類似功能的路徑】
- 建立ComboPooledDataSource物件【如果有配置檔案,那麼會讀取配置檔案來配置ComboPooledDataSource物件】
- 獲取連線
- 執行sql語句
當你使用完後,Connection物件呼叫close函式,就會把連線釋放會連線池中【這裡通過連線池獲取的Connection物件已經封裝過了,使用close函式相當於放回連線池中】
配置檔案c3p0-config.xml的寫法:
<c3p0-config> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost/bank</property> <property name="user">root</property> <property name="password">123456</property> <!-- 下面的是額外的配置,如最大連線數,連線池大小。。 <property name="initialPoolSize">10</property> <property name="maxIdleTime">30</property> <property name="maxPoolSize">100</property> <property name="minPoolSize">10</property> <property name="maxStatements">200</property> --> </default-config> <!-- 上面是預設的,如果不給引數,預設是上面的; --> <!-- 下面的是單獨的,在建立物件時把下面name中的那個值賦給物件的建構函式,那麼將使用下面的配置 --> <named-config name="student"> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost/student</property> <property name="user">root</property> <property name="password">123456</property> </named-config> </c3p0-config>
配置檔案c3p0.properties的寫法:
c3p0.driverClass=com.mysql.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql://localhost/bank c3p0.user=root c3p0.password=123456
想更詳細的瞭解c3p0,可以參考官方文件:https://www.mchange.com/projects/c3p0/index.html
怎樣去配置c3p0連線池,什麼英語代表什麼意思,具體請參考:https://www.mchange.com/projects/c3p0/index.html
補充:
- 事實上DBCP和c3p0還有不少使用方法,上面只講解了常用的。
DbUtils
- DbUtils是apache旗下的一個操作資料庫的工具
- DbUtils可以簡化我們對資料庫的CRUD操作,一個常用功能是能把查詢到的資料自動封裝起來,而不再需要我們操作ResultSet。
要想使用DBUtils,首先要匯入包:commons-dbutils-1.4.jar
增、刪、改:
- DbUtils的寫操作是一類,讀操作是一類
- 寫操作主要是呼叫update函式
1.新建QueryRunner物件【如果傳入一個連線池物件,那麼後續操作的資料庫連線就是這個連線池的連線;如果不設定,那麼執行update時要給一個連線物件】
2.呼叫update函式.
update()有多個重構函式,可以依據情況來選擇使用:
查:
- 寫操作主要是呼叫query函式
- 查詢操作的同時,可以配合javabean把資料封裝起來(資料返回的資料在ResultSet中,傳入一個ResultSetHandler物件以操作ResultSet中的資料)。
- 如下圖所示,ResultSetHandler物件是必須的引數,所以說,查出資料但不處理的操作不要使用DBUtils。
自定義操作資料:呼叫ResultSetHandler的匿名實現類中的handle方法處理resultset的資料
手動封裝:呼叫ResultSetHandler的實現類中的handle方法來講resultset的資料封裝到物件中
自動封裝資料:根據傳入的ResultSetHandler物件來處理資料
常見ResultSetHandler實現類:
- BeanHandler :把資料庫中的一行資料根據變數名自動封裝到物件中;如果查詢語句返回多條結果,將ResultSet中第一行的資料根據變數名自動封裝到物件中
- BeanListHandler:把資料庫中的多行資料根據變數名自動封裝到物件中,並存儲到List中返回。所以返回結果是一個含有多個bean物件的list
- ScalarHandler :將ResultSet中一條記錄的某一列的資料存成Object,返回值是一個Object。不給引數時預設是第一列的值,引數可以給列數,也可以給欄位名 【可以用於統計函式等返回一個值的情況】
- ArrayHandler :把一條記錄的所有資料儲存到一個數組中,第一列的資料在陣列的第一個位置。
- ArrayListHandler:與ArrayHandler功能類似,但可以返回包含多個數組的list了。
補充:對於封裝成物件的,需要提供一個bean類.class引數,這是為了能建立物件
關閉流、釋放資源:
DbUtils中提供了可以關閉各種資源的靜態方法
補充:
- 由於DbUtils支援傳入一個Connection物件,所以在一些比如轉賬的事務管理中,若是加錢和減錢在不同函式中,DbUtils可以藉助傳入同一個Connection物件來實現事務管理。
更多關於java相關內容感興趣的讀者可檢視本站專題:《Java使用JDBC操作資料庫技巧總結》、《Java+MySQL資料庫程式設計總結》、《Java資料結構與演算法教程》、《Java檔案與目錄操作技巧彙總》、《Java操作DOM節點技巧總結》和《Java快取操作技巧彙總》
希望本文所述對大家java程式設計有所幫助。