文章目錄
一、JDBC基本知識
是什麼
- 英文全稱:Java DataBase Connectivity(java語言連接數據庫)
- 是sun公司制定一套規範,一套接口
爲什麼要有JDBC(接口)
- 因爲每一個數據庫的底層實現原理不一樣,恰恰符合面向接口編程,下面解釋
JDBC接口的調用者與實現者
- 調用者:java程序員,調用這個接口就可以連接數據庫並進行操作,而不管連接的是哪一個數據庫
- 實現者:各大數據庫廠家,如:MySQL,SQL Sever,Oracle等等,該公司的程序員編寫程序實現JDBC接口
一圖搞懂JDBC接口
驅動:各大數據庫廠家實現JDBC接口的實現類也叫驅動,也就是jar包,需要java程序員到官網上下載
二、java中與JDBC相關的接口
相關的接口與類位於java.sql包下,
接口 | 解釋 |
---|---|
DriverMannger類 | 管理一組JDBC驅動程序,用於註冊驅動 |
Connection | java程序與特定的數據庫連接 |
Statement | 用於數據庫操作 |
PreparedStatement | 用於數據庫操作,Statement的子接口,下文寫區別 |
ResultSet | 數據庫查詢返回的結果集 |
java與數據庫的連接與操作靠這幾個接口(類)就可以實現,並且調用前一個接口的方法可以生成,下一個類的對象,是層層遞進的關係
三、JDBC編程的步驟
1.步驟總覽
2.重點說下前三步
後三步的代碼背後沒有多少內容,所以先暫時放放
2.1註冊驅動
- 告訴java程序,即將要連接的是哪個品牌的數據庫
導入MySQL的jar包(驅動)
右擊項目---->Open Module Settings
找到jar包點擊ok即可
代碼註冊驅動
/**
* @author Think-Coder
* @data 2020/5/5 15:11
*/
import java.sql.*;
public class JDBCTest03
{
public static void main(String[] args){
try{
//1.註冊驅動常用方式
//爲什麼常用:因爲參數是一個字符串,字符串可以寫道xxx.properties文件中
Class.forName("com.mysql.jdbc.Driver");
}catch(Exception e){
e.printStackTrace();
}
}
}
com.mysql.jdbc.Driver類源碼
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {}
static {
try {
//這個方法是註冊MySQL驅動的
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
整個註冊驅動方法驅動在static靜態代碼塊中,當執行Class.forName(“com.mysql.jdbc.Driver”);時會加載com.mysql.jdbc.Driver類,此時static靜態代碼塊執行,便會註冊驅動了
2.2.獲取Connection連接:DriverManager.getConnection方法
- 表示JVM的進程和數據庫進程之間的通道打開了
- 進程通信,重量級的,使用完一定要關閉
方法參數需要提供
url(統一資源定位符)
如:jdbc:mysql://127.0.0.1:3306/selfproj
jdbc:mysql:// 協議
127.0.0.1 IP地址
3306 端口號
selfproj 數據庫名
賬號:root
密碼:123456
代碼如下:
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/selfproj?characterEncoding=utf8","root","123456");
getConnection方法中是三個字符串參數,可以放在外部配置文件中
當更改數據庫時,只要更改外部配置文件就搞定,不需要重新啓動服務,這個很重要
咱們記住一條規律
只要參數是字符串,用戶需要動態變化的,都可以寫在外部配置文件中
2.3.獲取數據庫操作對象:通過Connection接口中的方法創建對象
創建Statement對象,通過Connection接口的createStatement()方法
try {
//1.註冊驅動
Class.forName("com.mysql.jdbc.Driver");
//2.獲取鏈接
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/selfproj?useUnicode=true&characterEncoding=utf8","root","123456");
//3.獲取數據庫操作對象
stmt = conn.createStatement();
//4.執行sql
//存在sql注入問題
//假如此時userName="張三",userPwd="張三'or'1'='1"
//通過字符串拼接將sql關鍵字or拼接進去
//String sql="select * from user where name='張三' and pwd ='張三'or'1'='1'"
//不需要正確的用戶名及密碼就能此時就能進入系統
String sql = "select * from user where name='"+userName+"'and pwd ='"+userPwd+"'";
//以上正好完成了sql語句的拼接
//以下代碼的含義是,發送sql語句給DBMS,DBMS進行sql編譯
rs = stmt.executeQuery(sql);
if(rs.next()){
loginSucess = true;
}
}catch (Exception e) {
e.printStackTrace();
}
因爲存在SQL注入問題,平時開發基本不用Statement對象,所以沒有貼完整得代碼
3.JDBC完整的6步
接下來會寫一個用戶登錄完整的代碼
將JDBC的6步完全融合進去,使用了PreparedStatement對象,操作數據庫,是開發中最常用的
public class JDBCTest08 {
public static void main(String[] args) {
//初始化一個界面
Map<String,String> userLoginInfo = initUI();
//驗證用戶名和密碼
boolean loginSucess = false;
try {
loginSucess = login(userLoginInfo);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(loginSucess?"登錄成功":"登錄失敗");
}
//用戶登錄的方法
public static boolean login(Map<String,String> userLoginInfo){
//打標記
boolean loginSucess = false;
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
//單獨定義變量
String userName = userLoginInfo.get("loginName");
String userPwd = userLoginInfo.get("loginPwd");
try {
//1.註冊驅動
Class.forName("com.mysql.jdbc.Driver");
//2.獲取鏈接
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/selfproj?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT", "root", "123456");
//3.獲取數據庫預編譯PreparedStatement對象
//sql語句框子,一個?代表一個佔位符
String sql = "select * from test where id=? and pwd=?";
//程序執行到此,會發送sql語句框子給DBMS,然後DBMS進行sql語句的預先編譯
//此時sql語句中沒有用戶輸入的值,很好的解決了sql注入問題
ps = conn.prepareStatement(sql);
//給?佔位符傳值
ps.setString(1, userName);
ps.setString(2, userPwd);
//4.執行sql
rs = ps.executeQuery();
//5.處理返回的結果集
// rs爲返回的結果集
if (rs.next()) {
loginSucess = true;
}
}catch (Exception e){
e.printStackTrace();
} finally {
//6.釋放資源
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return loginSucess;
}
//用戶輸入的方法
private static Map<String, String> initUI() {
Scanner s = new Scanner(System.in);
System.out.println("用戶名:");
String loginName = s.nextLine();
System.out.println("密碼:");
String loginPwd = s.nextLine();
Map<String,String> userLoginInfo = new HashMap<>();
userLoginInfo.put("loginName",loginName);
userLoginInfo.put("loginPwd",loginPwd);
return userLoginInfo;
}
}
解釋說明
- 完整的JDBC編程6步就寫完了,JDBC編程6步是針對於查詢的
- 對於增刪改的,是不需要第5步的,因爲沒有返回查詢結果集
- 使用增刪改時,只需將第4步ps.executeQuery()變爲ps.executeUpdate()就可以了,代碼我就不寫了,哈哈
下面對比Statement對象和PreparedStatement對象
- 1.Statement存在sql注入問題,PreparedStatement解決了sql注入問題。
- 2.PreparedStatement執行效率高,編譯一次執行多次,因爲相同的sql語句不會再編譯
- 而Statement編譯一次執行一次,因爲基本上sql語句不會相同
- 3.PreparedStatement會在編譯階段做類型檢查
總結:開發場景中99%使用PreparedStatement對象,在需要SQL注入的業務場景中使用Statement
四.封裝工具類
註冊驅動、連接數據庫和釋放連接經常使用可以封裝到工具類中
public class DBUtil {
/*
* 工具類中的構造方法都是私有的
* 因爲工具類當中的方法是靜態的,不需要new對象,直接採用類名調用
* */
private DBUtil(){}
//靜態代碼塊在類加載時執行,並且只執行一次
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/*
* 獲取數據庫連接對象
* */
public static Connection getConnection()throws Exception{
return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/selfproj?useUnicode=true&characterEncoding=utf8","root","123456");
}
/*
* 關閉資源
* */
public static void close(Connection conn, Statement ps, ResultSet rs){
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
使用工具類,實現模糊查詢
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//使用工具類獲取連接
conn=DBUtil.getConnection();
//獲取預編譯的數據庫操作對象
String sql = "select * from user where pwd like ?";
ps = conn.prepareStatement(sql);
//實現查詢密碼第二位是2的
ps.setString(1,"_2%");
rs=ps.executeQuery();
while(rs.next()){
System.out.println(rs.getString("pwd"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//使用工具類釋放資源
DBUtil.close(conn,ps,rs);
}
}
五、總結
JDBC是一套讓各個數據庫廠家實現的接口,通過調用這些接口,實現java程序連接數據庫,很好體現面向接口編程的特點