【Java】JDBC基础使用教程
JDBC
- 一、JDBC簡(jiǎn)介
- 二、JDBC原理
- 二、 JDBC使用
- 三、JDBC小結(jié)
- 四、JDBC封裝
一、JDBC簡(jiǎn)介
JDBC 通過(guò)Java代碼來(lái)操作數(shù)據(jù)庫(kù)
實(shí)際工作中大部分的數(shù)據(jù)庫(kù)操作,都是通過(guò)代碼來(lái)完成的.格子編程語(yǔ)言都可以操作數(shù)據(jù)庫(kù),主要是數(shù)據(jù)庫(kù)提供了各種版本的API(一組函數(shù) / 一組類),調(diào)用這些API就可以操作數(shù)據(jù)庫(kù)。
但是我們要注意:數(shù)據(jù)庫(kù)的種類有許多,不同的數(shù)據(jù)庫(kù),提供的API不太一樣(因?yàn)椴煌臄?shù)據(jù)庫(kù)是不同的廠商實(shí)現(xiàn)的)
程序員,要想通過(guò)代碼來(lái)操作不同的數(shù)據(jù)庫(kù),就需要寫多份代碼,操作數(shù)據(jù)庫(kù)1(寫一份代碼),操作數(shù)據(jù)庫(kù)二(寫一份代碼),這樣造成開(kāi)發(fā)成本變高,學(xué)習(xí)成本變高。
那么我們想解決這個(gè):很多編程語(yǔ)言的做法,就是把各種數(shù)據(jù)庫(kù)的API再次封裝一層,封裝出一套統(tǒng)一的API,其中JAVA里面,這樣的封裝就是由Java標(biāo)準(zhǔn)庫(kù)來(lái)完成的,此時(shí)這一套封裝,稱為JDBC
更準(zhǔn)確的說(shuō)JDBC就是Java標(biāo)準(zhǔn)庫(kù)提供的API,這組API相當(dāng)于把不同的數(shù)據(jù)庫(kù)都統(tǒng)一成一種風(fēng)格了,通過(guò)這一組API,就可以操作任何數(shù)據(jù)庫(kù)(不需要關(guān)心數(shù)據(jù)庫(kù)與數(shù)據(jù)庫(kù)之間,API細(xì)節(jié)的差異了)
二、JDBC原理
這里看一個(gè)圖:
了解了上面,我們開(kāi)始進(jìn)行JDBC開(kāi)發(fā)。
JDBC API 是標(biāo)準(zhǔn)庫(kù)自帶的,直接使用
二、 JDBC使用
MySQL的JDBC驅(qū)動(dòng),這個(gè)不是系統(tǒng)自帶的,需要額外的進(jìn)行下載安裝
那么我們?cè)趺窗惭b呢?在哪里下載
但是上面的前2個(gè)方法很難找到,官網(wǎng)的差別很大,我們這里一般是中央倉(cāng)庫(kù),后面的學(xué)習(xí)中用到的第三方庫(kù),全是中央倉(cāng)庫(kù)去找。
中央倉(cāng)庫(kù)地址
然后點(diǎn)進(jìn)去發(fā)現(xiàn)有許多版本,我們選擇什么版本呢?具體使用什么版本還是看你安裝的mysql服務(wù)器的版本~
Mysql主流的服務(wù)器版本就是兩套
8.x系列(使用8.x系列)
5.x系列 (使用5.1.x系列) 小版本區(qū)別不大,關(guān)鍵是大版本
小版本指的是:5.1.49 和5.1.48 這些區(qū)別不大,如果5版本使用8版本的 可能會(huì)出現(xiàn)連不上的問(wèn)題。
下載:點(diǎn)擊按鈕下載驅(qū)動(dòng)
這個(gè)驅(qū)動(dòng)包,是一個(gè)jar包,就稱為jar包,這是java程序打包部署的一種常見(jiàn)格式,這個(gè).jar 就和壓縮包類似,jar包本質(zhì)就是把一些.class文件以壓縮包的形式,給打包在一起了
引用jar包:開(kāi)始使用 先來(lái)搞一個(gè)簡(jiǎn)單的以后教大家更加科學(xué)的方式:
開(kāi)始JDBC 寫代碼
使用mysql workbench,也需要建立一個(gè)連接,也需要指定數(shù)據(jù)庫(kù)的ip和端口
ip:127.0.0.1表示主機(jī)自身 (是區(qū)分在哪個(gè)主機(jī)上)
port:3306安裝數(shù)據(jù)庫(kù)服務(wù)器的時(shí)候,手動(dòng)設(shè)置的一般默認(rèn)就是3306(區(qū)分在主機(jī)上的什么程序上)
使用JDBC來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)的增加:
我們這里有個(gè)insert方法里面就是寫代碼來(lái)實(shí)現(xiàn)功能
DataSource 是標(biāo)準(zhǔn)庫(kù)里面的,也就是自帶的,它是一個(gè)interface 接口
MysqlDataSource 是jar包的,也就是說(shuō)如果jar包沒(méi)有導(dǎo)入成功就沒(méi)有辦法使用 實(shí)現(xiàn)了DataSource interface的類
DataSource 這個(gè)概念表示“數(shù)據(jù)庫(kù)在哪里”,對(duì)于Mysql來(lái)說(shuō),數(shù)據(jù)庫(kù)就是一個(gè)服務(wù)器程序,因此就可以通過(guò)DataSource 來(lái)描述服務(wù)器的地址,端口,用戶名,密碼,要訪問(wèn)數(shù)據(jù)庫(kù)名等等
1)數(shù)據(jù)庫(kù)的ip端口 ,數(shù)據(jù)名通過(guò)URL表示
使用到一個(gè) setUTL 這個(gè)方法,這個(gè)setURL方法屬于 MysqlDataSource 不是DataSource 的方法,此處需要向下轉(zhuǎn)型
這個(gè)操作涉及了向下轉(zhuǎn)型,我們?yōu)槭裁匆@樣寫:
使用這種轉(zhuǎn)型的寫法,也很常見(jiàn),帶來(lái)的好處就是,代碼中其他部分拿到的dataSource都是 DataSource類型,和具體的數(shù)據(jù)庫(kù)種類無(wú)關(guān).日后如果需要切換數(shù)據(jù)庫(kù),其他代碼就完全不用改動(dòng)了.
比如使用的是MysqlDataSource ,因?yàn)镸ysqlDataSource 是Mysql的如果數(shù)據(jù)庫(kù)變量了那么其他需要變一點(diǎn)不方便
來(lái)看看set.URL里面的內(nèi)容分別是什么意思
還有新增的2個(gè) useSSL:加密
為什么要加密:
到底需要打開(kāi)嗎加密嗎?
2)設(shè)置登錄數(shù)據(jù)庫(kù)的用戶名
MySQL支持自己創(chuàng)建用戶.
MySQL只要安裝好之后,就會(huì)自帶一個(gè)用戶,就是root.表示"管理員”,擁有最高的權(quán)限,可以管理其他用戶的權(quán)限.當(dāng)前階段咱們不必過(guò)多的關(guān)注這里的權(quán)限.(權(quán)限的話以后到公司里,都是有專門的人來(lái)給你分配好的)
3)設(shè)置登錄數(shù)據(jù)庫(kù)的密碼
3.連接數(shù)據(jù)庫(kù),進(jìn)行真正的網(wǎng)絡(luò)通信
這個(gè)就是開(kāi)始進(jìn)行網(wǎng)絡(luò)操作,如果數(shù)據(jù)庫(kù)連接上了,會(huì)返回一個(gè)實(shí)例,如果失敗會(huì)拋出一個(gè)異常
啥時(shí)候會(huì)連接失敗呢?原因非常多,例如 ip ,端口,密碼,這些錯(cuò)誤會(huì)失敗,用戶沒(méi)有權(quán)限也會(huì)失敗,數(shù)據(jù)庫(kù)沒(méi)有正確啟動(dòng)也會(huì)失敗
異常處理 注意是這個(gè)庫(kù)里面的:import java.sql.Connection;
4.構(gòu)造一個(gè)SQL語(yǔ)句,為插入準(zhǔn)備!
通過(guò)其他語(yǔ)言來(lái)操作數(shù)據(jù)庫(kù),其實(shí)還是通過(guò)SQL來(lái)完成!
這里有一個(gè)數(shù)據(jù)庫(kù),結(jié)構(gòu)是這樣的:
此處不需要use數(shù)據(jù)庫(kù)的操作,在URL中已經(jīng)設(shè)定好數(shù)據(jù)庫(kù)的名字了,此時(shí)客戶端連上去之后就能直接確定數(shù)據(jù)庫(kù)
執(zhí)行語(yǔ)句寫好了,我們還需要執(zhí)行, 有一個(gè)專門的對(duì)象 :PreparedStatement
這里要介紹一下為什么要這個(gè)對(duì)象:我們的SQL語(yǔ)句不一定是直接寫死的值直接給你的,可能里面的信息是要?jiǎng)討B(tài)拼接,就是不是已經(jīng)給值的,說(shuō)白了重要的功能是動(dòng)態(tài)拼接SQL
5.執(zhí)行SQL客戶端把SQL通過(guò)網(wǎng)絡(luò)請(qǐng)求,發(fā)送給mysql服務(wù)器,mysqk服務(wù)器來(lái)解析這個(gè)SQL請(qǐng)求,執(zhí)行具體操作,并返回響應(yīng)結(jié)果,此處使用excuteUpdate 來(lái)完成數(shù)據(jù)庫(kù)內(nèi)容的變更(邊更包含 insert,update,delete),返回值是整數(shù),返回多少就是影響多少行操作 executeQuery:數(shù)據(jù)查詢.針對(duì)select =>返回值是個(gè)ResultSet .
最后一步:我們要關(guān)閉資源
為什么關(guān)閉,客戶端通過(guò)網(wǎng)絡(luò)和服務(wù)器建立連接,客戶端和服務(wù)器之間各自會(huì)分配一些資源,來(lái)保持這樣的連接信息(記錄對(duì)端的ip port)每維護(hù)一個(gè)連接,就都得分配一些硬件資源,如果一直不關(guān)閉資源越耗越多,最后沒(méi)有資源,程序就無(wú)法正常運(yùn)行
調(diào)用close的順序,應(yīng)該是按照申請(qǐng)順序的“逆序”來(lái)進(jìn)行的~
前面的代碼,是先創(chuàng)建Connection,再創(chuàng)建PreparedStatement
后面的代碼,就是先關(guān)閉PreparedStatement,后關(guān)閉Connection
最后我們執(zhí)行,全部的代碼放在下面最后看看結(jié)果:
package bookManager;import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;import javax.sql.DataSource; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Connection;/*** Created by Lin* Description:* User: Administrator* Date: 2022-01-14* Time: 14:45*/ //通過(guò)這個(gè)類 把數(shù)據(jù)庫(kù)連接操作封裝一下 public class DBUtil {private static String url = "xxxxx"; //這個(gè)要輸入自己的private static String username ="xxxx";private static String password = "xxxx";//接下來(lái)創(chuàng)建數(shù)據(jù)源//其實(shí)每個(gè)項(xiàng)目里面有一個(gè)數(shù)據(jù)源就可以了//像DataSource這樣的實(shí)例,不應(yīng)該被創(chuàng)建多個(gè)private static DataSource dataSource = new MysqlDataSource();//靜態(tài)代碼塊 執(zhí)行時(shí)間是在類加載階段static {((MysqlDataSource)dataSource).setURL(url);((MysqlDataSource)dataSource).setUser(username);((MysqlDataSource)dataSource).setPassword(password);}//提供一個(gè)方法,來(lái)建立連接public static Connection getConnection() throws SQLException {return dataSource.getConnection();}//釋放資源代碼//這里的參數(shù)不要null就關(guān)閉public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){if(resultSet != null){try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}if (statement != null){try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if (connection !=null){try {connection.close();} catch (SQLException e) {e.printStackTrace();}}} }數(shù)據(jù)庫(kù)最后執(zhí)行成功會(huì)新增一個(gè)數(shù)據(jù):
如果我們想動(dòng)態(tài)拼接怎么辦呢??
可以嘗試這樣的寫法:
但是通過(guò)字符串拼接,確實(shí)可以動(dòng)態(tài)的構(gòu)造出SQL,但是不建議這樣使用,這樣拼接比較麻煩,另一方面這樣不安全,容易被SQL注入。
那么我們要怎么樣實(shí)現(xiàn),更加安全呢?
我們只需要把,SQL語(yǔ)句的拼接全部變成? ?,這樣也可以清楚的看清楚我們有那幾個(gè)值,而且也更加方便,下面是賦值
那個(gè)1,就是id替換了第一個(gè)?的地方,那個(gè)2就是name替換了第二個(gè)? 然后第一個(gè)是int類型,第二個(gè)替換成String類型的。
statement就支持一組setxxx 這樣的方法,xxx值得是一個(gè)具體的類型~,根據(jù)要設(shè)置的類型不同,來(lái)決定使用不同的方法,數(shù)據(jù)庫(kù)的所以的類型基本上全都支持
setxxx方法內(nèi)部對(duì)于設(shè)置的值,進(jìn)行了比較嚴(yán)格的校驗(yàn),如果用戶插入的內(nèi)容是包含這種疑似SQL注入的時(shí)候,setxxx 就可以識(shí)別出來(lái)。
我們可以看statement里面的SQL
拼裝后的樣子:
最后數(shù)據(jù)庫(kù)也成功了:
寫完了插入,我們來(lái)寫一下刪除唄:
public static void delete() throws SQLException {//刪除和插入差不多 只是把SQL從SQL變成delete//1.創(chuàng)建數(shù)據(jù)源,吧數(shù)據(jù)庫(kù)的位置信息設(shè)置進(jìn)去DataSource dataSource = new MysqlDataSource();((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/java101?characterEncoding=utf8&&useSSL=false");((MysqlDataSource)dataSource).setUser("root");((MysqlDataSource)dataSource).setPassword("200224");//2.和數(shù)據(jù)庫(kù)建立連接Connection connection= dataSource.getConnection();//3.構(gòu)造SQLScanner scanner = new Scanner(System.in);System.out.println("請(qǐng)輸入要?jiǎng)h除的id:");int id= scanner.nextInt();String sql = "delete from test where id = ?";PreparedStatement statement = connection.prepareStatement(sql);statement.setInt(1,id);//4.執(zhí)行SQLint ret = statement.executeUpdate();System.out.println("ret="+ret);//5.釋放資源statement.close();connection.close();}其實(shí)發(fā)現(xiàn)就是SQL有區(qū)別其他地方?jīng)]有區(qū)別對(duì)吧
但是發(fā)現(xiàn)我們的JDBC 操作數(shù)據(jù)庫(kù)是不是有點(diǎn)太麻煩了,的確,但是我們之后會(huì)告訴簡(jiǎn)化的方法的,畢竟代碼是給我們帶來(lái)方便的 。
結(jié)果:
數(shù)據(jù)庫(kù):
寫一下修改:
public static void update() throws SQLException {//1.創(chuàng)建數(shù)據(jù)源DataSource dataSource = new MysqlDataSource();((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/java101?characterEncoding=utf8&&useSSL=false");((MysqlDataSource)dataSource).setUser("root");((MysqlDataSource)dataSource).setPassword("200224");//2.創(chuàng)建連接Connection connection = dataSource.getConnection();//3.構(gòu)造數(shù)據(jù)庫(kù)System.out.println("請(qǐng)輸入要修改的id");Scanner scanner = new Scanner(System.in);int id = scanner.nextInt();System.out.println("請(qǐng)輸入要修改的name");Scanner scanner1 = new Scanner(System.in);String name = scanner1.nextLine();String sql = "update test set name = ? where id = ?";PreparedStatement statement = connection.prepareStatement(sql);statement.setString(1,name);statement.setInt(2,id);//4.執(zhí)行SQLint ret = statement.executeUpdate();System.out.println("ret"+ret);//5.關(guān)閉statement.close();connection.close();}
數(shù)據(jù)庫(kù):
查找:查詢和修改插入刪除,就有一些區(qū)別了!
插入刪除修改,執(zhí)行完的返回結(jié)果,只有一個(gè)int而已
查找操作,執(zhí)行完的結(jié)果,是包含一組結(jié)果集合(一張臨時(shí)表),
此處就需要寫一些額外的代碼,把這個(gè)臨時(shí)表/結(jié)果表里的內(nèi)容獲取到
這個(gè)結(jié)果的集合的遍歷,就非常類似于"迭代器"的遍歷
resultSet.next() 獲取當(dāng)前行,同時(shí)切換到下一行 這個(gè)操作類似 i++
resultSet 就相當(dāng)于一張表,每次next得到其中的一行,就可以進(jìn)一步的根據(jù)這一行,得到里面的列
如果獲取到了這一行 會(huì)返回一個(gè)true 如果遍歷到了表的末尾,在嘗試next 就會(huì)返回false
使用getxxx方法要和表里的類型相對(duì)
數(shù)據(jù)庫(kù):
還有些編程語(yǔ)言/庫(kù)里,把ResultSet也叫做光標(biāo)
三、JDBC小結(jié)
1.DataSource和MysqlDataSource表示數(shù)據(jù)源(數(shù)據(jù)在哪里)
- DataSource :通用的,能夠支持各種數(shù)據(jù)庫(kù)
- MysqlDataSource:是MySQL驅(qū)動(dòng)包里提供的專門針對(duì)·MySQL的類,設(shè)置用戶名,密碼,URL…基本信息
2 .Connection connection = dataSource.getConnection()
- 通過(guò)DataSource來(lái)建立Connection (要先知道服務(wù)器的位置才可以連接)
3.構(gòu)造SQL
PreparedStatement:
里面包含的不僅僅是SQL,要通過(guò)這個(gè)對(duì)象來(lái)把用戶構(gòu)造的SQL通過(guò)網(wǎng)絡(luò)發(fā)送給服務(wù)器
Connection是自身真的服務(wù)器的位置的(從DataSource過(guò)來(lái)的)通過(guò)connection創(chuàng)建出的PreparedStatement,PreparedStatement也知道服務(wù)器的位置
executeQuery / executeUpdate:通過(guò)網(wǎng)絡(luò)發(fā)送,前提知道在哪里
4.遍歷結(jié)果集合
通過(guò)網(wǎng)絡(luò),數(shù)據(jù)集合已經(jīng)拿回來(lái)了,到了本地,響應(yīng)的結(jié)果已經(jīng)在客戶端代碼的內(nèi)存中,可以在本地遍歷,獲取內(nèi)容
通過(guò)這些,大家要記住一句話,MySQL是一個(gè)“客戶端 服務(wù)器” 結(jié)構(gòu)的程序,服務(wù)器是Mysql的本體,負(fù)責(zé)管理數(shù)據(jù),客戶端有許多形態(tài)(cmd,workbench ,JDBC…)
四、JDBC封裝
剛剛上面的代碼比較冗余,許多代碼重復(fù)的還寫,其實(shí)我們可以把部分代碼封裝一下,即可輕松一點(diǎn):
URL部分
接下來(lái)創(chuàng)建數(shù)據(jù)源
其實(shí)每個(gè)項(xiàng)目里面有一個(gè)數(shù)據(jù)源就可以了
像DataSource這樣的實(shí)例只要有1個(gè)就可以了,不應(yīng)該被創(chuàng)建多個(gè)
我們通過(guò)Static來(lái)修飾,此處的Static是表示的是“類成員”,“類方法”
DBUtil在程序中,只存在一份!! 這個(gè)類里面的成員,也就是只有一份了!
我們寫的類,被編譯成.class文件,程序運(yùn)行的時(shí)候,jvm就會(huì)從指定的路徑中,加載.class文件,.class文件是有固定格式的…(從jvm的實(shí)現(xiàn)規(guī)范上看到)
JVM就會(huì)把.class文件內(nèi)容進(jìn)行解析,并且加載到內(nèi)存中,并且在內(nèi)存構(gòu)造一個(gè)“類對(duì)象”,(類對(duì)象里面就包含了這個(gè)類的關(guān)鍵信息,這個(gè)類叫什么名字,類里面有哪些屬性,每個(gè)屬性叫什么,每個(gè)屬性是public還是private,還有什么方法,叫什么名字,方法的參數(shù)叫什么,返回值是啥public /private)
類就是圖紙~
JVM在加載的時(shí)候,就會(huì)先看看這個(gè)類是不是已經(jīng)在內(nèi)存中存在了,如果存在,就不要重復(fù)加載,如果不存在才從.class加載
所以才要加static
像這樣的操作,保證類中在程序只有唯一實(shí)例,稱為“單例模式”,也是一種設(shè)計(jì)模式
接下來(lái)我們需要執(zhí)行數(shù)據(jù)庫(kù)連接,以及后續(xù)的建立連接和關(guān)閉釋放資源
直接調(diào)用close就可以關(guān)閉,調(diào)用connectio可以連接,最后的代碼就是這樣的DBUtil
為什么我們這里要這樣寫,因?yàn)槿绻覀兙颓短滓粚觮ry catch的話,那就會(huì)出現(xiàn)問(wèn)題,如果第一個(gè)close出現(xiàn)異常,那么就會(huì)去catch語(yǔ)句,其他的就不執(zhí)行了,所以我們使用這樣的
總結(jié)
以上是生活随笔為你收集整理的【Java】JDBC基础使用教程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java 线程转储_获取Java线程转储
- 下一篇: 自学Java怎么入门