1. 程式人生 > 程式設計 >Java JDBC基本使用方法詳解

Java JDBC基本使用方法詳解

本文例項講述了Java JDBC基本使用方法。分享給大家供大家參考,具體如下:

本文內容:

  • 什麼是JDBC
  • JDBC的使用
  • 事務
  • 連線池
  • DbUtils

首發日期:2018-05-27

修改:

  1. 2018-07-19:增加了事務、連線池、DBUtils
  2. 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包新增到當前專案引用的庫裡面。image

載入驅動:

  • image

PS:

  • 在上面的forName中,執行了註冊驅動,註冊驅動這個程式碼被定義在驅動類的靜態程式碼塊中。
  • 對於一些新手,使用的方法可能是image,對於這種情況,那麼他可以使用driver或DriverManager.getConnection來獲取資料庫連線物件;而對於另外一些新手,他們可能會使用image,然後再通過DriverManager.getConnection來獲取資料庫連線物件。但本質上,這是一種浪費,因為靜態程式碼塊中已經靜態生成了一個驅動物件並使用DriverManager.registerDriver註冊了,所以上面兩種都是浪費。使用forName後,可以使用DriverManager.getConnection來獲取資料庫連線物件。

獲取連線:

  • 在考慮使用forName節省資源後,下面介紹的獲取連線的方法使用的是DriverManager.getConnectionimage
  • getConnection需要引數
    • url:定義了連線的資料庫的路徑
      • jdbc協議:資料庫子協議:主機[:埠][/連線的資料庫] 【[]代表可選的】
      • 例如:jdbc:mysql://localhost:3306/testimage
    • 配置流Properties:定義了連線資料庫的方式,一般至少包含user和password
    • 不使用配置流時,傳入user和password
    • 如果使用匿名登入,則只傳入url

image

執行SQL語句:

JDBC執行SQL語句的方式主要有三種:

1.使用Statement執行sql語句

2.使用PreparedStatement執行sql語句

3.使用CallableStatement執行sql語句

上面的Statement、PerPareStatement、Callalestatement都可以使用連線物件來獲取。

image

  • 使用Statement執行語句
    • Statement物件的獲取可以使用createStatement()來獲取
    • 獲取Statement物件後,對於查詢類的sql語句使用:executeQuery(sql),sql是一個字串sql語句,返回結果是一個結果集【如果獲取結果看下面的結果部分】
    • 對於更新類(插入、修改、刪除、更新)的語句使用:executeUpdate(sql),sql是一個字串sql語句,返回結果是一個整數(受影響的行數)

image

  • 使用PreparedStatement執行語句
    • PreparedStatement物件的獲取可以使用prepareStatement(sql)來獲取,注意的是需要傳入一條sql語句
    • PreparedStatement的功能類似Statement,但不同的是PreparedStatement可以使用佔位符,它是由佔位符標識需要輸入資料的位置,然後再逐一填入資料。當然,PreparedStatement也可以執行沒有佔位符的sql語句
      • 使用佔位符後,使用setStringsetInt等方法來設定每一位的資料。【有各種對應資料型別的設定方法,比如還有setFloat
        • setXXX方法中,第一個引數是位置,第二個是資料
    • 獲取Statement物件後,對於查詢類的sql語句使用:executeQuery(),返回結果是一個結果集【如果獲取結果看下面的結果部分】
    • 對於更新類(插入、修改、刪除、更新)的語句使用:executeUpdate(),返回結果是一個整數(受影響的行數)
    • 補充:
      • 對於有sql快取池的資料庫,PreparedStatement的效率要高於Statement【有興趣的自查】

image

  • 使用CallableStatement執行語句
    • CallableStatement主要用來呼叫儲存過程
    • 對於輸出引數,需要使用registerOutParameter註冊,第一個引數是位置,第二個引數是引數型別(使用Types.xxx)
    • 註冊之後,想要獲取輸出引數,可以使用CallableStatement物件自身的getXXX方法來獲取

定義的儲存過程示例:

image

使用:

image

獲取返回:

  • 返回結果是一個結果集,它有一個游標指向結果的每一行,最開始它不指向結果,第一次執行next()後,它指向第一行結果,繼續執行next(),他會繼續指向下一行。next的返回結果是布林值,它可以用來判斷是否有下一行。
    • 對於每一行結果,可以使用getXXX方法(參照下面)來獲取某一列的結果,getXXX方法的引數可以為欄位名,也可以為索引號(從1開始)

image

image

關閉連線:

  • 後開啟的需要先關閉,Statement、Connection、ResultSet都是需要關閉的
  • 注意:關閉之前需要留心檢查是否為null

image


事務

不瞭解事務是什麼的,可以看一下我的另外一篇博文:mysql之事務管理

設定事務管理:

連線物件.setAutoCommit(boolean)【當引數為true時,代表允許自動提交(事務管理是關閉的,每一條命令都會自動提交);當為false時,代表不允許自動提交,命令會在執行commit之後再統一提交(開啟事務管理的)】

提交事務:

連線物件.commit()

回滾事務:

連線物件.rollback()

例子:

以銀行轉賬為例,張三轉給李四100元,執行事務後,如果執行出錯將不會提交資料到資料庫:

image

image

補充:

  • 有些時候,在開發中是不會把兩個操作放到一個地方的(在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.手動配置法:

  1. 建立BasicDataSource物件: BasicDataSource dataSource = new BasicDataSource();
  2. 配置BasicDataSource物件:(少用)呼叫對應函式配置,例如dataSource.setDriverClassName("com.mysql.jdbc.Driver");
  3. 得到連線物件:Connection conn = ds.getConnection();
  4. 操作資料庫。(得到資料庫連線物件後,就可以像以前一樣去操作資料庫了)

image

2.配置檔案配置法:

  1. 建立BasicDataSourceFactory物件:BasicDataSourceFactory factory = new BasicDataSourceFactory();
  2. 利用BasicDataSourceFactory物件的createDataSource函式讀取配置檔案配置DataSource物件:DataSource dataSource = factory.createDataSource(properties);【配置檔案能用哪些引數可以參考這個文件:http://commons.apache.org/proper/commons-dbcp/configuration.html】
  3. 得到連線物件:Connection conn = ds.getConnection();
  4. 操作資料庫。(得到資料庫連線物件後,就可以像以前一樣去操作資料庫了)

image

當使用完畢後,像往常一樣呼叫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,這裡不講】

手動配置法:

  1. 建立ComboPooledDataSource物件:ComboPooledDataSource dataSource = new ComboPooledDataSource();
  2. 呼叫對應函式配置對應屬性

image

配置檔案配置法:

  1. 建立配置檔案,c3p0的配置檔名字是固定的,必須是c3p0.properties或c3p0-config.xml,否則識別不了。配置檔案的寫法看下面【配置檔案儲存的位置:1.能在classpath中獲取到的目錄(比如工程的src目錄)、2.WEB-INF/classes、3.某些類似功能的路徑】
  2. 建立ComboPooledDataSource物件【如果有配置檔案,那麼會讀取配置檔案來配置ComboPooledDataSource物件】
  3. 獲取連線
  4. 執行sql語句

image

當你使用完後,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()有多個重構函式,可以依據情況來選擇使用:

image

image

image

查:

  • 寫操作主要是呼叫query函式
  • 查詢操作的同時,可以配合javabean把資料封裝起來(資料返回的資料在ResultSet中,傳入一個ResultSetHandler物件以操作ResultSet中的資料)。
  • 如下圖所示,ResultSetHandler物件是必須的引數,所以說,查出資料但不處理的操作不要使用DBUtils。

image

自定義操作資料:呼叫ResultSetHandler的匿名實現類中的handle方法處理resultset的資料

image

手動封裝:呼叫ResultSetHandler的實現類中的handle方法來講resultset的資料封裝到物件中

image

自動封裝資料:根據傳入的ResultSetHandler物件來處理資料

image

常見ResultSetHandler實現類:

  • BeanHandler :把資料庫中的一行資料根據變數名自動封裝到物件中;如果查詢語句返回多條結果,將ResultSet中第一行的資料根據變數名自動封裝到物件中
  • BeanListHandler:把資料庫中的多行資料根據變數名自動封裝到物件中,並存儲到List中返回。所以返回結果是一個含有多個bean物件的list
  • ScalarHandler :將ResultSet中一條記錄的某一列的資料存成Object,返回值是一個Object。不給引數時預設是第一列的值,引數可以給列數,也可以給欄位名 【可以用於統計函式等返回一個值的情況】
  • ArrayHandler :把一條記錄的所有資料儲存到一個數組中,第一列的資料在陣列的第一個位置。
  • ArrayListHandler:與ArrayHandler功能類似,但可以返回包含多個數組的list了。

補充:對於封裝成物件的,需要提供一個bean類.class引數,這是為了能建立物件

關閉流、釋放資源:

DbUtils中提供了可以關閉各種資源的靜態方法

image

image

補充:

  • 由於DbUtils支援傳入一個Connection物件,所以在一些比如轉賬的事務管理中,若是加錢和減錢在不同函式中,DbUtils可以藉助傳入同一個Connection物件來實現事務管理。

更多關於java相關內容感興趣的讀者可檢視本站專題:《Java使用JDBC操作資料庫技巧總結》、《Java+MySQL資料庫程式設計總結》、《Java資料結構與演算法教程》、《Java檔案與目錄操作技巧彙總》、《Java操作DOM節點技巧總結》和《Java快取操作技巧彙總》

希望本文所述對大家java程式設計有所幫助。