jdbc就是這麼簡單

来源:https://www.cnblogs.com/SIHAIloveYAN/archive/2018/08/03/9411301.html
-Advertisement-
Play Games

一、JDBC JAVA Database Connectivity java 資料庫連接. JDBC(Java DataBase Connectivity,java資料庫連接)是一種用於執行SQL語句的Java API,可以為多種關係資料庫提供統一訪問,它由一組用Java語言編寫的類和介面組成。JD ...


一、JDBC

JAVA Database Connectivity java 資料庫連接.

JDBC(Java DataBase Connectivity,java資料庫連接)是一種用於執行SQL語句的Java API,可以為多種關係資料庫提供統一訪問,它由一組用Java語言編寫的類和介面組成。JDBC提供了一種基準,據此可以構建更高級的工具和介面,使資料庫開發人員能夠編寫資料庫應用程式,同時,JDBC也是個商標名。

二、為什麼會出現JDBC

SUN公司提供的一種資料庫訪問規則、規範, 由於資料庫種類較多,並且java語言使用比較廣泛,sun公司就提供了一種規範,讓其他的資料庫提供商去實現底層的訪問規則。 我們的java程式只要使用sun公司提供的jdbc驅動即可。

三、資料庫驅動

我們安裝好資料庫之後,我們的應用程式也是不能直接使用資料庫的,必須要通過相應的資料庫驅動程式,通過驅動程式去和資料庫打交道。其實也就是資料庫廠商的JDBC介面實現,即對Connection等介面的實現類的jar文件。
1.png

四、常用介面

1.Driver介面

Driver介面由資料庫廠家提供,作為java開發人員,只需要使用Driver介面就可以了。在編程中要連接資料庫,必須先裝載特定廠商的資料庫驅動程式,不同的資料庫有不同的裝載方法。如:

  • 裝載MySql驅動:Class.forName("com.mysql.jdbc.Driver");

  • 裝載Oracle驅動:Class.forName("oracle.jdbc.driver.OracleDriver");

2.Connection介面

Connection與特定資料庫的連接(會話),在連接上下文中執行sql語句並返回結果。DriverManager.getConnection(url, user, password)方法建立在JDBC URL中定義的資料庫Connection連接上。

  • 連接MySql資料庫:Connection conn = DriverManager.getConnection("jdbc:mysql://host:port/database", "user", "password");

  • 連接Oracle資料庫:Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@host:port:database", "user", "password");

  • 連接SqlServer資料庫:Connection conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://host:port; DatabaseName=database", "user", "password");

常用方法:

  • createStatement():創建向資料庫發送sql的statement對象。
  • prepareStatement(sql) :創建向資料庫發送預編譯sql的PrepareSatement對象。
  • prepareCall(sql):創建執行存儲過程的callableStatement對象。
  • setAutoCommit(boolean autoCommit):設置事務是否自動提交。
  • commit() :在鏈接上提交事務。
  • rollback() :在此鏈接上回滾事務。

3.Statement介面

用於執行靜態SQL語句並返回它所生成結果的對象。

三種Statement類:

  • Statement:由createStatement創建,用於發送簡單的SQL語句(不帶參數)。
  • PreparedStatement :繼承自Statement介面,由preparedStatement創建,用於發送含有一個或多個參數的SQL語句。PreparedStatement對象比Statement對象的效率更高,並且可以防止SQL註入,所以我們一般都使用PreparedStatement。
  • CallableStatement:繼承自PreparedStatement介面,由方法prepareCall創建,用於調用存儲過程。

常用Statement方法:

  • execute(String sql):運行語句,返回是否有結果集
  • executeQuery(String sql):運行select語句,返回ResultSet結果集。
  • executeUpdate(String sql):運行insert/update/delete操作,返回更新的行數。
  • addBatch(String sql) :把多條sql語句放到一個批處理中。
  • executeBatch():向資料庫發送一批sql語句執行。

4.ResultSet介面

ResultSet提供檢索不同類型欄位的方法,常用的有:

  • getString(int index)、getString(String columnName):獲得在資料庫里是varchar、char等類型的數據對象。
  • getFloat(int index)、getFloat(String columnName):獲得在資料庫里是Float類型的數據對象。
  • getDate(int index)、getDate(String columnName):獲得在資料庫里是Date類型的數據。
  • getBoolean(int index)、getBoolean(String columnName):獲得在資料庫里是Boolean類型的數據。
  • getObject(int index)、getObject(String columnName):獲取在資料庫里任意類型的數據。

ResultSet還提供了對結果集進行滾動的方法:

  • next():移動到下一行
  • Previous():移動到前一行
  • absolute(int row):移動到指定行
  • beforeFirst():移動resultSet的最前面。
  • afterLast() :移動到resultSet的最後面。

使用後依次關閉對象及連接:ResultSet → Statement → Connection

五、使用JDBC的基本步驟

1. 註冊驅動
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
2. 建立連接
//DriverManager.getConnection("jdbc:mysql://localhost/test?user=SIHAI&password=SIHAI");
//2. 建立連接 參數一: 協議 + 訪問的資料庫 , 參數二: 用戶名 , 參數三: 密碼。

 conn = DriverManager.getConnection("jdbc:mysql://localhost/student", "root", "root");
3. 創建statement
//3. 創建statement , 跟資料庫打交道,一定需要這個對象
st = conn.createStatement();
4. 執行sql ,得到ResultSet
//4. 執行查詢 , 得到結果集
String sql = "select * from t_stu";
rs = st.executeQuery(sql);
5. 遍歷結果集
        //5. 遍歷查詢每一條記錄
        while(rs.next()){
            int id = rs.getInt("id");
            String name = rs.getString("name");
            int age = rs.getInt("age");
            System.out.println("id="+id + "===name="+name+"==age="+age);
                
        }
6. 釋放資源
    if (rs != null) {
       try {
            rs.close();
        } catch (SQLException sqlEx) { } // ignore 
        rs = null;
    }
    

六、JDBC 工具類構建

1. 資源釋放工作的整合
/**
     * 釋放資源
     * @param conn
     * @param st
     * @param rs
     */
    public static void release(Connection conn , Statement st , ResultSet rs){
        closeRs(rs);
        closeSt(st);
        closeConn(conn);
    }

    
    private static void closeRs(ResultSet rs){
        try {
            if(rs != null){
                rs.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            rs = null;
        }
    }
    
    private static void closeSt(Statement st){
        try {
            if(st != null){
                st.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            st = null;
        }
    }
    
    private static void closeConn(Connection conn){
        try {
            if(conn != null){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            conn = null;
        }
    }
2. 驅動防二次註冊
/**
     * 獲取連接對象
     * @return
     */
    public static Connection getConn(){
        Connection conn = null;
        try {
            Class.forName(driverClass);
            //靜態代碼塊 ---> 類載入了,就執行。 java.sql.DriverManager.registerDriver(new Driver());
            //DriverManager.registerDriver(new com.mysql.jdbc.Driver());
            //DriverManager.getConnection("jdbc:mysql://localhost/test?user=monty&password=greatsqldb");
            //2. 建立連接 參數一: 協議 + 訪問的資料庫 , 參數二: 用戶名 , 參數三: 密碼。
            conn = DriverManager.getConnection(url, name, password);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }
3. 使用properties配置文件
  • 在src底下聲明一個文件 xxx.properties ,裡面的內容吐下:
        driverClass=com.mysql.jdbc.Driver
        url=jdbc:mysql://localhost/student
        name=root
        password=root
  • 在工具類裡面,使用靜態代碼塊,讀取屬性
static{
            try {
                //1. 創建一個屬性配置對象
                Properties properties = new Properties();
                InputStream is = new FileInputStream("jdbc.properties"); //對應文件位於工程根目錄
                 
                //使用類載入器,去讀取src底下的資源文件。 後面在servlet  //對應文件位於src目錄底下
                //InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
                //導入輸入流。
                properties.load(is);
                
                //讀取屬性
                driverClass = properties.getProperty("driverClass");
                url = properties.getProperty("url");
                name = properties.getProperty("name");
                password = properties.getProperty("password");
                
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

源代碼如下:

public class JDBCUtil {
    
    static String driverClass = null;
    static String url = null;
    static String name = null;
    static String password= null;
    
    static{
        try {
            //1. 創建一個屬性配置對象
            Properties properties = new Properties();
            InputStream is = new FileInputStream("jdbc.properties");
            
            //使用類載入器,去讀取src底下的資源文件。 後面在servlet
//          InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
            //導入輸入流。
            properties.load(is);
            
            //讀取屬性
            driverClass = properties.getProperty("driverClass");
            url = properties.getProperty("url");
            name = properties.getProperty("name");
            password = properties.getProperty("password");
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 獲取連接對象
     * @return
     */
    public static Connection getConn(){
        Connection conn = null;
        try {
            Class.forName(driverClass);
            //靜態代碼塊 ---> 類載入了,就執行。 java.sql.DriverManager.registerDriver(new Driver());
            //DriverManager.registerDriver(new com.mysql.jdbc.Driver());
            //DriverManager.getConnection("jdbc:mysql://localhost/test?user=monty&password=greatsqldb");
            //2. 建立連接 參數一: 協議 + 訪問的資料庫 , 參數二: 用戶名 , 參數三: 密碼。
            conn = DriverManager.getConnection(url, name, password);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }
    
    /**
     * 釋放資源
     * @param conn
     * @param st
     * @param rs
     */
    public static void release(Connection conn , Statement st , ResultSet rs){
        closeRs(rs);
        closeSt(st);
        closeConn(conn);
    }

    
    private static void closeRs(ResultSet rs){
        try {
            if(rs != null){
                rs.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            rs = null;
        }
    }
    
    private static void closeSt(Statement st){
        try {
            if(st != null){
                st.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            st = null;
        }
    }
    
    private static void closeConn(Connection conn){
        try {
            if(conn != null){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            conn = null;
        }
    }
}

七、資料庫的CRUD

  • insert操作
INSERT INTO t_stu (NAME , age) VALUES ('wangqiang',28)

INSERT INTO t_stu VALUES (NULL,'wangqiang2',28)
// 1. 獲取連接對象
conn = JDBCUtil.getConn();
// 2. 根據連接對象,得到statement
st = conn.createStatement();

//3. 執行添加
String sql = "insert into t_stu values(null , 'aobama' , 59)";
//影響的行數, ,如果大於0 表明操作成功。 否則失敗
int result = st.executeUpdate(sql);

if(result >0 ){
    System.out.println("添加成功");
}else{
    System.out.println("添加失敗");
}
  • delete操作
DELETE FROM t_stu WHERE id = 6
// 1. 獲取連接對象
conn = JDBCUtil.getConn();
// 2. 根據連接對象,得到statement
st = conn.createStatement();

//3. 執行添加
String sql = "delete from t_stu where name='aobama'";
//影響的行數, ,如果大於0 表明操作成功。 否則失敗
int result = st.executeUpdate(sql);

if(result >0 ){
    System.out.println("刪除成功");
}else{
    System.out.println("刪除失敗");
}
  • query操作
SELECT * FROM t_stu
    // 1. 獲取連接對象
    conn = JDBCUtil.getConn();
    // 2. 根據連接對象,得到statement
    st = conn.createStatement();

    // 3. 執行sql語句,返回ResultSet
    String sql = "select * from t_stu";
    rs = st.executeQuery(sql);

    // 4. 遍歷結果集
    while (rs.next()) {
        String name = rs.getString("name");
        int age = rs.getInt("age");

        System.out.println(name + "   " + age);
    }
  • update操作
UPDATE t_stu SET age = 38 WHERE id = 1;
// 1. 獲取連接對象
conn = JDBCUtil.getConn();
// 2. 根據連接對象,得到statement
st = conn.createStatement();

//3. 執行添加
String sql = "update t_stu set age = 26 where name ='qyq'";
//影響的行數, ,如果大於0 表明操作成功。 否則失敗
int result = st.executeUpdate(sql);

if(result >0 ){
    System.out.println("更新成功");
}else{
    System.out.println("更新失敗");
}

八、使用單元測試,測試代碼

1. 定義一個類, TestXXX , 裡面定義方法 testXXX.

這個命名不一定需要這樣,但是這樣的命名更容易懂得測試的意思,所以建議命名見名知意。

2. 添加junit的支持。

右鍵工程 --- add Library --- Junit --- Junit4

3. 在方法的上面加上註解 , 其實就是一個標記。
    /**
 * 使用junit執行單元測試
 */
public class TestDemo {

    @Test
    public void testQuery() {
        // 查詢
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            // 1. 獲取連接對象
            conn = JDBCUtil.getConn();
            // 2. 根據連接對象,得到statement
            st = conn.createStatement();

            // 3. 執行sql語句,返回ResultSet
            String sql = "select * from t_stu";
            rs = st.executeQuery(sql);

            // 4. 遍歷結果集
            while (rs.next()) {
                String name = rs.getString("name");
                int age = rs.getInt("age");

                System.out.println(name + "   " + age);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtil.release(conn, st, rs);
        }

    }


    @Test
    public void testInsert(){
        
        // 查詢
        Connection conn = null;
        Statement st = null;
        try {
            // 1. 獲取連接對象
            conn = JDBCUtil.getConn();
            // 2. 根據連接對象,得到statement
            st = conn.createStatement();
            
            //3. 執行添加
            String sql = "insert into t_stu values(null , 'aobama' , 59)";
            //影響的行數, ,如果大於0 表明操作成功。 否則失敗
            int result = st.executeUpdate(sql);
            
            if(result >0 ){
                System.out.println("添加成功");
            }else{
                System.out.println("添加失敗");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JDBCUtil.release(conn, st);
        }

    }
    
    @Test
    public void testDelete(){
        
        // 查詢
        Connection conn = null;
        Statement st = null;
        try {
            // 1. 獲取連接對象
            conn = JDBCUtil.getConn();
            // 2. 根據連接對象,得到statement
            st = conn.createStatement();
            
            //3. 執行添加
            String sql = "delete from t_stu where name='aobama'";
            //影響的行數, ,如果大於0 表明操作成功。 否則失敗
            int result = st.executeUpdate(sql);
            
            if(result >0 ){
                System.out.println("刪除成功");
            }else{
                System.out.println("刪除失敗");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JDBCUtil.release(conn, st);
        }

    }
    @Test
    public void testUpdate(){
        
        // 查詢
        Connection conn = null;
        Statement st = null;
        try {
            // 1. 獲取連接對象
            conn = JDBCUtil.getConn();
            // 2. 根據連接對象,得到statement
            st = conn.createStatement();
            
            //3. 執行添加
            String sql = "update t_stu set age = 26 where name ='qyq'";
            //影響的行數, ,如果大於0 表明操作成功。 否則失敗
            int result = st.executeUpdate(sql);
            
            if(result >0 ){
                System.out.println("更新成功");
            }else{
                System.out.println("更新失敗");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JDBCUtil.release(conn, st);
        }
        
    }
}
4. 游標選中方法名字,然後右鍵執行單元測試。 或者是打開outline視圖, 然後選擇方法右鍵執行。

九、Dao模式

Data Access Object 數據訪問對象

DAO(Data Access Object) 數據訪問對象是一個面向對象的資料庫介面,它顯露了 Microsoft Jet 資料庫引擎(由 Microsoft Access 所使用),並允許 Visual Basic 開發者通過 ODBC 像直接連接到其他資料庫一樣,直接連接到 Access 表。DAO 最適用於單系統應用程式或小範圍本地分佈使用。

1. 新建一個dao的介面, 裡面聲明資料庫訪問規則
    /**
    * 定義操作資料庫的方法
     */
    public interface UserDao {
    
        /**
         * 查詢所有
         */
        void findAll();
    }
2. 新建一個dao的實現類,具體實現早前定義的規則
public class UserDaoImpl implements UserDao{

        @Override
        public void findAll() {
            Connection conn = null;
            Statement st = null;
            ResultSet rs = null;
            try {
                //1. 獲取連接對象
                conn = JDBCUtil.getConn();
                //2. 創建statement對象
                st = conn.createStatement();
                String sql = "select * from t_user";
                rs = st.executeQuery(sql);
                
                while(rs.next()){
                    String userName = rs.getString("username");
                    String password = rs.getString("password");
                    
                    System.out.println(userName+"="+password);
                }
                
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                JDBCUtil.release(conn, st, rs);
            }
        }
    
    }
3. 直接使用實現
    @Test
    public void testFindAll(){
        UserDao dao = new UserDaoImpl();
        dao.findAll();
    }

十、Statement安全問題

1. Statement執行 ,其實是拼接sql語句的。 先拼接sql語句,然後在一起執行。
String sql = "select * from t_user where username='"+ username  +"' and password='"+ password +"'";

UserDao dao = new UserDaoImpl();
dao.login("admin", "100234khsdf88' or '1=1");

SELECT * FROM t_user WHERE username='admin' AND PASSWORD='100234khsdf88' or '1=1' 

//前面先拼接sql語句, 如果變數裡面帶有了 資料庫的關鍵字,那麼一併認為是關鍵字。 不認為是普通的字元串。 
rs = st.executeQuery(sql);

PrepareStatement

該對象就是替換前面的statement對象。

  1. 相比較以前的statement, 預先處理給定的sql語句,對其執行語法檢查。 在sql語句裡面使用 ? 占位符來替代後續要傳遞進來的變數。 後面進來的變數值,將會被看成是字元串,不會產生任何的關鍵字。
String sql = "insert into t_user values(null , ? , ?)";
ps = conn.prepareStatement(sql);
 
 //給占位符賦值 從左到右數過來,1 代表第一個問號, 永遠你是1開始。
 ps.setString(1, userName);
 ps.setString(2, password);

PreparedStatement與Statement比較

(1) 使用PreparedStatement,代碼的可讀性和可維護性比Statement高。

(2) PreparedStatement 能最大可能提高性能。

DBServer會對預編譯語句提供性能優化。因為預編譯語句有可能被重覆調用,所以語句在被DBServer的編譯器編譯後的執行代碼被緩存下來,那麼下次調用時只要是相同的預編譯語句就不需要編譯,只要將參數直接傳入編譯過的語句執行代碼中就會得到執行。

在statement語句中,即使是相同操作但因為數據內容不一樣,所以整個語句本身不能匹配,沒有緩存語句的意義。事實是沒有資料庫會對普通語句編譯後的執行代碼緩存。這樣每執行一次都要對傳入的語句編譯一次。

(3) PreparedStatement能保證安全性,但 Statement有sql註入等安全問題。

十一、資料庫事務

1. 概述

在資料庫中,所謂事務是指一組邏輯操作單元,使數據從一種狀態變換到另一種狀態。

為確保資料庫中數據的一致性,數據的操縱應當是離散的成組的邏輯單元:當它全部完成時,數據的一致性可以保持,而當這個單元中的一部分操作失敗,整個事務應全部視為錯誤,所有從起始點以後的操作應全部回退到開始狀態。

事務的操作:先定義開始一個事務,然後對數據作修改操作,這時如果提交(COMMIT),這些修改就永久地保存下來,如果回退(ROLLBACK),資料庫管理系統將放棄您所作的所有修改而回到開始事務時的狀態。

2. 事務的ACID屬性

2.1 原子性(Atomicity)

原子性是指事務是一個不可分割的工作單位,事務中的操作要麼都發生,要麼都不發生。

2.2 一致性(Consistency)

事務必須使資料庫從一個一致性狀態變換到另外一個一致性狀態。(數據不被破壞)

2.3 隔離性(Isolation)

事務的隔離性是指一個事務的執行不能被其他事務干擾,即一個事務內部的操作及使用的數據對併發的其他事務是隔離的,併發執行的各個事務之間不能互相干擾。

2.4 持久性(Durability)

持久性是指一個事務一旦被提交,它對資料庫中數據的改變就是永久性的,接下來的其他操作和資料庫故障不應該對其有任何影響。

3. JDBC 事務處理

在JDBC中,事務預設是自動提交的,每次執行一個 SQL 語句時,如果執行成功,就會向資料庫自動提交,而不能回滾。

為了讓多個 SQL 語句作為一個事務執行,需調用 Connection 對象的 setAutoCommit(false); 以取消自動提交事務:

conn.setAutoCommit(false);

在所有的 SQL 語句都成功執行後,調用 commit(); 方法提交事務

conn.commit();

在出現異常時,調用 rollback(); 方法回滾事務,一般再catch模塊中執行回滾操作。

conn.rollback();

可以通過Connection的getAutoCommit()方法來獲得當前事務的提交方式。

註意:在MySQL中的資料庫存儲引擎InnoDB支持事務,MyISAM不支持事務。

十二、批量處理JDBC語句

1. 概述

當需要批量插入或者更新記錄時。可以採用Java的批量更新機制,這一機制允許多條語句一次性提交給資料庫批量處理。通常情況下比單獨提交處理更有效率。

JDBC的批量處理語句包括下麵兩個方法:

  • addBatch(String):添加需要批量處理的SQL語句或是參數;
  • executeBatch();執行批量處理語句;

通常我們會遇到兩種批量執行SQL語句的情況:

  • 多條SQL語句的批量處理;
  • 一個SQL語句的批量傳參;

2. Statement批量處理

Statement sm = conn.createStatement();
sm.addBatch(sql1);
sm.addBatch(sql2);
...
//批量處理
sm.executeBatch()
//清除sm中積攢的參數列表
sm.clearBatch();

3. PreparedStatement批量傳參

preparedStatement ps = conn.preparedStatement(sql);
for(int i=1;i<100000;i++){
    ps.setInt(1, i);
    ps.setString(2, "name"+i);
    ps.setString(3, "email"+i);
    ps.addBatch();
    if((i+1)%1000==0){
        //批量處理
        ps.executeBatch();
        //清空ps中積攢的sql
        ps.clearBatch();
    }
}

註意:MySQL不支持批量處理。

批量處理應該設置一個上限,當批量處理列表中的sql累積到一定數量後,就應該執行,併在執行完成後,清空批量列表。

一般在excel導入數據的時候會用到批處理。

十三、使用 JDBC 處理元數據

1. 概述

Java 通過JDBC獲得連接以後,得到一個Connection 對象,可以從這個對象獲得有關資料庫管理系統的各種信息,包括資料庫中的各個表,表中的各個列,數據類型,觸發器,存儲過程等各方面的信息。根據這些信息,JDBC可以訪問一個實現事先並不瞭解的資料庫。

獲取這些信息的方法都是在DatabaseMetaData類的對象上實現的,而DataBaseMetaData對象是在Connection對象上獲得的。

2. 獲取資料庫元數據

DatabaseMetaData 類中提供了許多方法用於獲得數據源的各種信息,通過這些方法可以非常詳細的瞭解資料庫的信息:

  • getURL():返回一個String類對象,代表資料庫的URL。
  • getUserName():返回連接當前資料庫管理系統的用戶名。
  • isReadOnly():返回一個boolean值,指示資料庫是否只允許讀操作。
  • getDatabaseProductName():返回資料庫的產品名稱。
  • getDatabaseProductVersion():返回資料庫的版本號。
  • getDriverName():返回驅動驅動程式的名稱。
  • getDriverVersion():返回驅動程式的版本號。

3. ResultSetMetaData

可用於獲取關於 ResultSet 對象中列的類型和屬性信息的對象:

  • getColumnName(int column):獲取指定列的名稱
  • getColumnCount():返回當前 ResultSet 對象中的列數。
  • getColumnTypeName(int column):檢索指定列的資料庫特定的類型名稱。
  • getColumnDisplaySize(int column):指示指定列的最大標準寬度,以字元為單位。
  • isNullable(int column):指示指定列中的值是否可以為 null。
  • isAutoIncrement(int column):指示是否自動為指定列進行編號,這樣這些列仍然是只讀的。

十四、創建可滾動、更新的記錄集

1. Statement

Statement stmt = conn.createStatement(type,concurrency);

2. PreparedStatement

PreparedStatement stmt = conn.prepareStatement(sql,type,concurrency);

type說明:

ResultSet的Type 說明
TYPE_FORWARD_ONLY 結果集不能滾動,只可向前滾動
TYPE_SCROLL_INSENSITIVE 雙向滾動,但不及時更新,就是如果資料庫里的數據修改過,並不在ResultSet中反應出來
TYPE_SCROLL_SENSITIVE 雙向滾動,並及時跟蹤資料庫的更新,以便更改ResultSet中的數據

Concurrency(併發類型)說明:

ResultSet的Concurrency(併發類型) 說明
CONCUR_READ_ONLY 結果集不可用於更新資料庫
CONCUR_UPDATABLE 結果集可以用於更新資料庫

3. ResultSet滾動的結果集使用

First: 將指針移動到此 ResultSet 對象的第一行
Last: 將指針移動到此 ResultSet 對象的最後一行
beforeFirst: 將指針移動到此 ResultSet 對象的開頭,正好位於第一行之前
afterLast: 將指針移動到此 ResultSet 對象的末尾,正好位於最後一行之後
isFirst: 檢索指針是否位於此 ResultSet 對象的第一行
isLast: 檢索指針是否位於此 ResultSet 對象的最後一行
isBeforeFirst: 檢索指針是否位於此 ResultSet 對象的第一行之前
isAfterLast: 檢索指針是否位於此 ResultSet 對象的最後一行之後
Relative: 按相對行數(或正或負)移動指針
Next: 將指針從當前位置下移一行
Previous: 將指針移動到此 ResultSet 對象的上一行
Absolute: 將指針移動到此 ResultSet 對象的給定行編號

如:

rs.absolute(80); //將指針移動到ResultSet 對象的第80行記錄。

註意:該特性對Oralce數據有效。但是在Mysql資料庫中無效,Mysql只支持TYPE_SCROLL_INSENSITIVE,CONCUR_READ_ONLY

十五、JDBC連接池

1. 為什麼要使用JDBC連接池

普通的JDBC資料庫連接使用 DriverManager 來獲取,每次向資料庫建立連接的時候都要將 Connection 載入到記憶體中,再驗證用戶名和密碼。需要資料庫連接的時候,就向資料庫要求一個,執行完成後再斷開連接。這樣的方式將會消耗大量的資源和時間。資料庫的連接資源並沒有得到很好的重覆利用.若同時有幾百人甚至幾千人線上,頻繁的進行資料庫連接操作將占用很多的系統資源,嚴重的甚至會造成伺服器的崩潰。

對於每一次資料庫連接,使用完後都得斷開。否則,如果程式出現異常而未能關閉,將會導致資料庫系統中的記憶體泄漏,最終將導致重啟資料庫。

這種開發不能控制被創建的連接對象數,系統資源會被毫無顧及的分配出去,如連接過多,也可能導致記憶體泄漏,伺服器崩潰。

為解決傳統開發中的資料庫連接問題,可以採用資料庫連接池技術。

2. 資料庫連接池(connection pool)

資料庫連接池的基本思想就是為資料庫連接建立一個“緩衝池”。預先在緩衝池中放入一定數量的連接,當需要建立資料庫連接時,只需從“緩衝池”中取出一個,使用完畢之後再放回去。

資料庫連接池負責分配、管理和釋放資料庫連接,它允許應用程式重覆使用一個現有的資料庫連接,而不是重新建立一個。

資料庫連接池在初始化時將創建一定數量的資料庫連接放到連接池中,這些資料庫連接的數量是由最小資料庫連接數來設定的。無論這些資料庫連接是否被使用,連接池都將一直保證至少擁有這麼多的連接數量。連接池的最大資料庫連接數量限定了這個連接池能占有的最大連接數,當應用程式向連接池請求的連接數超過最大連接數量時,這些請求將被加入到等待隊列中。

3. 資料庫連接池工作原理

2.png

4. 使用資料庫連接池的優點

(1)資源重用:

由於資料庫連接得以重用,避免了頻繁創建,釋放連接引起的大量性能開銷。在減少系統消耗的基礎上,另一方面也增加了系統運行環境的平穩性。

(2)更快的系統反應速度

資料庫連接池在初始化過程中,往往已經創建了若幹資料庫連接置於連接池中備用。此時連接的初始化工作均已完成。對於業務請求處理而言,直接利用現有可用連接,避免了資料庫連接初始化和釋放過程的時間開銷,從而減少了系統的響應時間。

(3)新的資源分配手段

對於多應用共用同一資料庫的系統而言,可在應用層通過資料庫連接池的配置,實現某一應用最大可用資料庫連接數的限制,避免某一應用獨占所有的資料庫資源。

(4)統一的連接管理,避免資料庫連接泄露
在較為完善的資料庫連接池實現中,可根據預先的占用超時設定,強制回收被占用連接,從而避免了常規資料庫連接操作中可能出現的資源泄露。

5. 常用資料庫連接池介紹

JDBC 的資料庫連接池使用 javax.sql.DataSource 來表示,DataSource 只是一個介面,該介面通常由伺服器(Weblogic, WebSphere, Tomcat)提供實現,也有一些開源組織提供實現,如:

  • DBCP 資料庫連接池
  • C3P0 資料庫連接池
  • Proxpool 資料庫連接池

其中,DBCP和C3P0用得比較多。

Tomcat 在 7.0 以前的版本都是使用 commons-dbcp 做為連接池的實現。

數據源和資料庫連接不同,數據源無需創建多個,它是產生資料庫連接的工廠,因此整個應用只需要一個數據源即可。

當資料庫訪問結束後,程式還是像以前一樣關閉資料庫連接:conn.close(); 但它並沒有關閉資料庫的物理連接,它僅僅把資料庫連接釋放,歸還給了資料庫連接池。

大概基本的就是這麼多了,希望能夠幫助到大家,有問題可以交流溝通。

文章有不當之處,歡迎指正,如果喜歡微信閱讀,你也可以關註我的微信公眾號:好好學java,獲取優質學習資源。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1:children及find方法都用是用來獲得element的子elements的,兩者都不會返回 text node,就像大多數的jQuery方法一樣。 2:children方法獲得的僅僅是元素一下級的子元素,即:immediate children。 3:find方法獲得所有下級元素,即:de ...
  • CSS 的偽類選擇器和偽元素選擇器,讓 CSS 有了更為強大的功能。 偽類大家聽的多了,偽元素可能聽到的不是那麼頻繁,其實 CSS 對這兩個是有區分的。 有個錯誤有必要每次講到偽類都提一下,有時你會發現偽類元素使用了兩個冒號 (::) 而不是一個冒號 (:),這是 CSS3 規範中的一部分要求,目的 ...
  • 很多時候我們需要引入框架來開發項目,這時我們可能會遇到頁面還沒載入完源碼出來了的問題,給用戶一種不好的視覺體驗,這是便需要loading載入了,來完善用戶體驗! ...
  • 工廠方法模式 概要 1. 一個抽象產品類 2. 多個具體產品類 3. 一個抽象工廠 4. 多個具體工廠 每一個具體產品對應一個具體工廠 5. 符合 "OCP開放封閉原則" 優點 1. 降低了代碼耦合度,對象的生成交給子類去完成 2. 實現了開放封閉原則 每次添加子產品 不需要修改原有代碼 缺點 1. ...
  • 前言: spring 的環繞通知和前置通知,後置通知有著很大的區別,主要有兩個重要的區別: 1) 目標方法的調用由環繞通知決定,即你可以決定是否調用目標方法,而前置和後置通知 是不能決定的,他們只是在方法的調用前後執行通知而已,即目標方法肯定是要執行的。 2) 環繞通知可以控制返回對象,即你可以返回 ...
  • 有以下3種方式發送RocketMQ消息 可靠同步發送 reliable synchronous 可靠非同步發送 reliable asynchronous 單向發送 one-way transmission 可靠同步發送 主要運用在比較重要一點消息傳遞/通知等業務 可靠非同步發送 通常用於對發送消息響應 ...
  • what the f**k!!這個知識點學不好的最大元凶就是,我還單身??? python基礎(四): 面向對象的三個特點: 封裝,繼承,多態 類: 對象是面向對象編程的核心,在使用對象的過程中,為了將具有共同特征和行為的一組對象抽象定義,提出了另外一個新的概念——類 類就相當於製造飛機時的圖紙,用 ...
  • System中代表程式所在系統,提供了對應的一些系統屬性信息,和系統操作。System類不能手動創建對象,因為構造方法被private修飾,阻止外界創建對象。System類中的都是static方法,類名訪問即可。 常用方法: l currentTimeMillis() 獲取當前系統時間與1970年0 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...