天貓總站JavaEE版本的實現(一):jdbc的學習

jdbc(java database connection)是java內部集成的一套負責與database交互api。用以在java端執行增刪查找數據庫數據的操作。
這一套操作爲:
1.準備好數據庫
先準備操作的數據庫表爲選課表。表結構如下:
這裏寫圖片描述

2.連接數據庫
- 爲項目引用Jar包

這裏寫圖片描述

  • 註冊Driver到DriverManager裏面

這裏寫圖片描述

上面的代碼中有加載類Class.forName("com.mysql.jdbc.Driver")的描述。

查看com.mysql.jdbc.Driver源碼如下:
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    // ~ Static fields/initializers
    // ---------------------------------------------

    //
    // Register ourselves with the DriverManager
    //
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

    // ~ Constructors
    // -----------------------------------------------------------

    /**
     * Construct a new driver and register it with DriverManager
     * 
     * @throws SQLException
     *             if a database error occurs.
     */
    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
}

可知,在加載com.mysql.jdbc.Driver的時候,已經生成了一個Driver實例,並將其註冊到DriverManager裏面了。

3.執行insert的sql語句
這裏寫圖片描述
查詢Category表中數據爲:

這裏寫圖片描述

可見insert的sql語句起了作用。
上述代碼中:

Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/tmall?characterEncoding=UTF-8", "root", "admin");

用以連接tmall數據庫

Statement s = c.createStatement();
String sql = "insert into Category values(85," +"'ruff開發板')";
s.execute(sql);

用以執行SQL語句,向Category表中插入數據。

4.執行select語句,查詢表中數據
這裏寫圖片描述

其中
while(mResultSet.next()){
System.out.println("Category表中id > 80的產品名稱爲:" + mResultSet.getString(2));
}

取出結果集中,所有的第二列數據。其中ResultSet.next()方法的解釋爲:

Moves the cursor forward one row from its current position. A ResultSet cursor is initially positioned before the first row; the first call to the method next makes the first row the current row; the second call makes the second row the current row, and so on.

到此我們就基本上實現了JDBC的基本功能,可以開始業務開發了。

5.使用PreparedStatement實現數據庫的操作。

    public static void main(String args[]){
        //new CategoryDao().executePreparedStatement();
        //new CategoryDao().executeStatement("空調 or 1= 1");
        //new CategoryDao().executePreparedStatement("空調 or 1= 1");
        new CategoryDao().executePreparedStatement("空調");
    }


    private void executePreparedStatement(String userInput){
        String sql = "select * from Category where name = ?";
        try{
            Connection c = getConnection();
            PreparedStatement ps = c.prepareStatement(sql);
            ps.setString(1, userInput);
            ps.execute();
            ResultSet rs = ps.getResultSet();
            while(rs.next()){
                System.out.printf("%d,%s",rs.getInt(1),rs.getString(2));
            }
        }catch(SQLException ex){
            ex.printStackTrace();
        }

    }

上面的函數執行了從Category數據庫中查找id=80的項目並將name打印出來的功能,執行結果如下:

這裏寫圖片描述
Console界面將name=空調 的條目打印出來了。

5.使用PreparedStatement與使用Statement的對比。
上述示例代碼中的PreparedStatement.setString(1, userInput);是值往sql第一個參數傳值,然而Statement中sql是通過字符串拼接得到的。下面的代碼對比表示了其區別:

    public static void main(String args[]){
        //new CategoryDao().executePreparedStatement();
        new CategoryDao().executeStatement("75");
        //new CategoryDao().executePreparedStatement("空調 or 1= 1");
        //new CategoryDao().executePreparedStatement(75);
    }

        private void executeStatement(String userInput){
        String sql = "select * from Category where id = "   + userInput ;
        try{
            Connection c = getConnection();
            //PreparedStatement ps = c.prepareStatement(sql);
            //ps.setInt(1, 80);
            //ps.execute();
            Statement s = c.createStatement();
            s.execute(sql);
            ResultSet rs = s.getResultSet();
            while(rs.next()){
                System.out.printf("%d,%s",rs.getInt(1),rs.getString(2));
            }
        }catch(SQLException ex){
            ex.printStackTrace();
        }

    }

得到的結果爲:
這裏寫圖片描述

由此可見Statement的sql語句是採用字符串拼接得到的。
因此PreparedStatement可以在兩方面比Statement好:

(1)書寫很麻煩 。尤其是當sql字段涉及到char, varchar類型的數據時,轉義字符(\”)寫的人腦袋都要繞暈了。

(2)很重要的一點,PreparedStatement可以防止sql注入。

    public static void main(String args[]){
        //new CategoryDao().executePreparedStatement();
        new CategoryDao().executeStatement("75 or 1 = 1");
        //new CategoryDao().executePreparedStatement("空調 or 1= 1");
        //new CategoryDao().executePreparedStatement(75);
    }

        private void executeStatement(String userInput){
        String sql = "select * from Category where id = "   + userInput ;
        try{
            Connection c = getConnection();
            //PreparedStatement ps = c.prepareStatement(sql);
            //ps.setInt(1, 80);
            //ps.execute();
            Statement s = c.createStatement();
            s.execute(sql);
            ResultSet rs = s.getResultSet();
            while(rs.next()){
                System.out.printf("%d,%s",rs.getInt(1),rs.getString(2));
            }
        }catch(SQLException ex){
            ex.printStackTrace();
        }

    }

注意這行:

new CategoryDao().executeStatement("75 or 1 = 1");

執行結果爲:
這裏寫圖片描述

結果得知,打印出了Category表中所有的信息,這就是sql注入導致的信息泄露了。而在PreparedStatement中就不會產生這個結果,因爲 “75 or 1 = 1”這個參數在Category表中是查不出來東西的。

(3)還有一點重要的區別是執行效率的區別

使用 PreparedStatement 最重要的一點好處是它擁有更佳的性能優勢,SQL語句會預編譯在數據庫系統中。執行計劃同樣會被緩存起來,它允許數據庫做參數化查詢。使用預處理語句比普通的查詢更快,因爲它做的工作更少(數據庫對SQL語句的分析,編譯,優化已經在第一次查詢前完成了)。爲了減少數據庫的負載,生產環境中德JDBC代碼你應該總是使用PreparedStatement 。值得注意的一點是:爲了獲得性能上的優勢,應該使用參數化sql查詢而不是字符串追加的方式。

發佈了49 篇原創文章 · 獲贊 32 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章