Java程式設計基礎33——JDBC

扎瓦發表於2019-01-19

1.JDBC概念和資料庫驅動程式

  • A: JDBC概述

    • JDBC(Java Data Base Connectivity,java資料庫連線)是一種用於執行SQL語句的Java API,可以為多種關聯式資料庫提供統一訪問,它由一組用Java語言編寫的類和介面組成。是Java訪問資料庫的標準規範
    • JDBC提供了一種基準,據此可以構建更高階的工具和介面,使資料庫開發人員能夠編寫資料庫應用程式。
    • JDBC需要連線驅動,驅動是兩個裝置要進行通訊,滿足一定通訊資料格式,資料格式由裝置提供商規定,裝置提供商為裝置提供驅動軟體,通過軟體可以與該裝置進行通訊。
    • 我們使用的是mysql的驅動mysql-connector-java-5.1.39-bin.jar
  • B: 總結

    • JDBC是java提供給開發人員的一套運算元據庫的介面
    • 資料庫驅動就是實現該介面的實現類

2.JDBC原理

  • Java提供訪問資料庫規範稱為JDBC,而生產廠商提供規範的實現類稱為驅動
  • DBC是介面,驅動是介面的實現,沒有驅動將無法完成資料庫連線,從而不能運算元據庫!每個資料庫廠商都需要提供自己的驅動,用來連線自己公司的資料庫,也就是說驅動一般都由資料庫生成廠商提供。

3.準備資料

#建立資料庫
    create database mybase;
#使用資料庫
    use mybase;
#建立分類表
create table sort(
    sid int PRIMARY KEY AUTO_INCREMENT,
    sname varchar(100),
    sprice DOUBLE,
    sdesc VARCHAR(500)
);

#初始化資料
insert into sort(sname,sprice,sdesc) values
(`家電`,2000, `優惠的促銷`),
(`傢俱`,8900, `傢俱價格上調`),
(`玩具`,290, `賺家長的錢`),
(`生鮮`,500.99, `生鮮商品`),
(`服裝`,24000, `換季銷售`),
(`日用`,50, `洗髮水促銷`);

4.JDBC的開發步驟

  • 1.註冊驅動:告知JVM使用的是哪一個資料庫的驅動
  • 2.獲得連線:使用JDBC中的類,完成對MySQL資料庫的連線
  • 3.獲得語句執行平臺:通過連線物件獲取對SQL語句的執行者物件
  • 4.執行sql語句:使用執行者物件,向資料庫執行SQL語句,獲取到資料庫的執行後的結果
  • 5.處理結果
  • 6.釋放資源 一堆close();

5.匯入mysql資料庫驅動程式jar包

  • 建立lib目錄,用於存放當前專案需要的所有jar包
  • 選擇jar包,右鍵執行build path / Add to Build Path

6.註冊資料庫驅動程式

public class JDBCDemo {
    public static void main(String[] args)throws ClassNotFoundException,SQLException{
    //1.註冊驅動 反射技術,將驅動類加入到內容
    // 使用java.sql.DriverManager類靜態方法 registerDriver(Driver driver)
    // Diver是一個介面,引數傳遞,MySQL驅動程式中的實現類
    //DriverManager.registerDriver(new Driver());
    //驅動類原始碼,註冊2次驅動程式
    Class.forName("com.mysql.jdbc.Driver");                    
    }
}

7.獲取資料庫的連線物件

  • A:案例程式碼
public class JDBCDemo {
    public static void main(String[] args)throws ClassNotFoundException,SQLException{
        //1.註冊驅動 反射技術,將驅動類加入到內容
        // 使用java.sql.DriverManager類靜態方法 registerDriver(Driver driver)
        // Diver是一個介面,引數傳遞,MySQL驅動程式中的實現類
        //DriverManager.registerDriver(new Driver());
        //驅動類原始碼,註冊2次驅動程式
        Class.forName("com.mysql.jdbc.Driver");

        //2.獲得資料庫連線  DriverManager類中靜態方法
        //static Connection getConnection(String url, String user, String password)  
        //返回值是Connection介面的實現類,在mysql驅動程式
        //url: 資料庫地址  jdbc:mysql://連線主機IP:埠號//資料庫名字
        String url = "jdbc:mysql://localhost:3296/mybase";
        //使用者名稱和密碼用自己的
        String username="root";
        String password="123";
        Connection con = DriverManager.getConnection(url, username, password);
        System.out.println(con);                    
    }
}

8.獲取SQL語句的執行物件物件

  • A: 案例程式碼
public class JDBCDemo {
    public static void main(String[] args)throws ClassNotFoundException,SQLException{
        //1.註冊驅動 反射技術,將驅動類加入到內容
        // 使用java.sql.DriverManager類靜態方法 registerDriver(Driver driver)
        // Diver是一個介面,引數傳遞,MySQL驅動程式中的實現類
        //DriverManager.registerDriver(new Driver());
        //驅動類原始碼,註冊2次驅動程式
        Class.forName("com.mysql.jdbc.Driver");

        //2.獲得資料庫連線  DriverManager類中靜態方法
        //static Connection getConnection(String url, String user, String password)  
        //返回值是Connection介面的實現類,在mysql驅動程式
        //url: 資料庫地址  jdbc:mysql://連線主機IP:埠號//資料庫名字
        String url = "jdbc:mysql://localhost:3296/mybase";
        String username="root";
        String password="123";
        Connection con = DriverManager.getConnection(url, username, password);

        //3.獲得語句執行平臺, 通過資料庫連線物件,獲取到SQL語句的執行者物件
        // con物件呼叫方法   Statement createStatement() 獲取Statement物件,將SQL語句傳送到資料庫
        // 返回值是 Statement介面的實現類物件,,在mysql驅動程式
        Statement stat = con.createStatement();
        System.out.println(stat);
    }
}

9.執行insert語句獲取結果集

  • A: 案例程式碼
public class JDBCDemo {
    public static void main(String[] args)throws ClassNotFoundException,SQLException{
        //1.註冊驅動 反射技術,將驅動類加入到內容
        // 使用java.sql.DriverManager類靜態方法 registerDriver(Driver driver)
        // Diver是一個介面,引數傳遞,MySQL驅動程式中的實現類
        //DriverManager.registerDriver(new Driver());
        //驅動類原始碼,註冊2次驅動程式
        Class.forName("com.mysql.jdbc.Driver");

        //2.獲得資料庫連線  DriverManager類中靜態方法
        //static Connection getConnection(String url, String user, String password)  
        //返回值是Connection介面的實現類,在mysql驅動程式
        //url: 資料庫地址  jdbc:mysql://連線主機IP:埠號//資料庫名字
        String url = "jdbc:mysql://localhost:3296/mybase";
        String username="root";
        String password="123";
        Connection con = DriverManager.getConnection(url, username, password);

        //3.獲得語句執行平臺, 通過資料庫連線物件,獲取到SQL語句的執行者物件
        // con物件呼叫方法   Statement createStatement() 獲取Statement物件,將SQL語句傳送到資料庫
        // 返回值是 Statement介面的實現類物件,,在mysql驅動程式
        Statement stat = con.createStatement();
        //    4.執行sql語句
        // 通過執行者物件呼叫方法執行SQL語句,獲取結果
        // int executeUpdate(String sql)  執行資料庫中的SQL語句, insert delete update
        // 返回值int,操作成功資料表多少行
        int row = stat.executeUpdate
                ("INSERT INTO sort(sname,sprice,sdesc) VALUES(`汽車用品`,50000,`瘋狂漲價`)");
        System.out.println(row);

        //6.釋放資源  一堆close()
        stat.close();
        con.close();
    }
}

10.執行select語句獲取結果集

  • A: 案例程式碼
public class JDBCDemo1 {
    public static void main(String[] args) throws Exception{
        //1. 註冊驅動
        Class.forName("com.mysql.jdbc.Driver");
        //2. 獲取連線物件
        String url = "jdbc:mysql://localhost:3296/mybase";
        String username="root";
        String password="123";
        Connection con = DriverManager.getConnection(url, username, password);
        //3 .獲取執行SQL 語句物件
        Statement stat = con.createStatement();
        // 拼寫查詢的SQL
        String sql = "SELECT * FROM sort";
        //4. 呼叫執行者物件方法,執行SQL語句獲取結果集
        // ResultSet executeQuery(String sql)  執行SQL語句中的select查詢
        // 返回值ResultSet介面的實現類物件,實現類在mysql驅動中
        ResultSet rs = stat.executeQuery(sql);
        //5 .處理結果集
        // ResultSet介面方法 boolean next() 返回true,有結果集,返回false沒有結果集
        while(rs.next()){
            //獲取每列資料,使用是ResultSet介面的方法 getXX方法引數中,建議寫String列名
            System.out.println(rs.getInt("sid")+"   "+rs.getString("sname")+
                    "   "+rs.getDouble("sprice")+"   "+rs.getString("sdesc"));
        }

        rs.close();
        stat.close();
        con.close();
    }
}

11.SQL隱碼攻擊

  • A: SQL隱碼攻擊

    • a: 注入問題

      • 假設有登入案例SQL語句如下:
      • SELECT * FROM 使用者表 WHERE NAME = 使用者輸入的使用者名稱 AND PASSWORD = 使用者輸的密碼;
      • 此時,當使用者輸入正確的賬號與密碼後,查詢到了資訊則讓使用者登入。
        但是當使用者輸入的賬號為XXX 密碼為:XXX’ OR ‘a’=’a時,則真正執行的程式碼變為:

        • SELECT * FROM 使用者表 WHERE NAME = ‘XXX’ AND PASSWORD =’ XXX’ OR ’a’=’a’;
      • 此時,上述查詢語句時永遠可以查詢出結果的。那麼使用者就直接登入成功了,顯然我們不希望看到這樣的結果,這便是SQL隱碼攻擊問題。
    • b: 案例演示
CREATE TABLE users(
     id INT PRIMARY KEY AUTO_INCREMENT,
     username VARCHAR(100),
     PASSWORD VARCHAR(100)
);

INSERT INTO users (username,PASSWORD) VALUES (`a`,`1`),(`b`,`2`);

SELECT * FROM users;

-- 登入查詢
SELECT * FROM users WHERE username=`dsfsdfd` AND PASSWORD=`wrethiyu`1 OR 1=1

SELECT * FROM users WHERE username=`a` AND PASSWORD=`1`OR`1=1`
鍵盤錄入:
sdsdd
dfsssdd`or` 1=1

12.SQL隱碼攻擊使用者登入案例

  • A: 案例程式碼
public class JDBCDemo2 {
    public static void main(String[] args)throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3296/mybase";
        String username = "root";
        String password = "123";
        Connection con = DriverManager.getConnection(url, username, password);
        Statement stat = con.createStatement();

        Scanner sc = new Scanner(System.in);
        String user = sc.nextLine();
        String pass = sc.nextLine();

        //執行SQL語句,資料表,查詢使用者名稱和密碼,如果存在,登入成功,不存在登入失敗
        String sql = "SELECT * FROM users WHERE username=`dsfsdfd` AND PASSWORD=`wrethiyu` OR 1=1";
        String sql = "SELECT * FROM users WHERE username=`"+user+"` AND PASSWORD=`"+pass+"`";
        System.out.println(sql);
        ResultSet rs = stat.executeQuery(sql);
        while(rs.next()){
            System.out.println(rs.getString("username")+"   "+rs.getString("password"));
        }

        rs.close();
        stat.close();
        con.close();
    }
}

13.PrepareStatement介面預編譯SQL語句

  • A: PrepareStatement介面預編譯SQL語句

    • a: 預處理物件

      • 使用PreparedStatement預處理物件時,建議每條sql語句所有的實際引數,都使用逗號分隔。
      • String sql = “insert into sort(sid,sname) values(?,?)”;;
      • PreparedStatement預處理物件程式碼:
      • PreparedStatement psmt = conn.prepareStatement(sql)
    • b: 執行SQL語句的方法介紹

      • int executeUpdate(); –執行insert update delete語句.
      • ResultSet executeQuery(); –執行select語句.
      • boolean execute(); –執行select返回true 執行其他的語句返回false.
    • c: 設定實際引數

      • void setXxx(int index, Xxx xx) 將指定引數設定為給定Java的xx值。在將此值傳送到資料庫時,驅動程式將它轉換成一個 SQL Xxx型別值。
      • 例如:

        • setString(2, “家用電器”) 把SQL語句中第2個位置的佔位符? 替換成實際引數 “家用電器”
    • d: 案例程式碼
/*
 *  Java程式實現使用者登入,使用者名稱和密碼,資料庫檢查
 *  防止注入攻擊
 *  Statement介面實現類,作用執行SQL語句,返回結果集
 *  有一個子介面PreparedStatement  (SQL預編譯儲存,多次高效的執行SQL) 
 *  PreparedStatement的實現類資料庫的驅動中,如何獲取介面的實現類
 *  是Connection資料庫連線物件的方法
 *  PreparedStatement prepareStatement(String sql) 
 */
 
public class JDBCDemo3 {
    public static void main(String[] args)throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3296/mybase";
        String username = "root";
        String password = "123";
        Connection con = DriverManager.getConnection(url, username, password);
        Scanner sc = new Scanner(System.in);
        String user = sc.nextLine();
        String pass = sc.nextLine();

        //執行SQL語句,資料表,查詢使用者名稱和密碼,如果存在,登入成功,不存在登入失敗
        String sql = "SELECT * FROM users WHERE username=? AND PASSWORD=?";
        //呼叫Connection介面的方法prepareStatement,獲取PrepareStatement介面的實現類
        //方法中引數,SQL語句中的引數全部採用問號佔位符
        PreparedStatement pst =  con.prepareStatement(sql);
        System.out.println(pst);
        //呼叫pst物件set方法,設定問號佔位符上的引數
        pst.setObject(1, user);
        pst.setObject(2, pass);

        //呼叫方法,執行SQL,獲取結果集
        ResultSet rs = pst.executeQuery();
        while(rs.next()){
            System.out.println(rs.getString("username")+"   "+rs.getString("password"));
        }

        rs.close();
        pst.close();
        con.close();
    }
}

14.PrepareStatement介面預編譯SQL語句執行修改

  • A: 使用PrepareStatement介面,實現資料表的更新操作

    • 案例程式碼
public class JDBCDemo {
    public static void main(String[] args) throws Exception{
        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3296/mybase";
        String username="root";
        String password="123";
        Connection con = DriverManager.getConnection(url, username, password);    
        
        //拼寫修改的SQL語句,引數採用?佔位
        String sql = "UPDATE sort SET sname=?,sprice=? WHERE sid=?";
        //呼叫資料庫連線物件con的方法prepareStatement獲取SQL語句的預編譯物件
        PreparedStatement pst = con.prepareStatement(sql);
        //呼叫pst的方法setXXX設定?佔位
        pst.setObject(1, "汽車美容");
        pst.setObject(2, 49988);
        pst.setObject(3, 7);
        //呼叫pst方法執行SQL語句
        pst.executeUpdate();
        
        pst.close();
        con.close();
    }
}

15.PrepareStatement介面預編譯SQL語句執行查詢

  • A: PrepareStatement介面實現資料表的查詢操作
public class JDBCDemo1 {
    public static void main(String[] args) throws Exception{
        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3296/mybase";
        String username="root";
        String password="123";
        Connection con = DriverManager.getConnection(url, username, password);    

        String sql = "SELECT * FROM sort";

        PreparedStatement pst = con.prepareStatement(sql);

        //呼叫pst物件的方法,執行查詢語句,Select
        ResultSet rs=pst.executeQuery();
        while(rs.next()){
            System.out.println(rs.getString("sid")+"  "+rs.getString("sname")+"  "+rs.getString("sprice")+"  "+rs.getString("sdesc"));
        }
        rs.close();
        pst.close();
        con.close();
    }
}

16.JDBC的工具類和測試

  • A: 案例程式碼
//實現JDBC的工具類
//定義方法,直接返回資料庫的連線物件
public class JDBCUtils{
    private JDBCUtils(){}
    private static Connection con;

    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            con = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3307/mybase", "root", "allidea");
        } catch (Exception ex){
            throw new RuntimeException(ex + "資料庫連線失敗");
        }
    }

    //定義靜態方法,返回資料庫的連線物件

    public static Connection getConnection() {
        return con;
    }

    public static void colse(Connection con, Statement stat) {
        if(stat != null) {
            try{
                stat.close();
            }catch (SQLException ex) {}
        }

        if(con != null) {
            try{
                con.close();
            }catch (SQLException ex) {}
        }
    }

    public static void colse(Connection con, Statement stat, ResultSet rs) {
        if(rs != null) {
            try{
                rs.close();
            }catch (SQLException ex) {}
        }

        if(stat != null) {
            try{
                stat.close();
            }catch (SQLException ex) {}
        }

        if(con != null) {
            try{
                con.close();
            }catch (SQLException ex) {}
        }
    }
}
//測試JDBCUtils工具類的程式碼
public class TestJDBCUtils {
    public static void main(String[] args)throws Exception {
        Connection con = JDBCUtils.getConnection();
        PreparedStatement pst = con.prepareStatement("SELECT sname FROM sort");
        ResultSet rs = pst.executeQuery();
        while(rs.next()){
            System.out.println(rs.getString("sname"));
        }
        JDBCUtils.close(con, pst, rs);
    }
}

17.資料表資料儲存物件

  • A: 資料表資料儲存物件

    • a: 準備工作

      • 匯入jar包
      • 準備工具類JDBCUtils
    • b: 案例程式碼
//定義實體類Sort
public class Sort {
    private int sid;
    private String sname;
    private double sprice;
    private String sdesc;
    public Sort(int sid, String sname, double sprice, String sdesc) {
        this.sid = sid;
        this.sname = sname;
        this.sprice = sprice;
        this.sdesc = sdesc;
    }
    public Sort(){}
    public int getSid() {
        return sid;
    }
    public void setSid(int sid) {
        this.sid = sid;
    }
    public String getSname() {
        return sname;
    }
    public void setSname(String sname) {
        this.sname = sname;
    }
    public double getSprice() {
        return sprice;
    }
    public void setSprice(double sprice) {
        this.sprice = sprice;
    }
    public String getSdesc() {
        return sdesc;
    }
    public void setSdesc(String sdesc) {
        this.sdesc = sdesc;
    }
    @Override
    public String toString() {
        return "Sort [sid=" + sid + ", sname=" + sname + ", sprice=" + sprice + ", sdesc=" + sdesc + "]";
    }                
}
/*
 *  JDBC讀取資料表sort,每行資料封裝到Sort類的物件中
 *  很多個Sort類物件,儲存到List集合中
 */
public class JDBCDemo {
    public static void main(String[] args) throws Exception{
        //使用JDBC工具類,直接獲取資料庫連線物件
        Connection con = JDBCUtils.getConnection();
        //連線獲取資料庫SQL語句執行者物件
        PreparedStatement pst = con.prepareStatement("SELECT * FROM sort");
        //呼叫查詢方法,獲取結果集
        ResultSet rs = pst.executeQuery();
        //建立集合物件
        List<Sort> list = new ArrayList<Sort>();
        while(rs.next()){
            //獲取到每個列資料,封裝到Sort物件中
            Sort s = new Sort(rs.getInt("sid"),rs.getString("sname"),rs.getDouble("sprice"),rs.getString("sdesc"));
            //封裝的Sort物件,儲存到集合中
            list.add(s);
        }
        JDBCUtils.close(con, pst, rs);
        //遍歷List集合
        for(Sort s : list){
            System.out.println(s);
        }
    }
}

18.properties配置檔案

  • A:開發中獲得連線的4個引數(驅動、URL、使用者名稱、密碼)通常都存在配置檔案中,方便後期維護,程式如果需要更換資料庫,只需要修改配置檔案即可。
  • B:通常情況下,我們習慣使用properties檔案,此檔案我們將做如下要求:

    • 1.檔案位置:建議src下
    • 2.檔名稱:任意,副檔名為properties
    • 3.檔案內容:一行一組資料,格式是“key=value”.
    • 4:key命名自定義,如果是多個單詞,習慣使用點分隔。例如:jdbc.driver
    • 5:value值不支援中文,如果需要使用非英文字元,將進行unicode轉換。
  • C: properties檔案的建立

    • src路徑下建立database.properties(其實就是一個文字檔案)
  • D: properties檔案的編寫(內容如下)
    driverClass=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3296/mybase
    username=root
    password=123        
  • E: 載入配置檔案
/*
 *  載入properties配置檔案
 *  IO讀取檔案,鍵值對儲存到集合
 *  從集合中以鍵值對方式獲取資料庫的連線資訊,完成資料庫的連線
 */
public class PropertiesDemo {
    public static void main(String[] args) throws Exception{
        FileInputStream fis = new FileInputStream("database.properties");
        System.out.println(fis);
        //使用類的載入器
        InputStream in = PropertiesDemo.class.getClassLoader().getResourceAsStream("database.properties");
        System.out.println(in);
        Properties pro = new Properties();
        pro.load(in);
        System.out.println(in);                    
    }
}
  • F: 通過配置檔案連線資料庫
/*
 *  載入properties配置檔案
 *  IO讀取檔案,鍵值對儲存到集合
 *  從集合中以鍵值對方式獲取資料庫的連線資訊,完成資料庫的連線
 */
public class PropertiesDemo {
    public static void main(String[] args) throws Exception{
        FileInputStream fis = new FileInputStream("database.properties");
        System.out.println(fis);
        //使用類的載入器
        InputStream in = PropertiesDemo.class.getClassLoader().getResourceAsStream("database.properties");
        System.out.println(in);
        Properties pro = new Properties();
        pro.load(in);
        //獲取集合中的鍵值對
        String driverClass=pro.getProperty("driverClass");
        String url = pro.getProperty("url");
        String username = pro.getProperty("username");
        String password = pro.getProperty("password");
        Class.forName(driverClass);
        Connection con = DriverManager.getConnection(url, username, password);
        System.out.println(con);
    }
}

19.讀取配置檔案的工具類

  • A: 讀取配置檔案的工具類
/*
 *  編寫資料庫連線的工具類,JDBC工具類
 *  獲取連線物件採用讀取配置檔案方式
 *  讀取檔案獲取連線,執行一次,static{}
 */
public class JDBCUtilsConfig {
    private static Connection con ;
    private static String driverClass;
    private static String url;
    private static String username;
    private static String password;

    static{
        try{
            readConfig();
            Class.forName(driverClass);
            con = DriverManager.getConnection(url, username, password);
        }catch(Exception ex){
            throw new RuntimeException("資料庫連線失敗");
        }
    }

    private static void readConfig()throws Exception{
        InputStream in = JDBCUtilsConfig.class.getClassLoader().getResourceAsStream("database.properties");
         Properties pro = new Properties();
         pro.load(in);
         driverClass=pro.getProperty("driverClass");
         url = pro.getProperty("url");
         username = pro.getProperty("username");
         password = pro.getProperty("password");
    }

    public static Connection getConnection(){
        return con;
    }
}            
  • B: 測試工具類
public class TestJDBCUtils {
    public static void main(String[] args) {
        Connection con = JDBCUtilsConfig.getConnection();
        System.out.println(con);
    }
}

相關文章