1. 程式人生 > >JDBC技術詳解

JDBC技術詳解

JDBC基礎

1.JDBC介紹

JDBC是java訪問[物件型資料庫/關係型資料庫]資料庫的規則,是原SUN公司開發的.

原來我們程式設計師需要針對具體的資料庫操作,費時費力;
自從有了JDBC規則後,程式設計師只需要針對JDBC規則程式設計,不用管底層具體資料庫的實現,
好處在於:寫一份JDBC程式碼,可以在很多資料庫在執行,即可移植性

2.驅動的原理及使用

就是JDBC規則,在具體資料庫中的實現類,且用java書寫(需要安裝JDK)

3.JDBC核心使用

做jdbc程式碼,需要用到如下幾個固定步驟,以查詢為例:

  • 1_註冊mysql資料庫伺服器的驅動,DriverManager
  • 2_獲取mysql資料庫伺服器的連線,Connection
  • 3_獲取封裝sql語句的物件,Statement
  • 4_執行sql語句,並返回結果集合,ResultSet
  • 5_迭代這個結果集合,while(){}
  • 6_按輕到重的原則關閉連線物件,ResultSet-Statement-Connection,在必要情況下,Connection可重用

4.DriverManager(類)、Connection(介面)、Statement(介面)、ResultSet(介面)詳細使用

  • DriverManager:
    它是一個類,由原SUN公司提供,負責管理一個或一組訪問具體資料庫的驅動,
    即你想訪問Oracle資料庫伺服器的話,就讓DriverManager載入Oracle驅動,
    只需註冊一次就行

  • Connection:
    是原SUN公司提供的介面,是屬於重量級物件,建議少建立,要重用
    只要你想與資料庫進行操作,必須獲取連線物件

    jdbc:mysql://127.0.0.1:3306/mydb1","root","123"
    jdbc:主協議,你只要使用jdbc技術訪問資料庫,都是jdbc主協議
    mysql:子協議
    127.0.0.1:MySQL資料庫伺服器所在PC的IP地址或域名,建議用IP
    3306:MySQL資料庫伺服器所在的PC的埠號
    mydb1:訪問資料庫伺服器中哪一個具體的資料庫
    root:使用者名稱
    123:密碼,如果沒有密碼的話,也需要寫""空字串
    
  • Statement:
    負責封裝SQL語句並執行的物件,是原SUN公司提供的介面

    SQL語句在JDBC中分為二大類
    1_靜態SQL:SQL語句中無?符號,即select id,name from users where name = '張三'(上)
    2_動態SQL:SQL語句中有?符號,即select id,name from users where name = ?
               ?號由程式在執行時動態設定的值
    
  • Statement常用的API:
    查詢:executeQuery(引數為靜態SQL),返回值為ResultSet
    增刪改:executeUpdate(引數為靜態SQL),返回值為Int,表示影響表格行數

  • ResultSet:
    負責裝查詢語句的結果,預設情況下,遊標位於第一條記錄的前邊。
    next()方法就能向下移動一行,如果有結果,返回true

5.jdbc的crud

  • 增刪改:Statment.executeUpdate(),返回值為int,表示這次操作影響了表中的幾條記錄
  • 查詢:Statment.executeQuery(),返回值為ResultSet,表示這次查詢操作結果記錄數形成的集合

6.sql注入

  • 客戶端利用jdbc-Statement的缺點,傳入非法引數,從而讓jdbc返回不合法的值,我們利用這種情況,通稱為sql注入.
  • 現在專案中不直接使用Statement,使用PreparedStatement,PreparedStatement它除了具有Statement是所有功能外,還有動態sql處理能力,包括:程式執行時動態為?符設定值,安全檢查,避免sql注入問題,預處理能力

  • ?表示佔位符,只能出現在欄位值的位置,不能替代表名,不能替代列名;
    ?表示的欄位值,不管是什麼型別,都不用加”符號

  • Statement和PreparedStatement的區別:
    Statement只能處理靜態SQL;
    PreparedStatement既能處理靜態sql也能處理動態sql,它繼承了Statement的特點

  • 站在預處理角度:
    PreparedStatement適合做連續多次結構相同的sql語句,有優勢.
    Statement適合做連續多次不同結構的sql語句,有優勢.

  • 專案中,我們都用子介面,
    1_支援動態sql,也支援靜態sql
    2_預處理

    ---相同結構的sql
    select id,name,from users where id=1;
    select id,name,gender from users where id=2;
    是不相同結構 
    ---不同結構的sql
    
  • 宣告:
    靜態sql也可以用PreparedStatement

適合:
靜態sql—優先Statement;
動態sql—優先PreparedStatement

Statement程式碼實現:

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;

    /**
     * JDBC開發
     */
    public class Demo {
    static{
        //1)註冊一個MySQL資料庫驅動,因為你現在要訪問的是MySQL資料庫伺服器,用反射
        //好處:只向DriverManager註冊一次MySQL驅動
        //好處:無需匯入MySQL具體的類名
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    /**
     * 查詢所有使用者
     */
    public void findAllUser() throws Exception{
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            //NO2)獲取JavaApp與MySQL資料庫伺服器的連線
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mydb1","root","123");
            //NO3)建立封裝SQL語句的物件
            stmt = conn.createStatement();
            //NO4)執行SQL語句,返回結果集合,裡面存放裝SQL語句執行結果,即是四條記錄
            rs = stmt.executeQuery("select id,username,gender,hiredate from users");
            //NO5)迭代結果集合,在預設情況下,遊標指向第一條記錄之前,通過next方法將遊標下移一條,如果有記錄存在,返回true;否則false
            while(rs.next()){
                //獲取一條中id列名對應的值
                int id = rs.getInt("id");
                String username = rs.getString("username");
                String gender = rs.getString("gender");
                //在與JDBC訪問時,MySQL中的date,對應java中的java.sql.Date
                java.sql.Date hiredate = rs.getDate("hiredate");

                System.out.println(id+"#"+username+"#"+gender+"#"+hiredate);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            //通知呼叫者,給前臺使用者提示,html/jsp
            throw e;
        } finally{
            //NO6)關閉上述用過的連線物件
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }finally{
                    //GC回收
                    rs = null;
                }
            }
            if(stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }finally{
                    //GC回收
                    stmt = null;
                }
            }
            //後期重用Connection
            if(conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }finally{
                    //GC回收
                    conn = null;
                }
            }
        }
    }

    /**
     *  主方法
     */
    public static void main(String[] args) throws Exception{
        Demo dao = new Demo();
        dao.findAllUser();
    }
}

PreparedStatement完成對users表的CURD操作,程式碼實現:

    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import cn.itheima.entity.User;
    import cn.itheima.utils.JdbcUtils;

    /**
     * 演示PreparedStatement完成對users表的CURD操作
     */
    public class Demo01 {
        /**
         * 增加使用者 
         */
        public void add(User user){
            Connection conn = null;
            PreparedStatement pstmt = null;
            ResultSet rs = null;
            String sql = "insert into users(username,gender,hiredate) values(?,?,?)";
            try{
                conn = JdbcUtils.getConnection();
                pstmt = conn.prepareStatement(sql);
                pstmt.setString(1,user.getUsername());
                pstmt.setString(2,user.getGender());
                pstmt.setDate(3,new java.sql.Date(user.getHiredate().getTime()));
                int i = pstmt.executeUpdate();
                System.out.println(i>0?"成功":"失敗");
            }catch(Exception e){
                e.printStackTrace();
                throw new RuntimeException("增加使用者失敗");
            }finally{
                JdbcUtils.close(rs);
                JdbcUtils.close(pstmt);
                JdbcUtils.close(conn);
            }
        }
        /**
         * 修改使用者 
         */
        public void update(String oldUsername,String newUsername){
            Connection conn = null;
            PreparedStatement pstmt = null;
            ResultSet rs = null;
            String sql = "update users set username = ? where username = ?";
            try{
                conn = JdbcUtils.getConnection();
                pstmt = conn.prepareStatement(sql);
                pstmt.setString(1,newUsername);
                pstmt.setString(2,oldUsername);
                int i = pstmt.executeUpdate();
                System.out.println(i>0?"成功":"失敗");
            }catch(Exception e){
                e.printStackTrace();
                throw new RuntimeException("增加使用者失敗");
            }finally{
                JdbcUtils.close(rs);
                JdbcUtils.close(pstmt);
                JdbcUtils.close(conn);
            }
        }
        /**
         * 查詢使用者 
         * @param lastname 在這裡表示姓
         * @param gender 性別
         */
        public void find(String lastname,String gender){
            Connection conn = null;
            PreparedStatement pstmt = null;
            ResultSet rs = null;
            //String sql = "select * from users where username like '趙%' and gender = '男'";
            String sql = "select id,username,gender,hiredate from users where username like ? and gender = ?";
            try{
                conn = JdbcUtils.getConnection();
                pstmt = conn.prepareStatement(sql);
                pstmt.setString(1,lastname+"%");
                pstmt.setString(2,gender);
                rs = pstmt.executeQuery();
                while(rs.next()){
                    int id = rs.getInt("id");
                    String username = rs.getString("username");
                    gender = rs.getString("gender");
                    java.sql.Date hiredate = rs.getDate("hiredate");
                    System.out.println(id+"#"+username+"#"+gender+"#"+hiredate);
                }
            }catch(Exception e){
                e.printStackTrace();
                throw new RuntimeException("查詢使用者 失敗");
            }finally{
                JdbcUtils.close(rs);
                JdbcUtils.close(pstmt);
                JdbcUtils.close(conn);
            }
        }
        /**
         * 批量刪除使用者 
         */
        public void delete(int... ids){
            Connection conn = null;
            PreparedStatement pstmt = null;
            ResultSet rs = null;
            StringBuffer sb = new StringBuffer("delete from users where id in (");
            for(int id : ids){
                sb.append(id+",");
            }
            //刪除最後一個逗號
            sb.deleteCharAt(sb.length()-1);
            //在最後拼接)
            sb.append(")");
            String sql = sb.toString();
            try{
                conn = JdbcUtils.getConnection();
                pstmt = conn.prepareStatement(sql);
                int i = pstmt.executeUpdate();
                System.out.println(i>0?"成功":"失敗");
            }catch(Exception e){
                e.printStackTrace();
                throw new RuntimeException("批量刪除使用者失敗");
            }finally{
                JdbcUtils.close(rs);
                JdbcUtils.close(pstmt);
                JdbcUtils.close(conn);
            }
        }




        public static void main(String[] args) {
            Demo01 test = new Demo01();
            User user = new User();
            user.setUsername("張三");
            user.setGender("男");
            user.setHiredate(new java.util.Date());
            //test.add(user);
            //test.update("張三","李四");
            //test.find("趙","男");
            test.delete(1,6,7);
        }
    }