JDBC基本使用

    1. 簡介 JDBC(Java Data Base Connectivity) 是 Java 訪問數(shù)據(jù)庫的標(biāo)準(zhǔn)規(guī)范.,為 多種關(guān)系數(shù)據(jù)庫提供統(tǒng)一訪問。它由一組用Java語言編寫的類和接口組成。 JDBC只是Java提供的一些接口,而這些接口

    1. 簡介

    JDBC(Java Data Base Connectivity) 是 Java 訪問數(shù)據(jù)庫的標(biāo)準(zhǔn)規(guī)范.,為 多種關(guān)系數(shù)據(jù)庫提供統(tǒng)一訪問。它由一組用Java語言編寫的類和接口組成。

    JDBC只是Java提供的一些接口,而這些接口的實現(xiàn)類是由各個數(shù)據(jù)庫廠商提供的,稱之為數(shù)據(jù)庫連接驅(qū)動。這樣一來,我們就可以面向接口編程,以一種統(tǒng)一的方式訪問多種數(shù)據(jù)庫。

    2. JDBC使用流程

    1. 下載對應(yīng)版本的數(shù)據(jù)庫連接驅(qū)動,并導(dǎo)入項目。
    2. 注冊驅(qū)動
      通過 Class.froName("Driver實現(xiàn)類路徑"); 加載Driver驅(qū)動并注冊到DriverManager中。
      對于MySQL而言,不同版本的 "Driver實現(xiàn)類路徑" 也是不同的:
      5.x版本為:com.mysql.jdbc.Driver
      8.x版本為:com.mysql.cj.jdbc.Driver
      原理為: Driver類在靜態(tài)代碼塊中創(chuàng)建Driver對象,并注冊到DriverManager中。

    **注意:**在JDK1.6中DriverManager明確指出,在JDBC4.0及之后版本中可以不用forName顯示加載驅(qū)動。這是因為在獲取連接時,可以根據(jù)url判斷并自動加載對應(yīng)的驅(qū)動。但是一般開發(fā)中還是 要寫forName,因為有些場合并不會自動加載,如Tomcat中,由于類加載器不同,省略forName就會找不到類。

    1. 創(chuàng)建連接
      通過 DriverManager的getConnection方法獲取連接
    Connection getConnection(url,userName,password);
    • url:jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&serverTimezone=UTC
      jdbc:mysql是 協(xié)議 名,固定寫法
      localhost:3306為服務(wù)器地址 及 端口號
      test是要連接的數(shù)據(jù)庫名
      characterEncoding=UTF-8的作用為,告訴mysql,將數(shù)據(jù)轉(zhuǎn)化為 utf-8 格式之后再傳給我的程序。
      serverTimezone=UTC有時候不指定時區(qū)會報錯。
    • userName 登錄MySQL的用戶名
    • password 密碼
    1. 執(zhí)行SQL語句
      通過connection對象的createStatement()方法獲取Statement對象,然后通過Statement對象的executeUpdate()executeQuery()方法執(zhí)行SQL語句:
      executeUpdate():方法用于執(zhí)行insert update delete語句,返回受影響的行數(shù)。
      executeQuery():執(zhí)行select語句, 返回ResultSet結(jié)果集對象。
    2. 處理結(jié)果集
      ResultSet的作用為 封裝查詢結(jié)果,然后通過其next方法和getXxx方法遍歷結(jié)果集。

    方法

    說明

    boolean next()

    1) 游標(biāo)向下一行

    2) 返回 boolean 類型,如果還有下一條記錄,返回 true,否則返回 false

    xxx getXxx( String or int)

    1) 通過列名,參數(shù)是 String 類型。返回不同的類型

    2) 通過列號,參數(shù)是整數(shù),從 1 開始。返回不同的類型

    1. 釋放資源
      釋放原則為:先開的后關(guān),一次關(guān)閉 ResultSet對象,Statement對象,Connection對象
    2. 示例
    @Test
        public void test(){
            String url = "jdbc:mysql://192.168.65.131:3306/test?characterEncoding=UTF-8&serverTimezone=UTC";
            String userName = "mochen";
            String password = "123456";
            Connection conn = null;
            Statement stmt = null;
            ResultSet rs = null;  // 查詢數(shù)據(jù)
    
            try {
                // 加載Driver類,并注冊到DriverManager
                Class.forName("com.mysql.cj.jdbc.Driver");
                // 獲取連接
                conn = DriverManager.getConnection(url, userName, password);
                // 獲取Statement對象
                stmt = conn.createStatement();
                // 執(zhí)行SQL語句
                stmt.executeUpdate("insert into jdbc_user values(null,'王蛋','abcd','2014-05-12 13:21:00')");  // 插入數(shù)據(jù)
                rs = stmt.executeQuery("select * from jdbc_user");
                // 處理結(jié)果集
                while(rs.next()){
                    System.out.println(rs.getString(1)+"\t\t"+rs.getString(2)
                                       +"\t\t"+rs.getString(3)+"\t\t"
                                       +rs.getString(4));
                }
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            } finally { // 釋放資源
                if(null!=rs){
                    try {
                        rs.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if(null!=stmt){
                    try {
                        stmt.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if(null!=conn){
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    3. SQL注入 與 PreparedStatement

    3.1 SQL注入

    什么是SQL注入:

    當(dāng)要執(zhí)行的SQL語句 是由用戶輸入的參數(shù) 拼接而來時,如果用戶可以輸入一些有特殊意義的內(nèi)容,就可以改變原有的SQL的意義,從而進行非法操作。這種情況就稱為SQL注入。

    舉例:

    如 驗證用戶登錄的SQL語句:

    String sql = "select * from jdbc_user " +
    "where username = " + " '" + name +"' " +" and password = " +" '" + pass +"'";

    如果用戶輸入的密碼為:' or '1'=1因為1=1肯定是真,or 又是有真即真,所以where條件的結(jié)果總為true。這就改變了SQL原有的含義。

    真正的SQL注入可能要復(fù)雜的多,但原理應(yīng)該都是

    3.2 PreparedStatement

    1. 簡介

    PreparedStatement 是 Statement 接口的子接口,繼承于父接口中所有的方法。它是一個預(yù)編譯的 SQL 語 句對象。預(yù)編譯:是指SQL 語句被預(yù)編譯,并存儲在 PreparedStatement 對象中。然后可以使用此對象多次高效地執(zhí)行該語句。

    2. 使用

    // 獲取 PreparedStatement
    conn.prepareStatement(String sql);  // Sql中可以使用 ? 作為參數(shù)的占位符,然后使用setXxx方法賦值
    
    // 常用方法
    int executeUpdate();
    ResultSet executeQuery(); // 注意:這里不必填入SQL

    JDBC基本使用_bc

    3. 示例

    PreparedStatement ps = conn.prepareStatement("select * from employee where id=? and name=?");
    ps.setInt(1,1);
    ps.setString(2,"孫悟空");
    rs = ps.executeQuery();
    while (rs.next()){
        for(int i=0;i<6;i++){
            System.out.print(rs.getObject(i+1)+"\t");
        }
    }

    4. JDBC工具類

    如何編寫:

    1. 用常量記錄 DRIVERNAME、URL 、USER 、PASSWORD ,也可以用配置文件
    2. 靜態(tài)代碼塊中注冊驅(qū)動(或者是創(chuàng)建數(shù)據(jù)源)
    3. 提供靜態(tài)方法 獲取連接、 關(guān)閉對象。
      其他的方法(像直接執(zhí)行SQL的方法)就不要提供了,因為如果這樣調(diào)用者中就沒有Connection和Statement的引用,而這兩者又只能在處理結(jié)果后才能關(guān)閉,這就不是靜態(tài)方法能夠?qū)崿F(xiàn)的功能了。
    4. 工具類類一般都是提供靜態(tài)方法,不能創(chuàng)建對象。
      我認(rèn)為所謂工具就是要足夠簡單,獨立,與主程序邏輯沒什么關(guān)系。拿來即用,用完就不需要有什么后續(xù)操作。所以要用靜態(tài)方法。為了保證它的絕對簡單,最好提供private 構(gòu)造方法,明確禁止創(chuàng)建對象。

    示例:

    /**
     * JDBC 工具類
     */
    public class JDBCUtils {
        //1. 定義字符串常量, 記錄獲取連接所需要的信息
        public static final String DRIVERNAME = "com.mysql.jdbc.Driver";
        public static final String URL = "jdbc:mysql://localhost:3306/db4?characterEncoding=UTF-8";
        public static final String USER = "root";
        public static final String PASSWORD = "123456";
        //2. 靜態(tài)代碼塊, 隨著類的加載而加載
        static{
            try {
                //注冊驅(qū)動
                Class.forName(DRIVERNAME);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        //3.獲取連接的靜態(tài)方法
        public static Connection getConnection(){
            try {
                //獲取連接對象
                Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
                //返回連接對象
                return connection;
            } catch (SQLException e) {
                e.printStackTrace();
                return null;
            }
        }
        //關(guān)閉資源的方法
        public static void close(Connection con, Statement st){
            if(con != null && st != null){
                try {
                    st.close();
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        public static void close(Connection con, Statement st, ResultSet rs){
            if(rs != null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            close(con,st);
        }
    }

    5. 事務(wù)控制

    mysql的自動事務(wù)為每一條DML語句都開啟一個事務(wù)。JDBC可以通過關(guān)閉自動提交來打開事務(wù)。

    相關(guān)方法:

    void setAutoCommit(boolean autoCommit);  // 設(shè)置為 false 關(guān)閉事務(wù)的自動提交
    void commit();		// 事務(wù)提交
    void rollback();    // 事務(wù)回滾

    示例:

    //1. 獲取連接
    con = JDBCUtils.getConnection();
    //2. 開啟事務(wù)
    con.setAutoCommit(false);
    //3. 獲取到 PreparedStatement 執(zhí)行兩次更新操作
    //3.1 tom 賬戶 -500
    ps = con.prepareStatement("update account set money = money - ? where name = ? ");
    ps.setDouble(1,500.0);
    ps.setString(2,"tom");
    ps.executeUpdate();
    //模擬tom轉(zhuǎn)賬后 出現(xiàn)異常
    System.out.println(1 / 0);
    //3.2 jack 賬戶 +500
    ps = con.prepareStatement("update account set money = money + ? where name = ? ");
    ps.setDouble(1,500.0);
    ps.setString(2,"jack");
    ps.executeUpdate();
    //4. 正常情況下提交事務(wù)
    con.commit();
    System.out.println("轉(zhuǎn)賬成功!");

    6. 批處理

    6.1 簡介

    批處理指的是一次操作中執(zhí)行多條SQL語句,批處理相比于一次一次執(zhí)行效率會提高很多。主要用途就是批量操作,如一鍵生成一千個用戶,從提交的文件中提取并導(dǎo)入大批量的數(shù)據(jù) 等。

    6.2 實現(xiàn)

    Statement和PreparedStatement都支持批處理操作。

    相關(guān)方法:

    void addBatch();  // 將給定的 SQL 命令添加到此 Statement 對象的當(dāng)前命令列表中。
    int[] executeBatch();  // 提交一批命令到數(shù)據(jù)庫中執(zhí)行,返回的數(shù)組是每條命令所影響的行數(shù)

    示例:

    @Test  // Statement 批處理 測試
    public void test135() throws Exception{
        Connection conn = DruidUtils.getConnection();
        Statement stmt = conn.createStatement();
        for(int i=0;i<10;i++) {
            stmt.addBatch("insert into appdate values(123,'豬悟能')");
        }
        int[] ints = stmt.executeBatch();
        System.out.println(Arrays.toString(ints));
    }
    
    @Test  // PreparedStatement 批處理 測試
    public void test150() throws Exception{
        Connection conn = DruidUtils.getConnection();
        PreparedStatement ps = conn.prepareStatement("insert into appdate values(?,?)");
        for(int i=0;i<10;i++) {
            ps.setInt(1, 123);
            ps.setString(2,"豬悟能");
            ps.addBatch();
        }
        int[] ints = ps.executeBatch();
        System.out.println(Arrays.toString(ints));
    }

    **注意:**批處理中不能進行查詢

    JDBC基本使用_System_02

    7. 獲取元數(shù)據(jù)

    相關(guān)類:DatabaseMetaData、ResultSetMetaData

    使用方法:

    DatabaseMetaData:

    @Test // DatabaseMetaData 測試
    public void test165() throws Exception{
        Connection conn = DruidUtils.getConnection();
        // 通過 Connection 獲取 DatabaseMetaData 對象
        DatabaseMetaData dmd = conn.getMetaData();
    
        // 通過 DatabaseMetaData 對象(dmd) 獲取 元數(shù)據(jù)
        System.out.println(dmd.getDriverName());   // 驅(qū)動器名,如:MySQL Connector/J
        System.out.println(dmd.getURL());          // 就是連接是傳入的URL 
        System.out.println(dmd.getUserName());     // 登錄的用戶名,如:root@localhost
        System.out.println(dmd.isReadOnly());      // 是否 只讀 
    
        System.out.println(dmd.getDatabaseProductName());     // 獲取數(shù)據(jù)庫軟件的名字,如:MySQL
        System.out.println(dmd.getDatabaseProductVersion());  // 獲取數(shù)據(jù)庫軟件的版本,如:8.0.21
    }

    ResultSetMetaData

    @Test // ResultSetMetaData 測試
    public void test178() throws Exception{
        Connection conn = DruidUtils.getConnection();
        PreparedStatement ps = conn.prepareStatement("select * from employee");
        ps.executeQuery();
        // 同過 PreparedStatement 獲取 ResultSetMetaData 對象,注意 Statemet 不行。
        ResultSetMetaData rsmd = ps.getMetaData();
        // 通過 ResultsetMetaData 對象獲取元數(shù)據(jù)
        System.out.println(rsmd.getColumnCount());  // 獲取結(jié)果集的 列數(shù)
        System.out.println(rsmd.getColumnName(2)); // 獲取結(jié)果集 某一列的列名
        System.out.println(rsmd.getColumnTypeName(2)); // 返回對應(yīng)列的 數(shù)據(jù)類型(MySQL類型)名字,如:VARCHAR
        System.out.println(rsmd.getColumnClassName(2)); // 返回對應(yīng)列的 數(shù)據(jù)類型對應(yīng)的java類路徑,如:java.lang.String
    }

    8. 注意

    1. statement的方法使用說明
    execute()
    executeUpdate() 可以進行:
        數(shù)據(jù)的 增 刪 改、
        表的 增 刪 改
    
    executeQuery() 可以查詢:
        表中 數(shù)據(jù)
        有哪些表 和 數(shù)據(jù)庫 show tables, show databases
        當(dāng)前表名 select database()
        表結(jié)構(gòu) desc 表名 返回 表結(jié)構(gòu)包括:Field、TYPE、NULL、Key、Default、Extra

    暫時只能想到這些操作,其余的用到了在補充吧!

    1. Statement與PreparedStatement的選擇
      當(dāng)一次同一SQL要執(zhí)行很多次時,選擇preparedStatement。
      當(dāng)涉及到查詢參數(shù)時,使用PreparedStatement。
      其余情況:
      即 只是 簡單的 執(zhí)行單獨一條SQL語句,也不用有什么參數(shù)限制時,使用Statement即可。
      姑且這么認(rèn)為吧,對不對的 總得先有個判別依據(jù),要不然太混亂了。
    聲明:所有內(nèi)容來自互聯(lián)網(wǎng)搜索結(jié)果,不保證100%準(zhǔn)確性,僅供參考。如若本站內(nèi)容侵犯了原著者的合法權(quán)益,可聯(lián)系我們進行處理。
    發(fā)表評論
    更多 網(wǎng)友評論0 條評論)
    暫無評論

    返回頂部

    主站蜘蛛池模板: 福利一区福利二区| 日韩精品无码一区二区中文字幕| 国产av一区二区精品久久凹凸| 日本片免费观看一区二区| 一区二区三区日韩| 亚洲乱码日产一区三区| 伦理一区二区三区| 中文字幕无码一区二区三区本日| 日韩欧国产精品一区综合无码| 麻豆高清免费国产一区| 亚洲欧美日韩中文字幕一区二区三区 | 国产精品一区二区久久| 亚洲一区二区三区国产精华液| 国内精自品线一区91| 国产日韩精品一区二区在线观看 | 91成人爽a毛片一区二区| 国产精品日本一区二区不卡视频 | 亚洲国产日韩在线一区| 国产乱码一区二区三区| 在线观看日韩一区| 丰满人妻一区二区三区视频53| 无码人妻久久一区二区三区免费| 亚洲一区二区无码偷拍| 亚洲第一区在线观看| 色一乱一伦一图一区二区精品| 亚洲AV无码一区二区三区久久精品| 精品欧美一区二区在线观看| 三上悠亚日韩精品一区在线 | 国产成人无码aa精品一区| 国产日韩AV免费无码一区二区| 学生妹亚洲一区二区| 亚洲视频在线一区二区| 亚洲第一区二区快射影院| 国产在线精品一区免费香蕉| 国精产品999一区二区三区有限 | 日产亚洲一区二区三区| 精品成人一区二区三区免费视频 | 亚洲av日韩综合一区二区三区| 相泽亚洲一区中文字幕| 无码丰满熟妇浪潮一区二区AV| 亚洲国产精品一区二区第一页|