mysql和jdbc的区别_JDBC详解
一、 JDBC 簡(jiǎn)介
1 什么是 JDBC
?JDBC(JavaDataBaseConnectivity)java 數(shù)據(jù)庫連接 ? 是 JavaEE 平臺(tái)下的技術(shù)規(guī)范 ? 定義了在 Java 語言中連接數(shù)據(jù),執(zhí)行 SQL 語句的標(biāo)準(zhǔn) ? 可以為多種關(guān)系數(shù)據(jù)庫提供統(tǒng)一訪問
2 什么是數(shù)據(jù)庫驅(qū)動(dòng)程序
? 數(shù)據(jù)庫廠商對(duì) JDBC 規(guī)范的具體實(shí)現(xiàn) ? 不同數(shù)據(jù)產(chǎn)品的數(shù)據(jù)庫驅(qū)動(dòng)名字有差異 ? 在程序中需要依賴數(shù)據(jù)庫驅(qū)動(dòng)來完成對(duì)數(shù)據(jù)庫的操作
3 程序操作數(shù)據(jù)庫流程
二、 JDBC3.0 標(biāo)準(zhǔn)中常用接口與類
1 Driver 接口
Driver 接口的作用是來定義數(shù)據(jù)庫驅(qū)動(dòng)對(duì)象應(yīng)該具備的一些能力。比如與數(shù)據(jù)庫建立連 接的方法的定義所有支持 java 語言連接的數(shù)據(jù)庫都實(shí)現(xiàn)了該接口,實(shí)現(xiàn)該接口的類我們稱 之為數(shù)據(jù)庫驅(qū)動(dòng)類。在程序中要連接數(shù)據(jù)庫,必須先通過 JDK 的反射機(jī)制加載數(shù)據(jù)庫驅(qū)動(dòng) 類,將其實(shí)例化。不同的數(shù)據(jù)庫驅(qū)動(dòng)類的類名有區(qū)別。 加載 MySql 驅(qū)動(dòng):Class.forName("com.mysql.jdbc.Driver"); 加載 Oracle 驅(qū)動(dòng):Class.forName("oracle.jdbc.driver.OracleDriver");
2 DriverManager 類
DriverManager 通過實(shí)例化的數(shù)據(jù)庫驅(qū)動(dòng)對(duì)象,能夠建立應(yīng)用程序與數(shù)據(jù)庫之間建立連 接。并返回 Connection 接口類型的數(shù)據(jù)庫連接對(duì)象。
2.1常用方法
?getConnection(StringjdbcUrl,Stringuser,Stringpassword) 該方法通過訪問數(shù)據(jù)庫的 url、用戶以及密碼,返回對(duì)應(yīng)的數(shù)據(jù)庫的 Connection 對(duì)象。
2.2JDBCURL
與數(shù)據(jù)庫連接時(shí),用來連接到指定數(shù)據(jù)庫標(biāo)識(shí)符。在 URL 中包括了該數(shù)據(jù)庫的類型、 地址、端口、庫名稱等信息。不同品牌數(shù)據(jù)庫的連接 URL 不同。
3 Connection 接口
Connection 與數(shù)據(jù)庫的連接(會(huì)話)對(duì)象。我們可以通過該對(duì)象執(zhí)行 sql 語句并返回結(jié)
果。
連接 MySql 數(shù)據(jù)庫: Connection conn = DriverManager.getConnection("jdbc:mysql://host:port/database", "user", "password"); 連接 Oracle 數(shù)據(jù)庫: Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@host:port:database", "user","password"); 連接 SqlServer 數(shù)據(jù)庫: Connection conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://host:port; DatabaseName=database","user","password");
3.1常用方法
?createStatement():創(chuàng)建向數(shù)據(jù)庫發(fā)送 sql 的 Statement 接口類型的對(duì)象。 ?preparedStatement(sql) :創(chuàng)建向數(shù)據(jù)庫發(fā)送預(yù)編譯 sql 的 PrepareSatement 接口類型的
對(duì)象。 ?prepareCall(sql):創(chuàng)建執(zhí)行存儲(chǔ)過程的 CallableStatement 接口類型的對(duì)象。 ?setAutoCommit(booleanautoCommit):設(shè)置事務(wù)是否自動(dòng)提交。 ?commit() :在鏈接上提交事務(wù)。 ?rollback() :在此鏈接上回滾事務(wù)。
4 Statement 接口
用于執(zhí)行靜態(tài) SQL 語句并返回它所生成結(jié)果的對(duì)象。 由 createStatement 創(chuàng)建,用于發(fā)送簡(jiǎn)單的 SQL 語句(不支持動(dòng)態(tài)綁定)。
4.1常用方法
?execute(String sql):執(zhí)行參數(shù)中的 SQL,返回是否有結(jié)果集。 ?executeQuery(Stringsql):運(yùn)行 select 語句,返回 ResultSet 結(jié)果集。 ?executeUpdate(Stringsql):運(yùn)行 insert/update/delete 操作,返回更新的行數(shù)。 ?addBatch(Stringsql) :把多條 sql 語句放到一個(gè)批處理中。 ?executeBatch():向數(shù)據(jù)庫發(fā)送一批 sql 語句執(zhí)行。
5 PreparedStatement 接口
繼承自 Statement 接口,由 preparedStatement 創(chuàng)建,用于發(fā)送含有一個(gè)或多個(gè)參數(shù)的 SQL 語句。PreparedStatement 對(duì)象比 Statement 對(duì)象的效率更高,并且可以防止 SQL 注入,所以 我們一般都使用 PreparedStatement。
5.1常用方法
?addBatch()把當(dāng)前 sql 語句加入到一個(gè)批處理中。 ?execute() 執(zhí)行當(dāng)前 SQL,返回個(gè) boolean 值 ?executeUpdate()運(yùn)行 insert/update/delete 操作,返回更新的行數(shù)。 ?executeQuery() 執(zhí)行當(dāng)前的查詢,返回一個(gè)結(jié)果集對(duì)象 ?setDate(intparameterIndex,Date x)向當(dāng)前SQL語句中的指定位置綁定一個(gè)java.sql.Date
值。
? setDouble(int parameterIndex, double x)向當(dāng)前 SQL 語句中的指定位置綁定一個(gè) double
值
?setFloat(intparameterIndex,floatx)向當(dāng)前 SQL 語句中的指定位置綁定一個(gè) float 值 ?setInt(intparameterIndex,intx)向當(dāng)前 SQL 語句中的指定位置綁定一個(gè) int 值 ?setString(intparameterIndex,Stringx)向當(dāng)前 SQL 語句中的指定位置綁定一個(gè) String 值
6 ResultSet 接口
ResultSet 提供檢索不同類型字段的方法。
6.1常用方法
?getString(intindex)、getString(StringcolumnName) 獲得在數(shù)據(jù)庫里是 varchar、char 等類型的數(shù)據(jù)對(duì)象。 ?getFloat(intindex)、getFloat(StringcolumnName) 獲得在數(shù)據(jù)庫里是 Float 類型的數(shù)據(jù)對(duì)象。 ?getDate(intindex)、getDate(StringcolumnName) 獲得在數(shù)據(jù)庫里是 Date 類型的數(shù)據(jù)。 ?getBoolean(intindex)、getBoolean(StringcolumnName) 獲得在數(shù)據(jù)庫里是 Boolean 類型的數(shù)據(jù)。 ?getObject(intindex)、getObject(StringcolumnName) 獲取在數(shù)據(jù)庫里任意類型的數(shù)據(jù)。
6.2ResultSet 對(duì)結(jié)果集進(jìn)行滾動(dòng)的方法
?next():移動(dòng)到下一行。 ?Previous():移動(dòng)到前一行。 ?absolute(introw):移動(dòng)到指定行。 ?beforeFirst():移動(dòng) resultSet 的最前面。 ?afterLast() :移動(dòng)到 resultSet 的最后面。
7 CallableStatement 接口
繼承自 PreparedStatement 接口,由方法 prepareCall 創(chuàng)建,用于調(diào)用數(shù)據(jù)庫的存儲(chǔ)過程。
三、 JDBC 的使用
加載數(shù)據(jù)庫驅(qū)動(dòng)程序 → 建立數(shù)據(jù)庫連接 Connection → 創(chuàng)建執(zhí)行 SQL 的語句 Statement→ 處理執(zhí)行結(jié)果 ResultSet→ 釋放資源
1 下載數(shù)據(jù)庫驅(qū)動(dòng)
1.1MySQL 驅(qū)動(dòng)
1.2Oracle 驅(qū)動(dòng)
數(shù)據(jù)庫安裝目錄\oracle\product\11.2.0\dbhome_1\jdbc\lib
2 創(chuàng)建項(xiàng)目添加驅(qū)動(dòng)
3 通過 Statement 向表中插入數(shù)據(jù)
3.1注冊(cè)驅(qū)動(dòng)
Class.forName("com.mysql.jdbc.Driver");
3.2獲取連接
// 創(chuàng)建連接 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/
+ mysql?useSSL=false&useUnicode=true&" +
"characterEncoding=utf-8", "root", "root");
// jdbc:mysql://連接地址:連接端口號(hào)/連接那個(gè)數(shù)據(jù)庫?是否驗(yàn)證&開啟編碼&編碼方式
// root登陸數(shù)據(jù)庫的賬戶 //root登陸數(shù)據(jù)庫的密碼
3.3執(zhí)行 SQL
sta = conn.createStatement();//用于去提交事務(wù)的對(duì)象
String sql = "insert into usertable values(default,'"+age+"','"+userName+"','"+password+"')";
//所要執(zhí)行的sql語句
boolean flage = sta.execute(sql);//執(zhí)行sql語句
3.4釋放資源
finally {
try {
if(sta!=null) { //先關(guān)閉Statement
sta.close();
}
if(conn!=null) {//后關(guān)閉連接
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
更新表中的數(shù)據(jù)
public void updateUer(String userName,String passward,int age) {
Connection conn = null;
Statement sta = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql?"
+ "useSSL=false&useUnicode=true&" +
"characterEncoding=utf-8", "root", "root");
sta = conn.createStatement();
String sql = "update usertable set name='"+userName+"',passward="
+ "'"+passward+"',age='"+age+"'";
sta.executeUpdate(sql);
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(sta!=null) {
sta.close();
}
if(conn!=null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
4 ResultSet 講解
注意 ResultSet 中封裝的并不是我們查詢到的所有的結(jié)果集,而是返回了查詢到的結(jié)果 集的數(shù)據(jù)庫游標(biāo)。通過 ResultSet 中的 next()方法操作游標(biāo)的位置獲取結(jié)果集。
5 通過 ResultSet 實(shí)現(xiàn)邏輯分頁
sta = conn.createStatement();
String sql = "select * from usertable";
res = sta.executeQuery(sql);
int begin = (curretPage - 1) * pageSize + 1;// 指向當(dāng)前頁的起始數(shù)據(jù)
int end = curretPage * pageSize; // 指向當(dāng)前頁的最后一條數(shù)據(jù)
int currentCount = begin; // 指向當(dāng)前頁的第幾條數(shù)據(jù),最開始是指向第一條的
while (res.next()) {
if (currentCount >= begin && currentCount <= end) {
System.out.println(
res.getInt("id") + "\t" + res.getString("name") + "\t" + res.getString("passward"));
if (currentCount == end) {
break;
}
currentCount++;
}
}
6 SQL 注入問題
6.1什么是 SQL 注入
所謂 SQL 注入,就是通過把含有 SQL 語句片段的參數(shù)插入到需要執(zhí)行的 SQL 語句中, 最終達(dá)到欺騙數(shù)據(jù)庫服務(wù)器執(zhí)行惡意操作的 SQL 命令。
6.2SQL 注入案例
// SQL注入
public void sqlInject(String name) {
Connection conn = null;
Statement sta = null;
ResultSet res = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql?useSSL=false&
+"useUnicode=true&characterEncoding=utf-8", "root", "root");
sta = conn.createStatement();
String sql = "select * from usertable where name='" + name + "'";
res = sta.executeQuery(sql);
while (res.next()) {
System.out.println(res.getString("name") + "\t" + res.getString("id"));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
JDBCTest test = new JDBCTest();
test.sqlInject("李四' or 1=1 -- ");// --空格在數(shù)據(jù)庫中表示注釋,會(huì)查出數(shù)據(jù)庫中的所有數(shù)據(jù)
}
7. PreparedStatement 對(duì)象的使用(重點(diǎn))
7.1 PreparedStatement 特點(diǎn):
?PreparedStatement 接口繼承 Statement 接口
?PreparedStatement 效率高于 Statement
?PreparedStatement 支持動(dòng)態(tài)綁定參數(shù)
?PreparedStatement 具備 SQL 語句預(yù)編譯能力
? 使用 PreparedStatement 可防止出現(xiàn) SQL 注入問題
7.2通過 PreparedStatement 對(duì)象向表中插入數(shù)據(jù)
代碼
public void insert(int age, String name, String password) {
Connection conn = null;
PreparedStatement ps = null;
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql?useSSL=false&
+"useUnicode=true&characterEncoding=utf-8", "root", "root");
String sql = "insert into usertable values(default,?,?,?)";
try {
ps = conn.prepareStatement(sql);
ps.setInt(1, age);//將第一個(gè)問號(hào)的位置設(shè)置值
ps.setString(2, name);//將第二個(gè)問號(hào)的位置設(shè)置值
ps.setString(3, password);//將第三個(gè)問號(hào)的位置設(shè)置值
ps.execute();
} catch (SQLException e) {
e.printStackTrace();
}
}
8 PreparedStatement 的預(yù)編譯能力
8.1什么是預(yù)編譯
8.1.1 SQL 語句的執(zhí)行步驟
? 語法和語義解析
? 優(yōu)化 sql 語句,制定執(zhí)行計(jì)劃
? 執(zhí)行并返回結(jié)果
但是很多情況,我們的一條 sql 語句可能會(huì)反復(fù)執(zhí)行,或者每次執(zhí)行的時(shí)候只有個(gè)別的 值不同(比如 select 的 where 子句值不同,update 的 set 子句值不同,insert 的 values 值不同)。 如果每次都需要經(jīng)過上面的詞法語義解析、語句優(yōu)化、制定執(zhí)行計(jì)劃等,則效率就明顯不行 了。 所謂預(yù)編譯語句就是將這類語句中的值用占位符替代,可以視為將 sql 語句模板化或者 說參數(shù)化 預(yù)編譯語句的優(yōu)勢(shì)在于:一次編譯、多次運(yùn)行,省去了解析優(yōu)化等過程;此外預(yù)編譯語 句能防止 sql 注入
8.1.2 解析過程
8.1.2.1 硬解析 在不開啟緩存執(zhí)行計(jì)劃的情況下,每次 SQL 的處理都要經(jīng)過:語法和語義的解析,優(yōu) 化器處理 SQL,生成執(zhí)行計(jì)劃。整個(gè)過程我們稱之為硬解析。
8.1.2.2 軟解析 如果開啟了緩存執(zhí)行計(jì)劃,數(shù)據(jù)庫在處理 sql 時(shí)會(huì)先查詢緩存中是否含有與當(dāng)前 SQL 語句相同的執(zhí)行計(jì)劃,如果有則直接執(zhí)行該計(jì)劃。
8.2預(yù)編譯方式
開始數(shù)據(jù)庫的日志 showVARIABLESlike '%general_log%' setGLOBALgeneral_log=on setGLOBALlog_output='table'
8.2.1 依賴數(shù)據(jù)庫驅(qū)動(dòng)完成預(yù)編譯
如果我們沒有開啟數(shù)據(jù)庫服務(wù)端編譯,那么默認(rèn)的是使用數(shù)據(jù)庫驅(qū)動(dòng)完成 SQL 的預(yù)編 譯處理。
8.2.2 依賴數(shù)據(jù)庫服務(wù)器完成預(yù)編譯
我們可以通過修改連接數(shù)據(jù)庫的 URL 信息,添加 useServerPrepStmts=true 信息開啟服 務(wù)端預(yù)編譯。
9 PreparedStatement 批處理操作
代碼
String sql = "insert into usertable values(default,?,?,?)";
ps = conn.prepareStatement(sql);
for (User user : list) {
ps.setInt(1, user.getAge());
ps.setString(2, user.getName());
ps.setString(3, user.getPassword());
ps.addBatch();
}
ps.executeBatch();//提交
10 JDBC 中的事務(wù)處理
在 JDBC 操作中數(shù)據(jù)庫事務(wù)默認(rèn)為自動(dòng)提交。如果事務(wù)需要修改為手動(dòng)提交,那么我們 需要使用 Connection 對(duì)象中的 setAutoCommit 方法來關(guān)閉事務(wù)自動(dòng)提交。然后通過 Connection 對(duì)象中的 commit 方法與 rollback 方法進(jìn)行事務(wù)的提交與回滾。
代碼
String sql = "delete from usertable where name like ?";
conn.setAutoCommit(false);//將事務(wù)設(shè)置為手動(dòng)提交,默認(rèn)是自動(dòng)提交
ps = conn.prepareStatement(sql);
ps.setString(1,"%"+name+"%");
ps.execute();
conn.commit();//提交事務(wù)
四、 JDBC 進(jìn)階
1 動(dòng)態(tài)查詢
動(dòng)態(tài)刪除:根據(jù)用戶給定的條件來決定執(zhí)行什么樣的查詢。
//動(dòng)態(tài)刪除public void dynamicDelete(User user) {
Connection conn = null;
PreparedStatement ps = null;
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql?useSSL=false&+"useUnicode=true&characterEncoding=utf-8", "root", "root");String sql = connectSQL(user);try {conn.prepareStatement(sql);} catch (SQLException e) {e.printStackTrace();}}public String connectSQL(User user) {StringBuilder sb = new StringBuilder("delete from usertable where 1=1 ");if(user.getAge()>0) {sb.append(" and age = ").append(user.getAge());}if (user.getName()!=null) {sb.append(" add name = '").append(user.getName()).append("'");}if (user.getPassword()!=null) {sb.append(" and password = '").append(user.getPassword()).append("'");
}
return sb.toString();
}
總結(jié)
以上是生活随笔為你收集整理的mysql和jdbc的区别_JDBC详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 求一个好听的炫舞名字。
- 下一篇: springboot @cacheabl