JDBC面試知識點整理(溫習用)

要面試,因此把以前的筆記整理一遍,嘻嘻,加油java

JDBC編程mysql

使用JDBC,java程序能夠輕鬆地操做各類主流數據庫,Oracle,MySQL,等,使用JDBC編寫的程序不只能夠實現跨數據庫,還具備跨平臺性和可移植性。

JDBC(Java Database Connectiovity,Java數據庫鏈接)是一種執行SQL語句的JavaAPI,程序能夠經過JDBC API鏈接數據庫,並使用SQL結構化查詢語言完成對數據庫的操做,程序員使用JDBC編程時只須要掌握標準的JDBC API 便可,當須要在不一樣的數據庫之間切換時,只須要更換不一樣的數據庫驅動類,是面向接口編程的典例應用。ios

JDBC訪問數據庫時主要完成三個操做:程序員

  • 創建與數據庫的鏈接
  • 執行SQL語句
  • 獲取執行結果

JDBC驅動 數據庫驅動程序是JDBC程序和數據庫之間的轉換層,數據庫驅動程序負責將JDBC調用映射成特定的數據庫調用,有4種類型:JDBC-ODBC橋(最先),本地API驅動,網絡協議驅動,本地協議驅動(建議使用,純java編寫)。面試

JDBC API:提供一組用於與數據庫進行通訊的接口和類,都定義在java.sql包下。sql

Java.sql包經常使用接口和類數據庫

  • DriverManager
    •   用於管理JDBC驅動的服務類,該類的主要功能是加載和卸載各類驅動程序,創建數據庫鏈接並獲取鏈接對象
  • Connection
    •   該接口表明數據庫的鏈接,要訪問數據庫必須先得到數據庫的鏈接
  • Statement
    •   用於執行SQL語句的工具接口,當執行查詢語句時返回一個查詢到的結果集
  • PreparedStatement
    •   該接口用於執行預編譯的SQL語句,這些SQL語句帶有參數,避免數據庫每次都須要編譯SQL語句,執行時傳參
  • CallableStatement
    •   該接口用於調用SQl儲存過程
  • ResultSet
    •   該接口表示結果集,包含訪問查詢的各類方法

使用JDBC API中的類或者接口訪問數據庫時,容易引起SQLException異常,屬於檢查性異常。須要放在try……catch語句裏,對於DriverManager來說,要用到ClassNotFoundException異常。編程

 

DriverManager類:是數據庫驅動管理類,用於管理一組JDBC驅動程序的基本服務,應用程序和數據庫之間能夠經過DriverManager創建鏈接,網絡

DriverManager經常使用靜態方法併發

  • static connection getConnection(String url,String user,String password)
    •   獲取指定的URL的數據庫鏈接,其中url爲提供了一種標識數據庫位置的方法,user用戶名,password密碼
  • static Driver getDriver(String url)
    •   返回可以打開url所指定的數據庫的驅動程序

Connection接口:用於鏈接數據,每一個Connection表明一個數據庫鏈接會話,一個應用程序能夠與單個或者多個數據庫鏈接,經過DriverManager類的getConnection()方法能夠返回同一個Connection對象,該對象提供建立SQL的語法,完成基本SQL操做

Connection的經常使用方法

  • void close()
    •   斷開鏈接,釋放此Connection對象的數據庫和JDBC資源
  • Statement createStatement()
    •   建立一個Statement對象來將SQL語句發送到數據庫
  • void commit()
    •   用於提交SQL語句,確認從上一次提交/回滾以來進行的全部更改
  • boolean isClosed()
    •   用於判斷Connection對象是否已經被關閉
  • CallableStatement prepareCall(String sql)
    •   建立一個CallableStatement對象來調用數據庫儲存過程
  • PrepareStatement(String sql)
    •   建立一個PreparedStatement對象來將參數化的SQL語句發送到數據庫
  • void rollback()
    •   用於取消SQL語句,取消在當前事務中進行的全部更改

Statement接口:通常用於執行SQL語句,在JDBC中要執行SQL查詢語句的方式有

  • 通常查詢(Statement),
  • 參數查詢(PrepareStatement)
  • 儲存查詢(CallableStatement )

三種方式。Statement和PreparedStatement和CallableStatement三個接口具備依次繼承關係。

  • Statement接口的主要功能是將SQL語句傳送給數據庫,並返回SQL語句的執行結果,
  • Statement提交的SQL語句是靜態的,不須要接受任何參數,SQL語句能夠包含三種類型語句:SELECT查詢語句,DML語句,DDL語句。

Statement接口經常使用方法

  • void close()
    •   關閉Statement對象
  • boolean execute(String sql)
    •   執行給定的SQL語句,能夠返回多個結果
  • ResultSet executeQuery(String sql)
    •   執行給定SQL語句,返回單個ResultSet對象
  • int executeUpdate(String sql)
    •   執行給定的SQl語句,能夠爲DML語句或者DDL語句,返回影響行數
  • Connection getConnection()
    •   獲取生成此Statement對象的Connection對象
  • int getFetchSize()
    •   獲取結果集合的行數,該數是根據此Statement對象生成的ResultSet對象的默認獲取大小
  • int  getMaxRows()
    •   獲取由此Statement對象生成的ResultSet對象能夠包含的最大行數
  • ResultSet getResultSet()
    •   獲取由此Statement執行查詢語句返回的的ResultSet對象
  • int getUpdateCount()
    •   獲取此Statement執行DML語句所影響的記錄個數
  • void cioseOnComplection()
    •   當全部依賴Statement對象的ResultSet結果集關閉時,該Statement會自動關閉
  • boolean isCloseOnCompletion()
    •   判斷是否打開closeOnCompletion()
  • long executeLargeUpdate(String sql)
    •   加強版讀完executeUpdate()方法,記錄數超過Integer時使用,爲long

ResultSet接口:用於封裝結果集對象,該對象包含訪問查詢結果的方法,使用Statement中的executeQuery()方法能夠返回一個ResultSet結果集對象(f封裝了全部查詢條件的記錄),ResultSet具備指向當前數據行的遊標,並提供了許多方法來操做結果集中的遊標,提供getXXX()方法對結果集進行訪問。調用next()方法遊標會向下移動,      

ResultSet接口經常使用方法

  • boolean absolute(int row)
    •   將遊標移動到row條記錄
  • boolean relative(int rows)
    •   按相對行數(正或負)移動遊標
  • void beforeFirst()
    •   將遊標移動到結果集的開頭(第一行前)
  • boolean first()
    •   將遊標移動到結果集的第一行
  • boolean previous()
    •   將遊標移動到結果集的上一行
  • boolean next()
    •   將遊標移動到結果集中當前位置的下一行
  • boolean last()
    •   將遊標移動到結果集的最後一行
  • void afterlast()
    •   將遊標移動到結果集的末尾(最後一行後)
  • boolean isAfterLast()
    •   判斷遊標是否位於結果集的末尾(最後一行後)
  • boolean isBeforeFirst()
    •   判斷遊標是否位於結果集的開頭(第一行前)
  • boolean isFirst()
    •   判斷遊標是否位於結果集的第一行
  • boolean isLast()
    •   判斷遊標是否位於結果集的最後一行
  • int getRow()
    •   檢索當前行編號
  • String getString(int x)
    •   返回當前行第X列的列值,類型爲String
  • int getInt(int x)
    •   返回當前行第X列的列值,類型爲int
  • Statement getStatement()
    •   獲取生成結果集的Statement對象
  • void close()
    •   釋放此ResultSet對象的數據庫和JDBC資源
  • ResultSetMetaData getMetaData()
    •   獲取結果集的列的編號,類型,和屬性

數據庫環境搭建

  • 1,建立數據庫表。
  • 2設置Oracle驅動類路徑(Oracledatabase所提供的JDBC驅動程序(jre文件)導入到工程中)。

數據庫訪問:使用JDBC訪問數據庫步驟:

  • 加載數據庫驅動
    •   Class.forName("數據庫驅動類名");
      • mysql:com.mysql.jdbc.Driver;
      • oracle:oracle.jdbc.driver.OracleDriver;
  • 創建數據鏈接
    Connection conn = DriverManager.getConnection(String url,String user,String pass);                        
    mysql:DriverManager.getConnection("jdbc:mysql://localhost:3306/shop", "root","mysql");
    oracle:DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","sys as sysdba","oracle");
  • 建立Statement對象:經過Connection對象獲取Statement的方法;                                                                                             
    •    createStatement()//建立一個基本的Statement對象。
    •   prepareStatement(String sql)//根據參數化的SQL語句建立一個預編譯的PreparedStatement對象。
    •   PrepareCall(String sql)//根據SQL語句建立一個CallableStatement對象,用於調用儲存過程。   
  • 執行SQl語句:
    •   獲取Statement對象後,能夠調用該對象的不一樣方法來執行SQL語句,有三種執行SQl語句的方法
      • executeQuery():只能執行查詢語句,用於產生單個結果集。
      • executeUpdate()和executeLargeUpdate():用於執行DML和DDL語句,返回對應的行數和0;
      • execute():能夠執行任何SQL語句返回值爲布爾型。Statement對象將結果集分裝爲ResultSet對象並返回
  •  訪問結果集:
    •   SQL的查詢結果使用ResultSet封裝,ResultSet結果集中包含了知足SQL查詢條件的全部的行,使用getXXX()方法對結果集進行數據訪問,經過列索引和列名獲取遊標所指的列數據,經過next()和循環控制遊標。
  • 關閉對象
    •   關閉結果集,Statement對象,鏈接對象
  • 操做數據庫:

 

Statement接口

execute()方法能夠執行任何SQL語句,返回值爲布爾型表示是否返回了ResultSet對象,true時使用Statement的getResultSet()方法來獲取execute()方法執行SQL語句返回的ResultSet對象;false時使用getUpdateCount()方法獲取受影響得行數。

executeUpdate()和executeLargeUpdate():用於執行DML和DDL語句,返回對應的行數和0;當DML語句影響的記錄超過Integer.MAX_VALUE時,使用executeLargeUpdate(),類型爲long;

PreparedStatement接口

 PreparedStatement對象包含的SQL語句進行預編譯,須要屢次執行相同的SQL語句時,編譯好的語句比Statement對象快。能夠執行動態的SQL語句,即在SQL 語句中提供參數,動態SQL語句中用?做爲動態參數的佔位符。用setXXX()的方法經過佔位符的索引完成對參數的賦值。

         例:String insterSql = "INSERT INTO LIRUILONG.my_tests VALUES(?,?)";   

         PreparedStatement ps = conn.prepareStatement(insterSql);

         ps.setInt(1,4);

         ps.setString(2, "李瑞龍");      

CallableStatement接口:

JDBC提供CallableStatement接口,用於執行數據庫的儲存過程,該接口能夠處理通常的SQL 語句,也能夠處理以三種帶參數(IN ,OUT,IN OUT)的SQL儲存過程,使用Connection類的prepareCall(String sql)方法能夠建立一個CallableStatement對象,方法的參數能夠是一個調用存儲過程的字符串,cast = conn.prepareCall("{call LIRUILONG.addSub(?,?)");對CallableStatement的SQL語句執行通常用execute().

調用存儲過程的SQL:「{call 存儲過程名[(參數佔位符?)]}」、、有返回值的:「{參數佔位符?=call 存儲過程名[(參數佔位符?)]}」

CallableStatement接口經過setXXX()方法對IN參數進行賦值,

經過registerOutParameter(1, sql.Types.)方法對OUT參數進行類型註冊,第二個參數一般使用java.sql.Types靜態常量指定。

檢索結果的獲取經過getXXX()方法獲取OUT和IN OUT參數的值,

對於IN OUT 參數的值來說須要先使用setXXX()方法對參數進行設置,而後使用registerOutParameter()進行類型註冊,最後使用getXXX()方法來獲取檢索結果

數據庫訪問優化

即編寫一個數據庫訪問工具類DBUtil,用於提供訪問數據庫時所用到的鏈接,查詢等

編寫屬性文件:存放鏈接數據庫的參數信息,在項目的更目錄下建立一個config子目錄。並添加一個屬性文件oracle.properties,該文件以鍵-值對的形式保存鏈接Oracle的配置信息。在讀取配置文件的配置信息時,須要編寫一個Config配置類,在給類中經過java.util.Properrties類的get()方法來獲取指定的「鍵」所對應的值。

編寫DBUtil工具類。將SQL語句與參數包裝傳遞

使用DBUtil工具類。

集元數據

集元數據(Meta Data)是有關數據庫和表結構的信息,JDBC提供了獲取這些信息的DatabaseMetaData和ResultSetMetaData接口。

DatabaseMetaData接口:DatabaseMetaData接口主要用於獲取數據庫相關信息,如數據庫的全部表的列表,系統函數,關鍵字,數據庫產品名以及驅動類型。DatabaseMetaData對象經過getMetaData()方法進行獲取。DatabaseMetaData接口提供大量獲取信息的方法,這些方法可分爲兩大類:

  • 返回值爲boolean型,多用於檢查數據庫或驅動器是否支持某項功能,
  • 獲取數據庫或驅動的參數特徵值。

DatabaseMetaData

  • boolean supportsOuterJolns()
    •   檢查數據庫是否支持外部鏈接
  • boolean supportsStoredProcedures()
    •   檢查數據庫是否支持儲存過程
  • String getURL()
    •   返回用於鏈接數據庫的URL地址
  • String getUserName()
    •   獲取當前的用戶名
  • String getDatabaseProductName()
    •   獲取使用的數據庫產品名
  • String getDatabaseProductVersion()
    •   獲取使用的數據庫版本號
  • String getDriverName()
    •   獲取用於鏈接的驅動類型名稱
  • String getProductVerslon()
    •   獲取用於鏈接的驅動器版本號
  • ResultSet getTypeInfo()
    •   獲取數據庫中可能取得的全部數據類型的描述

ResultSetMetaData接口:用於獲取結果集的結構信息,經過ResultSet的getMetaData()方法來獲取對應的ResultSetMetaData對象

ResultSetMetaData的經常使用方法

  • int getColumnCount()
    •   返回此ResultSst對象中的列數
  • String getColumnName(int column)
    •   獲取指定列的名稱
  • int getColumnType(int cloumn)
    •   檢索指定列的SQL類型
  • String getTableName(int column)
    •   獲取指定列的表名
  • int getColumnDisplaySize(int column)
    •   指示指定列的最大標準寬度,以字符爲單位
  • boolean isAutoIncrement(int column)
    •   指示是否爲自動爲指定列中進行編號,這些列任然爲只讀
  • int isNullable(int column)
    •   指示指定列中的值是否能夠爲null
  • boolean isSearchable(int column)
    •   指示是否能夠在where子句中使用指定的列
  • boolean isReadOnly(int column)
    •   指示指定法人列是否明確不可寫入

事務處理:

事務是保證底層數據完整的重要手段由一步或幾步數據庫操做序列注組成的邏輯執行單元。事務具備ACID四個特性:

  • 原子性(Atomicity):事務是應用中的最小執行單位,具備不可在分的特性,所有完成或不執行。
  • 一致性(Consistency):事務執行先後數據庫都必須是出於一致狀態。
  • 隔離性(Isolation):各個事務互不干擾,及併發事務間互不影響。
  • 持久性(Durability):事務一旦提交,對數據庫的的物理存儲進行改變,不被丟失。

事務處理包括事務提交,終止和回滾,事務提交分顯式提交(commit)和自動提交,事務終止指未能成功完成事務,執行中斷,事務回滾有顯式回滾(rollback)和自動回滾(系統錯誤或強行退出)

JDBC對事務操做由Connection提供:

開啓事務,執行任意多條DML語句,執行成功提交事務,失敗回滾事務,Connection在默認狀況下會自動提交,及事務是關閉的,一條SQL語句執行後,系統調用commit()方法提交數據庫,沒法回滾,使用Connection的setAutoCommit()方法能夠開啓關閉自動提交模式(事務),該方法爲布爾型,參數false爲關閉自動提交,反之打開自動提交。

  • 開啓事務:conn.setAutoCommit(false);
  • 提交事務:conn.commit();
  • 回滾事務:conn.rollback();

當程序遇到未處理的SQLException異常,都會自動回滾,當捕獲該異常時,則須要在處理塊中顯示回滾。

保存點操做:

  • 使用Savepoint類聲明一個保存點對象(Savepoint s1),在須要的位置設置保存點(s1= conn.setSavepoint();)在回滾操做中能夠回滾到保存點位置(conn.rollback(s1));

批量更新:

  • 即多條SQL語句被做爲一批操做同時收集,並同時提交,必須獲得底層數據庫的支持,調用DatabaseLargeBatch()方法查看底層數據庫是否支持批量更新。建立一個Statement對象,使用Statement對象的addBatch()方法收集多條SQL語句,調用Statement的executeBatch()或者executeLargeBatch()方法同時提交全部的SQL語句。

---------------------

 JDBC工具類

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/project
jdbc.user=root
jdbc.password=123456
jdbc.datasource.size=10
package com.lirong.sparkproject.constant;
 
public interface Constants {
    /**
     * 數據庫相關常量
     */
    String JDBC_DRIVER = "jdbc.driver";
    String JDBC_URL = "jdbc.url";
    String JDBC_USER = "jdbc.user";
    String JDBC_PASSWORD = "jdbc.password";
    String JDBC_DATASOURCE_SIZE="jdbc.datasource.size";
}
import java.io.InputStream;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
 
import com.lirong.sparkproject.constant.Constants;
 
public abstract class JDBCHelper {
    //配置對象
    private static Properties prop=new Properties();
    /*
     * jdbc變量
     */
    static String driver=null;
    static String url=null;
    static String user=null;
    static String password=null;
    //thread封裝Connection對象
    static ThreadLocal<Connection> thread=new ThreadLocal<Connection>();
    //惟一空構造器私有化,不容許外部建立對象
    private JDBCHelper() {}
    /**
     *  靜態代碼塊爲jdbc變量賦值
     * 由於靜態代碼塊最早執行,因此調用getConnection()方法時,
     * 該方法內部的jdbc變量就完成了賦值操做
     */
    static {    
        try {
            //動態獲取配置文件的路徑
            InputStream in=JDBCHelper.class.getClassLoader().getResourceAsStream("my.properties");
            prop.load(in);//加載鍵值對信息
            /*
             * Constants常量接口中保存了不少常量,這些常量的值就是配置文件k-v數據的鍵
             * 
             */
            driver=prop.getProperty(Constants.JDBC_DRIVER);
            url=prop.getProperty(Constants.JDBC_URL);
            user=prop.getProperty(Constants.JDBC_USER);
            password=prop.getProperty(Constants.JDBC_PASSWORD);
            /*
             * 加載驅動,靜態代碼塊只執行一次,驅動只加載一次(加載驅動很耗性能的)
             */
            Class.forName(driver);//加載驅動            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 經過本方法客獲取一個MySQL數據庫的Connection對象
     * 
     * @return Connection對象
     */
    public static Connection getConnection() {
        Connection con = thread.get();
        if(con==null) {
            try {
                con = DriverManager.getConnection(url, user, password);
                thread.set(con);
            } catch (SQLException e) {
                e.printStackTrace();
            }        
        }
        return con;//返回jdbc鏈接
    }
    
    /**
     * 本方法中調用Date類型變量的setter方法時使用的是java.sql.Date,
     * 因此實體類在聲明Date類型變量時必定聲明成java.sql.Date
     * 至少Date類型變量對應的setter方法的形參必須是java.sql.Date,不然報錯
     * 
     * 查詢完畢後,使用者經過JDBCHelper.getConnection()獲取鏈接對象,並關閉它
     * 外部獲取的鏈接對象與本方法使用的鏈接對象,在同一線程類,是同一個對象
     * 
     * @param sql   要執行的查詢語句
     * @param t      實體類對象
     * @param objs    SQL語句中的參數
     * @return       裝有實體類對象的list集合
     */
    public static <T> List<T>  executeQuery(String sql,T t,Object...objs){
        //聲明jdbc變量
        List<T> list=new ArrayList<>();
        Connection conn = null;
        PreparedStatement ps =null;
        ResultSet rs =null;
        try {
            conn = JDBCHelper.getConnection();
            ps = conn.prepareStatement(sql);
            //給佔位符賦值
            if(objs!=null) {
                for(int i=0;i<objs.length;i++) {
                        ps.setObject((i+1), objs[i]);
                }
            }
            //執行sql語句
            rs = ps.executeQuery();
            //獲取結果集中字段的全部信息
            ResultSetMetaData rm = rs.getMetaData();
            int columnCount = rm.getColumnCount();//獲取字段數
            //遍歷結果集
            while(rs.next()) {
                    Class<? extends Object> cla = t.getClass();//獲取類對象
                    T newInstance=(T)cla.newInstance();//獲取類的對象
                    //一個for循環封裝一條記錄的全部值
                    for(int i=1;i<=columnCount;i++) {
                         String columnName = rm.getColumnName(i);//獲取字段名
                        //獲取字段對應的setter方法
                         String methodName="set"+columnName.substring(0, 1).toUpperCase()+columnName.substring(1);
                         String columnClassName = rm.getColumnClassName(i);//獲取字段java類型的徹底限定名    
                         //建立方法對象
                         Method method = cla.getDeclaredMethod(methodName, Class.forName(columnClassName));
                         method.invoke(newInstance,rs.getObject(columnName));//調用setter方法,執行對象屬性賦值
                    }
                    list.add(newInstance);//將對象加入集合
            }
        } catch (Exception  e) {
            e.printStackTrace();
        }finally {
            //關流
            JDBCHelper.close(ps,rs);
        }
        return list;
        
    }
    
    
    /**
     * 該方法封裝了MySQL數據庫的DML操做
     * 若是要實現事務:
     *         事務的開啓,關閉,回滾,及鏈接對象的關閉等操做
     *             使用者經過JDBCHelper.getConnection()獲取鏈接對象,經過鏈接對象並在外部聲明
     *             外部獲取的鏈接對象與本方法使用的鏈接對象,在同一線程類,是同一個對象
     * 
     * @param sql   要執行的SQL語句
     * @param objs  SQL語句中的參數
     * @return   成功執行返回影響的記錄條數,不然返回0
     * @throws SQLException 
     */
    public static Integer executeDML(String sql,Object...objs) {
        //聲明jdbc變量
        Connection conn =null;
        PreparedStatement ps =null;
        Integer i =0;
        try{            
            conn = JDBCHelper.getConnection();
            ps = conn.prepareStatement(sql);
            //給佔位符賦值
            if(objs!=null) {
                for(int j=0;j<objs.length;j++) {
                    ps.setObject((j+1), objs[j]);
                }
            }
            //執行SQL語句
            i = ps.executeUpdate();
        }catch(SQLException e) {
            e.printStackTrace();
        }finally {
            //關流
            JDBCHelper.close(ps);
        }            
        return i;        
    }    
    /**
     * 關流的方法,接收任意多個任意類型的流對象
     * 若是關閉的流對象有關閉的前後順序
     * 請將要先關閉的流對象放在前方
     * 
     * 全部流對象的頂級父接口都是AutoCloseable
     * @param t    要關閉的流對象,能夠是一個或多個(也能夠是零個)
     *                         
     */
    private static <T>void close(T...t){
        //循環關流
        for(T tmp:t) {
            //關閉流對象
            if(tmp instanceof AutoCloseable) {            
                try {
                    ((AutoCloseable)tmp).close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }                                            
        }
    }
}
相關文章
相關標籤/搜索