JavaWeb - JDBC、各個類詳解、工具類、解決sql注入


1.JDBC 概念  

  概念:Java DataBase Connectivity  Java數據庫連接,Java語言操作數據庫

  本質:其實是官方(sun)定義的一套操作所有關系型數據庫的規則,既接口。各個數據庫廠商去實現這套這套接口,提供數據庫驅動jar包。

       我們可以使用這套接口(JDBC)編程,真正執行的代碼是驅動jar包中的實現類。

 

2.快速入門

  (1)導入驅動jar包  mysql-connector-java-5.1.37-bin.jar

    1.復制mysql-connector-java-5.1.37-bin.jar到項目的libs目錄下 

    2.右鍵項目  add as library

  (2)注冊驅動

  (3)獲取數據庫連接對象 Connection

  (4)定義sql

  (5)獲取執行sql語句的對象 Statement

  (6)執行sql,接收返回的結果

  (7)處理結果

  (8)釋放資源

public class JdbcDemo1  {
    public static void main(String[] args) throws Exception {
        //1.導入驅動jar包
        //2.注冊驅動
        Class.forName("com.mysql.jdbc.Driver");

        //3.獲取數據庫連接對象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "woaini1314");

        //4.定義sql語句
        String sql = "update emp set salary = 9999 where id = 1";

        //5.獲取執行sql的對象 Statement
        Statement statement = conn.createStatement();

        //6.執行sql
        int count = statement.executeUpdate(sql);

        //7.處理結果
        System.out.println(count);

        //8.釋放資源
        statement.close();
        conn.close();
    }
}

 

3.JDBC各個類詳解

  (1)DriverManager:驅動管理對象

    *功能:

      1.注冊驅動:告訴程序該使用哪一個數據庫驅動jar包

        static void registerDriver(Driver  driver):注冊與給定的驅動程序 DriverManager

        寫代碼使用:Class.forName("com.mysql.jdbc.Driver");  - - > 來自導入的jar包  

        通過查看源碼發現:在com.mysql.jdbc.Driver類中存在靜態代碼塊

        注意:mysql之后的驅動jar包可以省略注冊驅動的步驟

      2.獲取數據庫連接

        *方法:static connection DriverManager.getConnection(String url,String user,String password)

        *參數:

          *url:指定連接的路徑

            *語法:jdbc:mysql:// IP地址(域名):端口號/數據庫名稱  如:jdbc:mysql://localhost:3306/db1

            *細節:如果ip地址是本地並且端口號為3306 則可以省略不寫 jdbc:mysql:///db1

          *user:用戶名

          *password:密碼

 

  (2)Connection:數據庫連接對象

    *功能:

      1.獲取執行sql的對象

        *statement createStatament()

        *Preparedstatement preparedStatament(String sql)

      2.管理事務:

        *開啟事務:  setAutoCommit(boolean autoCommit) : 調用該方法設置參數為false,既開啟事務 手動提交

        *提交事務:commit()

        *回滾事務:rollback()

  (3)Statement:執行Sql的對象

    1.執行sql

      1.boolean execute(String sql):可以執行任意的sql 了解

      2.int executeUpdate(String sql):執行的是DML(insert、update、delete)語句、DDL(create、alter、drop)語句

        *返回值:影響的行數,可以通過返回值的行數判斷DML語句是否執行成功 返回值 > 0 則執行成功 反之則失敗

      3.ResultSet executeQuery(String sql):執行DQL(select)語句

  (4)ResultSet:結果集對象,就是來封裝查詢結果的

      *boolean next():游標向下移動一行,判斷當前行是否是最后一行末尾(是否有數據),如果是則返回false

      *getXxx(參數):獲取數據

        Xxx:代表數據類型  如:int getInt() String getString()

        參數:int - - > 代表列的編號,從1開始   String - - > 代表列名稱

基本查詢:

    注意:

        正確使用步驟:

          1.游標向下移動一行

          2.判斷是否有數據

          3.獲取數據

public class JdbcDemo2 {
    public static void main(String[] args) {
        //練習:往數據庫db3表中添加、修改、刪除

        Statement stmt = null; //提升作用域 因為finally中要執行釋放資源
        Connection conn = null;
        ResultSet rs = null;
        try {
            //1.注冊驅動
            Class.forName("com.mysql.jdbc.Driver");
            //2.定義sql
            String sql = "SELECT * from stu3";

            //3.獲取connection對象
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "woaini1314");

            //4.獲取執行sql的對象 statement
            stmt = conn.createStatement();

            //5.執行sql
            rs = stmt.executeQuery(sql);

            //6.處理結果
                //讓光標向下移動一行
            //循環判斷
            while (rs.next()){
                String name = rs.getString("name");
                int id = rs.getInt(1);
                System.out.println(id + "---" + name);
            };


        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //7.釋放資源
            //stmt.close();
            //若用戶輸入密碼錯誤,要避免空指針異常
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            if(stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
循環讀取

 

  (5)PrepareStatement:執行Sql的對象

 

練習:JDBC增刪改

public class JdbcDemo2 {
    public static void main(String[] args) {
        //練習:往數據庫db3表中添加、修改、刪除

        Statement stmt = null; //提升作用域 因為finally中要執行釋放資源
        Connection conn = null;
        try {
            //1.注冊驅動
            Class.forName("com.mysql.jdbc.Driver");
            //2.定義sql
            String sql = "insert into stu3  values(null,'joe')";

            //3.獲取connection對象
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "woaini1314");

            //4.獲取執行sql的對象 statement
            stmt = conn.createStatement();

            //5.執行sql
            int count = stmt.executeUpdate(sql); //影響行數

            //6.處理結果
            System.out.println(count);
            if(count > 0){
                System.out.println("添加成功");
            }else {
                System.out.println("添加失敗");
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //7.釋放資源
            //stmt.close();
            //若用戶輸入密碼錯誤,要避免空指針異常
            if(stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
插入新數據

 

public class JdbcDemo2 {
    public static void main(String[] args) {
        //練習:往數據庫db3表中添加、修改、刪除

        Statement stmt = null; //提升作用域 因為finally中要執行釋放資源
        Connection conn = null;
        try {
            //1.注冊驅動
            Class.forName("com.mysql.jdbc.Driver");
            //2.定義sql
            String sql = "UPDATE stu3 set name = 'Lindsey' where id = 2";

            //3.獲取connection對象
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "woaini1314");

            //4.獲取執行sql的對象 statement
            stmt = conn.createStatement();

            //5.執行sql
            int count = stmt.executeUpdate(sql); //影響行數

            //6.處理結果
            System.out.println(count);
            if(count > 0){
                System.out.println("修改成功");
            }else {
                System.out.println("修改失敗");
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //7.釋放資源
            //stmt.close();
            //若用戶輸入密碼錯誤,要避免空指針異常
            if(stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
修改數據

 

練習:定義一個方法,查詢emp表的數據,將其封裝為對象,然后裝載集合,返回

public class JdbcPractise {
    public static void main(String[] args) {
        List<Emp> list = new JdbcPractise().findAll();
        for (Emp emp : list) {
            System.out.println(emp);
        }
    }

    /**
     * 查詢所有emp對象
     * @return
     */
    public List<Emp> findAll(){

        //提升變量,以防報錯或空指針異常
        ResultSet rs = null;
        Connection conn = null;
        Statement stmt = null;
        List<Emp> list = null;

        try {
            Class.forName("com.mysql.jdbc.Driver");
            //獲取連接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/pratise", "root", "woaini1314");

            stmt = conn.createStatement();

            //定義sql
            String sql = "select * from emp";
            rs = stmt.executeQuery(sql);

            //遍歷結果集 封裝對象,封裝集合
            Emp emp = null; //進行復用 防止反復進棧
            list = new ArrayList<Emp>();
            while (rs.next()){
                int id = rs.getInt("id");
                String ename = rs.getString("ename");
                int job_id = rs.getInt("job_id");
                int mgr = rs.getInt("mgr");
                Date joindate = rs.getDate("joindate");
                double salary = rs.getDouble("salary");
                double bonus = rs.getDouble("bonus");
                int dept_id = rs.getInt("dept_id");

                //創建emp對象,並賦值
                emp = new Emp();
                emp.setId(id);
                emp.setEname(ename);
                emp.setJob_id(job_id);
                emp.setMgr(mgr);
                emp.setJoindate(joindate);
                emp.setSalary(salary);
                emp.setDept_id(dept_id);
                emp.setBonus(bonus);

                //裝載集合
                list.add(emp);
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return list;
    }
}
從數據庫獲取數據並封裝

 

4.JDBC工具類

  目的:簡化書寫

  *分析:

    1.注冊驅動也抽取

    2.抽取一個方法獲取連接對象

      *需求:不想傳遞參數(麻煩),還得保證工具類的通用性

      *解決方案:配置文件

        jdbc.properties

          url = 

          user = 

          password =

    3.抽取一個方法釋放資源

import javax.swing.plaf.nimbus.State;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;


/**
     * JDBC工具類
     */
public class JDBCUtils {
    //只有靜態的變量才能被靜態方法和靜態代碼塊所訪問和使用
    private static String url;
    private static String user;
    private static String password;
    private static String driver;
    /**
     * 文件的讀取,只需要讀取一次就可以拿到這些值。使用靜態代碼塊
     */
    static {
        //讀取資源文件,獲取值
        try {
            //1.創建Properties 集合類
            Properties pro = new Properties();

            //獲取src文件下路徑的方式---> ClassLoader 類加載器
            ClassLoader classLoader = JDBCUtils.class.getClassLoader();
            URL resource = classLoader.getResource("jdbc.properties");
            String path = resource.getPath();
            System.out.println(path); //得到資源文件的絕對路徑

            //2.加載文件
            //pro.load(new FileReader("src/jdbc.properties"));
            pro.load(new FileReader(path));

            //3.獲取屬性,並賦值
            url = pro.getProperty("url");
            user = pro.getProperty("user");
            password=pro.getProperty("password");
            driver = pro.getProperty("driver");

            //注冊驅動
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 獲取連接的方法
     * @return  返回連接對象
     */
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,user,password);
    }

    /**
     * 釋放資源
     * @param stmt
     * @param conn
     */
    public static void close(Statement stmt,Connection conn){
        if(stmt!=null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        }
    }
    //釋放資源重載方法
    public static void close(ResultSet rs,Statement stmt, Connection conn){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(stmt!=null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
當配置文件在src文件下時的工具類

 

import javax.swing.plaf.nimbus.State;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;


/**
     * JDBC工具類
     */
public class JDBCUtils {
    //只有靜態的變量才能被靜態方法和靜態代碼塊所訪問和使用
    private static String url;
    private static String user;
    private static String password;
    private static String driver;
    /**
     * 文件的讀取,只需要讀取一次就可以拿到這些值。使用靜態代碼塊
     */
    static {
        //讀取資源文件,獲取值
        try {
            //1.創建Properties 集合類
            Properties pro = new Properties();

            //獲取src文件下路徑的方式---> ClassLoader 類加載器
           /* ClassLoader classLoader = JDBCUtils.class.getClassLoader();
            URL resource = classLoader.getResource("jdbc.properties");
            String path = resource.getPath();
            System.out.println(path); //得到資源文件的絕對路徑*/

            //2.加載文件
            //pro.load(new FileReader("src/jdbc.properties"));
            pro.load(new FileReader("D:\\DB\\jdbc_basic\\src\\cn\\itcast\\jdbc\\jdbc.properties"));

            //3.獲取屬性,並賦值
            url = pro.getProperty("url");
            user = pro.getProperty("user");
            password=pro.getProperty("password");
            driver = pro.getProperty("driver");

            //注冊驅動
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 獲取連接的方法
     * @return  返回連接對象
     */
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,user,password);
    }

    /**
     * 釋放資源
     * @param stmt
     * @param conn
     */
    public static void close(Statement stmt,Connection conn){
        if(stmt!=null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        }
    }
    //釋放資源重載方法
    public static void close(ResultSet rs,Statement stmt, Connection conn){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(stmt!=null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
第二種獲取地址方式

 

練習:

  需求:

    1.通過鍵盤錄入用戶名和密碼

    2.判斷用戶是否登錄成功

      select * from user where username = " " and password = " ";

      *如果這個sql有查詢結果,則登錄成功

  步驟:

    1.創建數據庫表user

CREATE TABLE USER(
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(32),
    PASSWORD VARCHAR(32)
);

SELECT * FROM USER;

INSERT INTO USER  VALUES(NULL,'zhangsan','123');
INSERT INTO USER  VALUES(NULL,'lisi','456');

 

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;

public class JdbcLogin {
    public static void main(String[] args) {
        //1.鍵盤錄入,接收用戶名和密碼
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入用戶名");
        String username = sc.nextLine();
        System.out.println("請輸入密碼");
        String password = sc.nextLine();

        //2.調用方法
        boolean flag = new JdbcLogin().login(username, password);
        //3.判斷結果
        if(flag){
            //登錄成功
            System.out.println("登錄成功");
        }else {
            System.out.println("賬號或密碼錯誤");
        }
    }

    /**
     * 登錄方法
     */
    public boolean login(String username, String password){
        if(username==null && password==null){
            return false;
        }
        //連接數據庫判斷是否登錄成功
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        //獲取數據庫連接
        try {
            conn = JDBCUtils.getConnection();
            //2.定義sql
            String sql = "select * from user where username = '"+username+"' and password = '"+password+"'";

            //3.獲取執行sql的對象
            stmt = conn.createStatement();

            //4.執行查詢
            rs = stmt.executeQuery(sql);

            //5.判斷
            return rs.next();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(rs,stmt,conn);
        }

        return false; //如果執行到這,說明出現了異常,返回false就好了
    }

}
練習答案

 

5.PreparedStatement解決sql注入問題

  1.Sql注入問題 : 在拼接sql時,有一些sql的特殊關鍵字參與字符串的拼接。會造成安全性問題

    1.隨便輸入用戶名,輸入密碼:a' or 'a' = 'a

    2.sql:select * from user where username = 'asgasg' and password = a' or 'a' = 'a

   2.解決sql注入問題:使用PrepareStatement對象來解決

  3.預編譯SQL:參數使用 ? 作為占位符

  4.步驟: 

  (1)導入驅動jar包  mysql-connector-java-5.1.37-bin.jar

  (2)注冊驅動

  (3)獲取數據庫連接對象 Connection

  (4)定義sql

      *注意:sql的參數使用 ? 作為占位符 如:select * from user where username = ? and password = ?

  (5)獲取執行sql語句的對象 PreparedStatement  Connection.PreparedStatement(String sql)

  (6)給?賦值

    *方法:setXxx(參數1,參數2)  參數1 是 ? 的位置編號,從1開始,參數2是問號的值

  (7)執行sql,接收返回的結果,不需要傳遞sql語句

  (8)處理結果

  (9)釋放資源

  5.注意:后期都會只有PreparedStatemet來完成增刪改查的所有操作  因為可以防止sql注入 而且效率更高

/**
     * 登錄方法
     */
    public boolean login(String username, String password){
        if(username==null && password==null){
            return false;
        }
        //連接數據庫判斷是否登錄成功
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        //獲取數據庫連接
        try {
            conn = JDBCUtils.getConnection();
            //2.定義sql
            String sql = "select * from user where username = ? and password = ?";

            //3.獲取執行sql的對象
            pstmt = conn.prepareStatement(sql);

            //給?賦值
            pstmt.setString(1,username);
            pstmt.setString(2,password);

            //4.執行查詢
            rs = pstmt.executeQuery();

            //5.判斷
            return rs.next();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(rs,pstmt,conn);
        }

        return false; //如果執行到這,說明出現了異常,返回false就好了
    }
方法升級

 

JDBC管理事務

  管理事務:

     *開啟事務:  setAutoCommit(boolean autoCommit) : 調用該方法設置參數為false,既開啟事務 手動提交

        *在執行sql之前開啟事務

     *提交事務:commit()

        *當所有sql都執行完提交事務

     *回滾事務:rollback()

        *在catch異常中回滾事務

 

public class JdbcOperateAffair {
    /**
     * JDBC管理事務
     */
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        PreparedStatement pstmt2 = null;
        try {
            conn = JDBCUtils.getConnection();
            //開啟事務
            conn.setAutoCommit(false);

            //2.定義sql
                //張三減500 李四+500
            String sql = "update account set balance = balance - ? where id = ?";
            String sql2 = "update account set balance = balance + ? where id = ?";

            //3.獲取執行sql的對象
            pstmt = conn.prepareStatement(sql);
            pstmt2 = conn.prepareStatement(sql2);

            //4.設置參數
            pstmt.setDouble(1,500);
            pstmt.setInt(2,1);
            pstmt2.setDouble(1,500);
            pstmt2.setInt(2,2);

            //5.執行sql
            pstmt.executeUpdate();
            pstmt2.executeUpdate();

            //提交事務
            conn.commit();
        } catch (Exception e) {
            //出異常了則進行事務的異常
            try {
                if(conn!=null){
                conn.rollback();}
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            JDBCUtils.close(pstmt,conn);
            JDBCUtils.close(pstmt2,null);
        }

    }
}
管理事務

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM