前言
由於目前市面上存在的多種數據庫,為了使Java編寫的程序不依賴具體的數據庫,Java提供了專門用於操作數據庫的API,就是JDBC
(Java Data Base Connectivity)Java數據庫連接。使用JDBC的應用程序和數據庫連接后,就可以使用JDBC
提供的API操作數據庫。
基本步驟:
- 與一個數據庫建立連接
- 向連接的數據庫發送SQL語句
- 處理SQL語句返回的結果
連接數據庫
在開發中常用的連接方式是加載JDBC-數據庫驅動(連接器)
,即JDBC
調用本地的JDBC-數據庫驅動
和相應數據庫建立連接。連接需要經歷兩個步驟:
- 加載
JDBC-數據庫驅動
。 - 和指定的數據庫建立連接。
如果JDK擴展沒用JDBC-MySQL驅動
,可登錄MySQL
官網下載,選擇JDBC Driver for MySQL
,例如下載的是mysql-connector-java-5.1.40.zip
,解壓后復制到JDK擴展目錄中,例如E:\jdk1.8\jre\lib\ext
。之后便開始加載JDBC-MySQL
數據庫驅動,負責加載驅動的代碼為:
try {//MySQL驅動被封裝在Driver類中
Class.forName("com.mysql.jdbc.Driver");
//oracle
Class.forName("oracle.jdbc.driver.OracleDriver");
//加載SQLServer驅動
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
//加載Derby驅動
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
}catch(Exception e){ }
之后第三步開始連接數據庫,java.sql
包中的DriverManager
類有兩個用於建立連接的類方法:
- Connection
getConnection(String ,String ,String)
- Connection
getConnection(String)
上述兩個方法都有可能返回SQLException
異常,DriverManager
類調用上述方法可以和數據庫建立連接,可以返回一個Connection
對象。注意,連接時MySQL數據庫服務器啟動,默認端口為3306
。
Connection con;
String url = "jdbc:mysql://127.0.0.1:3306/users?user=root&password=123456&useSSL=true";
//String url = "jdbc:mysql://127.0.0.1:3306/users?useSSL=true&characterEncoding=utf-8";
//String sqlserver_url="jdbc:sqlserver://localhost:1433;DatabaseName=users";
//String derby="jdbc:derby:users;create=true";創建並連接users數據庫
//String user = "root";
//String password = "123456";
try{//連接MySQL數據庫users
con = DriverManager.getConnection(url);
//con = DriverManager.getConnection(url,user,password);
}catch(SQLException e){
System.out.println(e);
}
需要注意的是,如果連接數據庫的表中有漢字,那么建立連接時要多傳一個參數characterEncoding
,取值utf-8或gb2312
。
查詢操作
建立連接后就可以發送SQL語句了,和數據庫進行交互,常見操作有查詢、修改和更新等。步驟具體如下:
-
向數據庫發送查詢語句
使用
statement
聲明一個SQL語句對象,然后讓連接對象con調用方法creatStatement()
創建這個SQL語句對象。try{ Statement sql = con.createStatement(); }catch(SQLException e){ System.out.println(e); }
-
處理查詢結果
有了SQL語句對象后,這個對象就可以調用相應的方法實現對數據庫的查詢和修改,並將查詢結果存放在一個
ResultSet類
聲明的對象中,即查詢結果將返回一個ResultSet
對象,對象由按字段組織的數據行構成。ResultSet rs1 = sql.executeQuery("SELECT * FROM users"); ResultSet rs2 = sql.executeQuery("SELECT name,height FROM users");
結果集
rs1
的列數和users
的列數相同,結果集rs2
列數只有2列。ResultSet
對象一次只能看到一個數據行,使用next()
移到下一行,獲得一行數據后,ResultSet
對象可以使用getXxx
方法獲得字段值,將位置索引或列名傳遞給getXxx
方法即可。無論字段為何種屬性,總可以使用getString(int columnIndex)
或getString(String columnName)
方法返回字段的串表示。 -
關閉連接
ResultSet
對象和數據庫連接對象實現了緊密的綁定,則一旦連接對象被關閉,ResultSet
對象中的數據立刻消失。con.close(); //關閉連接將無法獲取數據
順序查詢
ResultSet
對象一次只能看到一個數據行,使用next()
方法移到下一個數據行,next()
最初查詢位置,即游標位置
,在第一行前面。next()
向下移動游標,移動成功返回true
,否則返回false
。
rs = sql.executeQuery("SELECT * FROM users");
while(rs.next()){
String number = rs.getString(1);
String name = rs.getString(2);
Date date = rs.getDate(3);
System.out.println(number);
System.out.println(name);
System.out.println(date);
}
con.close();
控制游標
調用next()
方法使游標向下移動,若需要在結果集中上下移動、顯示某一條記錄或隨機顯示若干記錄,必須返回一個可滾動的結果集。為了得到一個可滾動的結果集可使用如下方法:
Statement st = con.createStatement(int type,int concurrency);
type
的取值決定滾動方式:
ResultSet.TYPE_FORWORD_ONLY
:結果集的游標只能向下滾動。ResultSet.TYPE_SCROLL_INSENSITIVE
:結果集的游標可以上下移動,當數據庫變化時,當前結果集不變。ResultSet.TYPE_SCROLL_SENSITIVE
:返回可滾動的結果集,當數據庫變化時,當前結果集同步改變。
concurrency
取值決定是否可以用結果集更新數據庫:
ResultSet.CONCUR_READ_ONLY
:只讀,不能用結果集更新數據庫中的表。ResultSet.CONCUR_UPDATABLE
:能用結果集更新數據庫中的表。
滾動查詢經常會用到一些實例方法,大家可自行查詢了解和使用。例如public void last()
移到最后一行,public int getRow()
返回當前行號。
條件和排序查詢
需要條件進行查詢時,可在SQL語句中添加條件。
-
where子語句
select 字段 from 表 where 條件
-
字段值和固定值比較
select name from users where name='騷年'
-
字段值在某個范圍內
select * from users where height>1.60 and height<1.8 select * from users where weight>45 and name!='張三'
-
使用某些特殊日期函數,如
year
,month
,day
select * from users where year(birthday)<2013 and month(birthday)<=10 select * from users where year(birthday) between 2000 and 2014
-
使用某些特殊的時間函數,如
hour
,minute
,second
select * from timelist where second(shijian)=32
-
使用操作符
like
進行模式匹配,使用%代替0給或多個字符,用下划線_代替一個字符,例如在name字段查詢含‘凱’字的記錄。select * form users where name like '%凱%'
-
排序
用
order by
子語句進行排序,例如:select * from users order by height select * from users where name like '%凱%' order by name
增刪改操作
Statement
對象調用方法:
public int executeUpdate(String sqlStatement);
通過參數sqlStatement
指定的方式實現對數據庫中記錄的更新、添加和刪除操作。
-
更新
下述SQL語句將
users
表中name
值為“張三”的記錄的height
字段的值更新為1.77:update 表 set 字段 = 新值 where <條件子句> update users set height = 1.77 where name='張三'
-
添加
以下SQL語句將
users
表中添加兩條新的記錄(記錄之間用逗號分隔):insert into 表(字段列表) values (對應的具體的記錄) insert into 表 values (對應的具體的記錄) insert into users values ('R1001','基地','2020-11-21',1.67),('R1002','包有為','2020-12-20',1.79)
-
刪除
下述SQL語句將刪除
users
表中的number
字段值為R1002
的記錄:delete from 表名 where <條件子句> delete from users where number='R1002'
當返回結果集后,沒用立即輸出結果集的記錄,而是接着執行了更新語句,那么結果集就不能輸出記錄,如果要返回結果集就必須重新返回結果集。
使用預處理語句
Java提供了更高效的數據庫處理機制,就是PreparedStatement
預處理語句對象。它的目的是減輕數據庫SQL解釋器的負擔,事先將SQL語句解釋為數據庫底層的內部命令,然后讓數據庫去執行這個命令,從而提高了訪問數據庫的速度。
連接對象調用preparedStatement(String sql)
方法對參數sql
指定的SQL語句進行預編譯處理,生成數據庫底層的內部命令,並將該命令封裝在PreparedStatement
對象中,那么該對象調用下列方法都可以使得該命令被數據庫執行。
ResultSet executeQuery()
boolean execute()
int executeUpdate()
只要編譯好了PreparedStatement
對象,那么該對象可以隨時執行上述方法。
使用通配符?
來代替字段的值,只要在預處理語句之前再設置通配符所代表的具體值即可。
String str = "select * from users where height < ? and name= ?";
PreparedStatement sql = con.preparedStatement(str);
在sql
對象執行之前,必須調用相應的方法設置通配符?
代表的具體值,例如:
sql.setFloat(1,1.76f);
sql.setString(2,"哦哦");
通配符按照它們在預處理語句中從左到右依次出現的順序分別為第1、2···n個通配符,使用通配符可以隨時改變SQL語句中的條件。常用方法有以下幾個:
void setDate(int paraIndex,Date x);
void setDouble(int paraIndex,double x);
void setFloat(int paraIndex,float x);
void setInt(int paraIndex,int x);
void setLong(int paraIndex,long x);
void setString(int paraIndex,String x);
通用查詢
編寫一個類,用戶將數據庫名、SQL語句傳遞給該類對象,那么該對象就用一個二維數組返回查詢結果。為了編寫通用查詢,需要知道數據庫的列的名字,特別是表的列數(字段的個數),簡單的方法就是使用返回到程序的結果集獲取相關信息。結果集ResultSet
對象調用getMetaData()
方法返回一個ResultSetMetaData
對象(結果集的元數據對象)。
ResultSetMetaData metaData = rs.getMetaData();
之后metaData
調用getColumnCount()
方法就可以返回結果集中的列的數目,調用getColumnName(int i)
就可以返回結果集中的第i列的名字。
int columnCount = metaData.getColumnCount();
String columnName = metaData.getColumnName(i);
事務
事務由一組SQL語句組成,所謂事務處理,是指應用程序保證事務中的SQL語句要么全部執行要么一個都不執行。事務處理是保證數據庫中數據完整性與一致性的重要機制。應用程序與數據庫建立連接后,可能使用多條SQL語句操作數據庫中的一個或多個表。例如管理資金轉賬的應用程序,保證轉賬雙方資金安全合理,則SQL語句都執行或都不執行。
JDBC
處理事務的步驟:
-
用
setAutoCommit(boolean b)
方法關閉自動提交模式關閉自動提交就是關閉SQL語句的即可生效性,連接對象的提交模式是
自動提交模式
,連接對象產生的Statement
或PreparedStatement
對象對數據庫提交的任何SQL語句都會立即生效,而我們的要求是讓一組提交的SQL語句同步生效。就是歸納為不能立刻生效,不能不生效!連接對象
con
首先調用setAutoCommit(boolean autoCommit)
方法,參數取值false
即可關閉。注意,先關閉再獲取Statement
對象。sql = con.createStatement();
-
用
commit()
方法處理事務關閉后,連接對象產生的
Statement
對象對數據庫提交的任何一條SQL語句都不會立刻生效,這樣Statement
對象可以提交多條SQL語句,這些SQL語句就是一個事務,事務中的SQL語句不會立刻生效。連接對象調用commit()
方法就是試圖讓事務中的SQL語句全部生效。 -
用
rollback()
方法處理事務失敗處理事務失敗就是撤銷事務所做的操作。事務中任何一個SQL語句未能生效,就拋出
SQLException
異常,在處理該異常時,必須讓連接對象con
調用rollback()
方法,作用是撤銷事務中成功執行的SQL語句對數據庫所做的更新、插入和刪除操作,讓數據庫中的數據恢復為之前的狀態。
事務的四大特點(ACID)
- Atomicity(原子性):表示一個事務內的所有操作是一個整體,要么全部成功,要么全失敗;
- Consistency(一致性):表示一個事務內有一個操作失敗時,所有的更改過的數據都必須回滾到修改前的狀態;
- Isolation(隔離性):事務查看數據時數據所處的狀態,要么是另一並發事務修改它之前的狀態,要么是另一事務修改它之后的狀態,事務不會查看中間狀態的數據。
- Durability(持久性):持久性事務完成之后,它對於系統的影響是永久性的。
事務隔離級別從低到高:
- 讀取未提交(Read Uncommitted)
- 讀取已提交(Read Committed)
- 可重復讀(Repeatable Read)
- 序列化(serializable)
批處理Batch
- 靈活指定SQL語句中的變量
PreparedStatement - 對存儲過程進行調用
CallableStatement - 運用事務處理
Transaction - 批處理
Batch
對於大量的批處理,建議使用Statement,因為PreparedStatement的預編譯空間有限,當數據量特別大時,會發生異常。
CLOB文本大對象操作
- CLOB(Character Large Object)
用於存儲大量的文本數據-大字段有些特殊,不同數據庫處理的方式不一樣,大字段的操作常常是以流的方式來處理的。而非一般的字段,一次即可讀出數據。 - Mysql中相關類型:
TINYTEXT最大長度為255(2^8-1)字符的TEXT列。
TEXT[(M)]最大長度為65535(2^16-1)字符的TEXT列。
MEDIUMTEXT最大長度為16,777,215(2^24-1)字符的TEXT列。
LONGTEXT最大長度為4,294,967,295或4GB(2^32-1)字符的TEXT列。
BLOB二進制大對象的使用
- BLOB(Binary Large Object) 用於存儲大量的二進制數據
大字段有些特殊,不同數據庫處理的方式不一樣,大字段的操作常常是以流的方式來處理的。而非一般的字段,一次即可讀出數據。 - Mysql中相關類型:
TINYBLOB最大長度為255(2^8-1)字節的BLOB列。
BLOB[(M)]最大長度為65535(2^16-1)字節的BLOB列。
MEDIUMBLOB最大長度為16,777,215(2^24-1)字節的BLOB列。
LONGBLOB最大長度為4,294,967,295或4GB(2^32-1)字節的BLOB列。
最后
以上就是JDBC的基本內容了,在學JDBC的同時,最好提前了解熟悉一下MySQL。如果有問題,可以上公眾號菜雞干Java上加wx交流,公眾號上會分享一些知識干貨哦!