(5)修改和獲取ResultSet的值

前面的入門程序展示了如何從Result獲取對(duì)象,然后進(jìn)行對(duì)象的映射
這篇文章主要從下面的幾個(gè)方面講解:

  • ResultSet 接口
  • 從行檢索出列值
  • 游標(biāo)(Cursors)
  • 更新ResultSet 對(duì)象中行
  • 批量更新
  • 在ResultSet插入行

1.ResultSet 接口

ResultSet接口提供了檢索和操作執(zhí)行查詢結(jié)果的方法,ResultSet對(duì)象可以具有不同的功能和特征。這些特性是類型、并發(fā)性和游標(biāo)保持性。

  • ResultSet Types(結(jié)果集類型)

ResultSet對(duì)象的類型在兩個(gè)方面決定了它的功能級(jí)別:游標(biāo)操作的方式,以及對(duì)底層數(shù)據(jù)源的并發(fā)

ResultSet對(duì)象的靈敏度由三種不同的ResultSet類型之一決定:

  • TYPE_FORWARD_ONLY: 無(wú)法滾動(dòng)結(jié)果集;它的光標(biāo)僅向前移動(dòng),從第一行之前移動(dòng)到最后一行之后
  • TYPE_SCROLL_INSENSITIVE:滾動(dòng)的結(jié)果集,光標(biāo)可以向前移動(dòng)或者向后移動(dòng)到相對(duì)位置和絕對(duì)位置,結(jié)果集不敏感
  • TYPE_SCROLL_SENSITIVE:滾動(dòng)的結(jié)果集,光標(biāo)可以向前移動(dòng)或者向后移動(dòng)到相對(duì)位置和絕對(duì)位置,結(jié)果集敏感

默認(rèn)的結(jié)果集類型為: TYPE_FORWARD_ONLY,并不是所有的數(shù)據(jù)庫(kù)都支持所有的結(jié)果集類型,如果調(diào)用 DatabaseMetaData.supportsResultSetType返回true則說(shuō)明支持該結(jié)果集類型。

TYPE_SCROLL_INSENSITIVE和TYPE_SCROLL_SENSITIVE兩者的區(qū)別:
TYPE_SCROLL_INSENSITIVE當(dāng)獲取結(jié)果集的時(shí)候是緩存結(jié)果集到內(nèi)存中,當(dāng)調(diào)用next方法的時(shí)候直接從內(nèi)存中獲取
TYPE_SCROLL_SENSITIVE對(duì)返回的結(jié)果集是敏感的,那么是不是意味著拿到結(jié)果集后,數(shù)據(jù)庫(kù)中的數(shù)據(jù)變化都會(huì)反映到結(jié)果集中呢?不是這樣的,這里此時(shí)拿到的結(jié)果集只是記錄某種條件的的rowid
當(dāng)調(diào)用next方法的時(shí)候,在根據(jù)rowid去數(shù)據(jù)庫(kù)區(qū)查詢。
在調(diào)用next方法之前對(duì)數(shù)據(jù)庫(kù)進(jìn)行了更新操作,此時(shí)調(diào)用next方法可以獲取最新的數(shù)據(jù)
對(duì)于數(shù)據(jù)進(jìn)行插入的數(shù)據(jù),由于緩存的rowid并沒(méi)有,所以不會(huì)查詢出來(lái)。
但對(duì)于刪除操作。因?yàn)閿?shù)據(jù)庫(kù)刪除記錄只是記錄上做一個(gè)標(biāo)記,不再被檢索,但原來(lái)被緩存的ROWID還在,根據(jù)它還可以通過(guò)數(shù)據(jù)庫(kù)自己的底層操作正確地把數(shù)據(jù)提取出來(lái)

  • ResultSet Concurrency (結(jié)果集并發(fā)性)
    ResultSet對(duì)象的并發(fā)性決定了支持什么級(jí)別的更新功能。

有兩種更新的級(jí)別

  • CONCUR_READ_ONLY: ResultSet結(jié)果集不能被更新
  • CONCUR_UPDATABLE : ResultSet結(jié)果集可以被更新

默認(rèn)的結(jié)果集并發(fā)性為CONCUR_READ_ONLY
并不是所有的數(shù)據(jù)庫(kù)都支持所有的并發(fā)類型,可以用 DatabaseMetaData.supportsResultSetConcurrency()來(lái)檢測(cè)是否支持哪種結(jié)果集并發(fā)類型,返回true,則說(shuō)明支持

  • Cursor Holdability(游標(biāo)保持性)

調(diào)用方法Connection.commit可以關(guān)閉在當(dāng)前事務(wù)期間創(chuàng)建的ResultSet對(duì)象。然而,在某些情況下,這可能不是我們想要的行為。ResultSet屬性的可保持性使應(yīng)用程序能夠控制在調(diào)用commit時(shí)ResultSet對(duì)象(游標(biāo))是否關(guān)閉。

下面有兩種游標(biāo)保持性

  • HOLD_CURSORS_OVER_COMMIT:當(dāng)調(diào)用commit方法的時(shí)候,游標(biāo)沒(méi)有關(guān)閉,當(dāng)繼續(xù)保持。
  • CLOSE_CURSORS_AT_COMMIT:調(diào)用commit方法的時(shí)候,游標(biāo)關(guān)閉

并不是所有的數(shù)據(jù)庫(kù)都支持游標(biāo)的關(guān)閉和持有型。

下面給出一個(gè)具體的實(shí)例:

/**
 * @Project: jdk
 * @description: mysql的ResultSet測(cè)試
 * @author: sunkang
 * @create: 2018-10-14 14:33
 * @ModificationHistory who      when       What
 **/
public class ResultSetTest {

    public static void main(String[] args) throws SQLException {

        ResultSetTest  resultSetTest = new ResultSetTest();

        Connection con =  resultSetTest.getDefalutConnection();

        //驗(yàn)證mysql 支持哪些ResultSet類型
        DatabaseMetaData dbMetaData    = con.getMetaData();
        System.out.println("Supports TYPE_FORWARD_ONLY? "+dbMetaData.supportsResultSetType(ResultSet.TYPE_FORWARD_ONLY));
        System.out.println("Supports TYPE_SCROLL_INSENSITIVE? "+dbMetaData.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE));
        System.out.println("Supports TYPE_SCROLL_SENSITIVE? "+dbMetaData.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE));
       /* 上面的輸出結(jié)果為:
        Supports TYPE_FORWARD_ONLY? false
        Supports TYPE_SCROLL_INSENSITIVE? true
        Supports TYPE_SCROLL_SENSITIVE? false
        說(shuō)明mysql支持類型為 TYPE_SCROLL_INSENSITIVE
        */

        //驗(yàn)證mysql 支持哪些ResultSet并發(fā)性
        System.out.println("Supports CONCUR_READ_ONLY? "+dbMetaData.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY));
        System.out.println("Supports CONCUR_UPDATABLE? "+dbMetaData.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE));

      /* 上面的輸出結(jié)果為:
        Supports CONCUR_READ_ONLY? true
        Supports CONCUR_UPDATABLE? true
        說(shuō)明mysql 可以在ResultSet對(duì)象更改結(jié)果集
        */

        //驗(yàn)證mysql 支持哪些游標(biāo)保持性
        System.out.println("Supports HOLD_CURSORS_OVER_COMMIT? "+dbMetaData.supportsResultSetHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT));
        System.out.println("Supports CLOSE_CURSORS_AT_COMMIT? "+dbMetaData.supportsResultSetHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT));

        /**
         * Supports HOLD_CURSORS_OVER_COMMIT? true
         * Supports CLOSE_CURSORS_AT_COMMIT? false
         * 說(shuō)明mysql在commit提交之后,游標(biāo)還是打開(kāi)的
         */
        //創(chuàng)建了一個(gè)類型為HOLD_CURSORS_OVER_COMMIT,并發(fā)性為:CONCUR_UPDATABLE,以及游標(biāo)的保持性為:HOLD_CURSORS_OVER_COMMIT的語(yǔ)句集
       Statement statement  =  con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE,ResultSet.HOLD_CURSORS_OVER_COMMIT);

        ResultSet resultSet = statement.executeQuery("SELECT * FROM user");

        //設(shè)置連接的自動(dòng)提交為false
        con.setAutoCommit(false);
        //更新user 的address統(tǒng)一后面加上:update語(yǔ)句
        while (resultSet.next()) {
            //address為大寫和小寫都是可以的
            String address = resultSet.getString("address");
            resultSet.updateString("address", address+":update");
            //更新此行
            resultSet.updateRow();
            //在這里提交,游標(biāo)還是打開(kāi)的,所以不會(huì)有問(wèn)題
            con.commit();
        }
        //釋放資源
        resultSet.close();
        statement.close();
        con.close();
    }


    public Connection getDefalutConnection(){
        Connection connection = null;
        try {
            //1.加載數(shù)據(jù)庫(kù)驅(qū)動(dòng)
            Class.forName("com.mysql.jdbc.Driver");
            //2.通過(guò)驅(qū)動(dòng)管理類獲取數(shù)據(jù)庫(kù)鏈接
              connection =  DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "123");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
}

2.從行檢索出列值

入門程序已經(jīng)給出了,這里不再描述
可以根據(jù)索引來(lái)獲取對(duì)應(yīng)的列值,也可以根據(jù)列名獲取列值,這里的列名可以使列的別名, 根據(jù)列名獲取列的值的時(shí)候,這里輸入名稱可以大寫也可以是小寫

while(resultSet.next()){
                User user = new User();
                user.setId(resultSet.getInt("id"));
                user.setUsername(resultSet.getString("username"));
                user.setSex(resultSet.getString("sex"));
                user.setBirthday(resultSet.getTimestamp("birthday"));
                user.setAddress(resultSet.getString("address"));
                userList.add(user);
            }

3.cursors(游標(biāo))

你可以通過(guò)一個(gè)游標(biāo)來(lái)訪問(wèn)ResultSet的內(nèi)部數(shù)據(jù),游標(biāo)表示執(zhí)行ResultSet的某一行,當(dāng)ResultSet對(duì)象創(chuàng)建的時(shí)候,游標(biāo)指向的是第一行的前一行,調(diào)用next方法,可以使游標(biāo)向下移動(dòng),下面是移動(dòng)游標(biāo)的方法

next :移動(dòng)游標(biāo)執(zhí)行下一行,當(dāng)游標(biāo)的執(zhí)行的行存在數(shù)據(jù)的時(shí)候返回true,當(dāng)游標(biāo)執(zhí)行最后一行的后面的時(shí)候返回false
previous: 將游標(biāo)向上移動(dòng),該方法返回boolean型數(shù)據(jù),當(dāng)移到結(jié)果集第一行之前時(shí),返回false。
beforeFirst: 將游標(biāo)移動(dòng)到結(jié)果集的初始位置,即在第一行之前。
afterLast: 將游標(biāo)移到結(jié)果集最后一行之后。
first: 將游標(biāo)移到結(jié)果集的第一行。
last: 將游標(biāo)移到結(jié)果集的最后一行。
relative(int row):將游標(biāo)移動(dòng)到相對(duì)于當(dāng)前位置的指定行
absolute(int row): 將游標(biāo)移動(dòng)到指定的行數(shù)
getRow() : 得到當(dāng)前游標(biāo)所指向行的行號(hào),行號(hào)從1開(kāi)始,依次類推

一般數(shù)據(jù)庫(kù)默認(rèn)的ResultSet的敏感類型為TYPE_FORWARD_ONLY,這集意味著游標(biāo)不能滾動(dòng),除了調(diào)用next方法之外,其他的方法不可以進(jìn)行調(diào)用,所以游標(biāo)只能向下移動(dòng)

4.更新ResultSet 對(duì)象中行

上面的mysql的ResultSet測(cè)試已經(jīng)展示如何更新ResultSet中的行,更新ResultSet對(duì)象的行,需要數(shù)據(jù)庫(kù)支持ResultSet并發(fā)性為CONCUR_UPDATABLE,不然是無(wú)法更新的

 while (resultSet.next()) {
            //address為大寫和小寫都是可以的
            String address = resultSet.getString("address");
            resultSet.updateString("address", address+":update");
            //更新此行
            resultSet.updateRow();
}

5.批量更新

下面展示的是一個(gè)數(shù)據(jù)庫(kù)批量更新的例子

/**
 * @Project: jdk
 * @description:  批量更新  
 * @author: sunkang
 * @create: 2018-10-14 15:46
 * @ModificationHistory who      when       What
 **/
public class BatchUpdateTest{
    public static void main(String[] args) {
        BatchUpdateTest batchUpdateTest = new BatchUpdateTest();
        Connection con =batchUpdateTest.getDefalutConnection();
        Statement statement = null;
        try {
            //默認(rèn)的事務(wù)提交類型是自動(dòng)提交,但是在這里需要設(shè)置自動(dòng)提交類型為false,在出現(xiàn)錯(cuò)誤的時(shí)候需要回滾
            con.setAutoCommit(false);
             statement  =  con.createStatement();
            for(int i=0;i<10;i++){
                String username = "sunkang"+ i;
                statement.executeUpdate("insert user(username,birthday,sex,address) values ('"+username+"',NOW(),1,'hanghzou')");
            }
            //表示批量語(yǔ)句集返回的受影響的行數(shù)
            int[]  updateCounts  =  statement.executeBatch();
            con.commit();
            System.out.println(Arrays.toString(updateCounts));
        } catch (SQLException e) {
            //出現(xiàn)異常的時(shí)候回滾事務(wù)
            try {
                con.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            //關(guān)閉語(yǔ)句集
            if(statement!=null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            try {
                //設(shè)置回來(lái)
                con.setAutoCommit(true);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public Connection getDefalutConnection(){
        Connection connection = null;
        try {
            //1.加載數(shù)據(jù)庫(kù)驅(qū)動(dòng)
            Class.forName("com.mysql.jdbc.Driver");
            //2.通過(guò)驅(qū)動(dòng)管理類獲取數(shù)據(jù)庫(kù)鏈接
            connection =  DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "123");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
}

上面程序展示的普通的statement 執(zhí)行批量更新,如果是預(yù)編譯的statement呢?下圖展示了預(yù)編譯的statement的批量更新

        String sql = "insert user(username,birthday,sex,address) values (?,now(),?,?)";
            PreparedStatement preparedStatement =  con.prepareStatement(sql);
            for(int i=10;i<12;i++){
                String username = "sunkang"+ i;
                preparedStatement.setString(1,username);
                preparedStatement.setString(2,"1");
                preparedStatement.setString(3,"hanghzou");
                preparedStatement.addBatch();
            }
            preparedStatement.executeBatch();
            con.commit();

6.在ResultSet插入行

并不是所有數(shù)據(jù)都支持在ResultSet執(zhí)行插入的,前面的例子已經(jīng)測(cè)試mysql支持結(jié)果集并發(fā)性為CONCUR_UPDATABLE

/**
 * @Project: jdk
 * @description:  插入的測(cè)試
 * @author: sunkang
 * @create: 2018-10-14 16:18
 * @ModificationHistory who      when       What
 **/
public class InsertRowByResultSet {

    public static void main(String[] args) throws SQLException {
        ResultSetTest  resultSetTest = new ResultSetTest();
        Connection con =  resultSetTest.getDefalutConnection();
        Statement statement  = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
        String sql = "select * from user";
        ResultSet resultSet  = statement.executeQuery(sql);
        //移動(dòng)游標(biāo)到插入的行
        resultSet.moveToInsertRow();
        //插入一行數(shù)據(jù)
        resultSet.updateString("username","wangzhi");
        resultSet.updateString("sex","1");
        resultSet.updateTimestamp("birthday",new Timestamp(System.currentTimeMillis()));
        resultSet.updateString("address","han");

        //插入該條記錄
        resultSet.insertRow();
        //游標(biāo)移動(dòng)到最開(kāi)始的地方
        resultSet.beforeFirst();
        //釋放資源
        resultSet.close();
        statement.close();
    }
    
    public Connection getDefalutConnection(){
        Connection connection = null;
        try {
            //1.加載數(shù)據(jù)庫(kù)驅(qū)動(dòng)
            Class.forName("com.mysql.jdbc.Driver");
            //2.通過(guò)驅(qū)動(dòng)管理類獲取數(shù)據(jù)庫(kù)鏈接
            connection =  DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "123");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn) # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    呂品?閱讀 10,118評(píng)論 0 44
  • JDBC基礎(chǔ)知識(shí) 一、采用JDBC訪問(wèn)數(shù)據(jù)庫(kù)的基本步驟: A.載入JDBC驅(qū)動(dòng)程序 B.定義連接URL ...
    91數(shù)據(jù)閱讀 4,064評(píng)論 0 20
  • 本節(jié)介紹Statement接口及其子類PreparedStatement和CallableStatement。 它...
    zlb閱讀 1,242評(píng)論 0 0
  • 從前,有一戶人家,哥哥從軍在外,家里只有姑嫂二人,嫂子叫佩蘭,小姑叫藿香。佩蘭十分疼愛(ài)妹妹,藿香也很體貼嫂...
    清泉明月T_T閱讀 2,084評(píng)論 0 1
  • 風(fēng)推云霞,時(shí)間白馬,秋風(fēng)漸起,鴻雁南歸。當(dāng)海棠早已落盡,弦月再籠窗臺(tái),不覺(jué)已秋。 走過(guò)春的盎然,途徑夏的璀璨。忽然...
    楊一說(shuō)閱讀 682評(píng)論 5 11

友情鏈接更多精彩內(nèi)容