Documentation

The Java™ Tutorials
Hide TOC
Retrieving and Modifying Values from Result Sets从结果集中检索和修改值
Trail: JDBC Database Access
Lesson: JDBC Basics

Retrieving and Modifying Values from Result Sets从结果集中检索和修改值

The following method, CoffeesTable.viewTable outputs the contents of the COFFEES tables, and demonstrates the use of ResultSet objects and cursors:以下方法CoffeesTable.viewTable输出COFFEES表的内容,并演示ResultSet对象和游标的使用:

public static void viewTable(Connection con) throws SQLException {
    String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES";
    try (Statement stmt = con.createStatement()) {
      ResultSet rs = stmt.executeQuery(query);
      while (rs.next()) {
        String coffeeName = rs.getString("COF_NAME");
        int supplierID = rs.getInt("SUP_ID");
        float price = rs.getFloat("PRICE");
        int sales = rs.getInt("SALES");
        int total = rs.getInt("TOTAL");
        System.out.println(coffeeName + ", " + supplierID + ", " + price +
                           ", " + sales + ", " + total);
      }
    } catch (SQLException e) {
      JDBCTutorialUtilities.printSQLException(e);
    }
  }

A ResultSet object is a table of data representing a database result set, which is usually generated by executing a statement that queries the database. ResultSet对象是表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。For example, the CoffeeTables.viewTable method creates a ResultSet, rs, when it executes the query through the Statement object, stmt. 例如,CoffeeTables.viewTable方法通过Statement对象stmt执行查询时,会创建一个ResultSetrsNote that a ResultSet object can be created through any object that implements the Statement interface, including PreparedStatement, CallableStatement, and RowSet.请注意,可以通过实现Statement接口的任何对象创建ResultSet对象,包括PreparedStatementCallableStatementRowSet

You access the data in a ResultSet object through a cursor. 您可以通过游标访问ResultSet对象中的数据。Note that this cursor is not a database cursor. 请注意,此游标不是数据库游标。This cursor is a pointer that points to one row of data in the ResultSet. 此游标是指向ResultSet中一行数据的游标。Initially, the cursor is positioned before the first row. 最初,游标位于第一行之前。The method ResultSet.next moves the cursor to the next row. 方法ResultSet.next将游标移动到下一行。This method returns false if the cursor is positioned after the last row. 如果游标位于最后一行之后,则此方法返回falseThis method repeatedly calls the ResultSet.next method with a while loop to iterate through all the data in the ResultSet.此方法使用while循环重复调用ResultSet.next方法,以遍历ResultSet中的所有数据。

This page covers the following topics:本页涵盖以下主题:

ResultSet Interface接口

The ResultSet interface provides methods for retrieving and manipulating the results of executed queries, and ResultSet objects can have different functionality and characteristics. ResultSet接口提供了检索和操作已执行查询结果的方法,ResultSet对象可以具有不同的功能和特征。These characteristics are type, concurrency, and cursor holdability.这些特征是类型、并发性和游标保持性。

ResultSet Types类型

The type of a ResultSet object determines the level of its functionality in two areas: the ways in which the cursor can be manipulated, and how concurrent changes made to the underlying data source are reflected by the ResultSet object.ResultSet对象的类型决定了它在两个方面的功能级别:游标的操作方式,以及ResultSet对象如何反映对基础数据源所做的并发更改。

The sensitivity of a ResultSet object is determined by one of three different ResultSet types:ResultSet对象的敏感度由以下三种不同ResultSet类型之一决定:

The default ResultSet type is TYPE_FORWARD_ONLY.默认的ResultSet类型为TYPE_FORWARD_ONLY

Note: Not all databases and JDBC drivers support all ResultSet types. :并非所有数据库和JDBC驱动程序都支持所有ResultSet类型。The method DatabaseMetaData.supportsResultSetType returns true if the specified ResultSet type is supported and false otherwise.如果指定的ResultSet类型受支持,则DatabaseMetaData.supportsResultSetType方法返回true,否则返回false

ResultSet Concurrency并发性

The concurrency of a ResultSet object determines what level of update functionality is supported.ResultSet对象的并发性决定了支持哪一级别的更新功能。

There are two concurrency levels:有两个并发级别:

The default ResultSet concurrency is CONCUR_READ_ONLY.默认ResultSet并发性为CONCUR_READ_ONLY

Note: Not all JDBC drivers and databases support concurrency. :并非所有JDBC驱动程序和数据库都支持并发。The method DatabaseMetaData.supportsResultSetConcurrency returns true if the specified concurrency level is supported by the driver and false otherwise.如果驱动程序支持指定的并发级别,则方法DatabaseMetaData.supportsResultSetConcurrency返回true,否则返回false

The method CoffeesTable.modifyPrices demonstrates how to use a ResultSet object whose concurrency level is CONCUR_UPDATABLE.CoffeesTable.modifyPrices方法演示了如何使用并发级别为CONCUR_UPDATABLEResultSet对象。

Cursor Holdability游标保持性

Calling the method Connection.commit can close the ResultSet objects that have been created during the current transaction. 调用方法Connection.commit可以关闭在当前事务期间创建的ResultSet对象。In some cases, however, this may not be the desired behavior. 然而,在某些情况下,这可能不是期望的行为。The ResultSet property holdability gives the application control over whether ResultSet objects (cursors) are closed when commit is called.ResultSet属性holdability使应用程序可以控制在调用commit时是否关闭ResultSet对象(游标)。

The following ResultSet constants may be supplied to the Connection methods createStatement, prepareStatement, and prepareCall:以下ResultSet常量可提供给Connection方法createStatementprepareStatementprepareCall

The default cursor holdability varies depending on your DBMS.默认游标保持能力因DBMS而异。

Note: Not all JDBC drivers and databases support holdable and non-holdable cursors. :并非所有JDBC驱动程序和数据库都支持可保持和不可保持游标。The following method, JDBCTutorialUtilities.cursorHoldabilitySupport, outputs the default cursor holdability of ResultSet objects and whether HOLD_CURSORS_OVER_COMMIT and CLOSE_CURSORS_AT_COMMIT are supported:以下方法JDBCTutorialUtilities.cursorHoldabilitySupport输出ResultSet对象的默认游标保持能力,以及是否支持HOLD_CURSORS_OVER_COMMITCLOSE_CURSORS_AT_COMMIT

public static void cursorHoldabilitySupport(Connection conn)
    throws SQLException {

    DatabaseMetaData dbMetaData = conn.getMetaData();
    System.out.println("ResultSet.HOLD_CURSORS_OVER_COMMIT = " +
        ResultSet.HOLD_CURSORS_OVER_COMMIT);

    System.out.println("ResultSet.CLOSE_CURSORS_AT_COMMIT = " +
        ResultSet.CLOSE_CURSORS_AT_COMMIT);

    System.out.println("Default cursor holdability: " +
        dbMetaData.getResultSetHoldability());

    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));
}

Retrieving Column Values from Rows从行中检索列值

The ResultSet interface declares getter methods (for example, getBoolean and getLong) for retrieving column values from the current row. ResultSet接口声明用于从当前行检索列值的getter方法(例如getBooleangetLong)。You can retrieve values using either the index number of the column or the alias or name of the column. 可以使用列的索引号或列的别名或名称检索值。The column index is usually more efficient. 列索引通常更有效。Columns are numbered from 1. 列从1开始编号。For maximum portability, result set columns within each row should be read in left-to-right order, and each column should be read only once.为了实现最大的可移植性,每行中的结果集列应该按从左到右的顺序读取,并且每列只应该读取一次。

For example, the following method, CoffeesTable.alternateViewTable, retrieves column values by number:例如,以下方法CoffeesTable.alternateViewTable按编号检索列值:

public static void alternateViewTable(Connection con) throws SQLException {
    String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES";
    try (Statement stmt = con.createStatement()) {
      ResultSet rs = stmt.executeQuery(query);
      while (rs.next()) {
        String coffeeName = rs.getString(1);
        int supplierID = rs.getInt(2);
        float price = rs.getFloat(3);
        int sales = rs.getInt(4);
        int total = rs.getInt(5);
        System.out.println(coffeeName + ", " + supplierID + ", " + price +
                           ", " + sales + ", " + total);
      }
    } catch (SQLException e) {
      JDBCTutorialUtilities.printSQLException(e);
    }
  }

Strings used as input to getter methods are case-insensitive. 用作getter方法输入的字符串不区分大小写。When a getter method is called with a string and more than one column has the same alias or name as the string, the value of the first matching column is returned. 当使用字符串调用getter方法并且多个列具有与字符串相同的别名或名称时,将返回第一个匹配列的值。The option to use a string as opposed to an integer is designed to be used when column aliases and names are used in the SQL query that generated the result set. 使用字符串而不是整数的选项是为了在生成结果集的SQL查询中使用列别名和名称时使用。For columns that are not explicitly named in the query (for example, select * from COFFEES) it is best to use column numbers. 对于查询中未显式命名的列(例如,select * from COFFEES),最好使用列号。If column names are used, the developer should guarantee that they uniquely refer to the intended columns by using column aliases. 如果使用了列名,开发人员应该通过使用列别名来保证它们唯一地引用了预期的列。A column alias effectively renames the column of a result set. 列别名可以有效地重命名结果集的列。To specify a column alias, use the SQL AS clause in the SELECT statement.要指定列别名,请在SELECT语句中使用SQL AS子句。

The getter method of the appropriate type retrieves the value in each column. 适当类型的getter方法检索每个列中的值。For example, in the method CoffeeTables.viewTable, the first column in each row of the ResultSet rs is COF_NAME, which stores a value of SQL type VARCHAR. 例如,在方法CoffeeTables.viewTable中,ResultSet rs每行的第一列是COF_NAME,它存储SQL类型VARCHAR的值。The method for retrieving a value of SQL type VARCHAR is getString. 检索SQL类型VARCHAR的值的方法是getStringThe second column in each row stores a value of SQL type INTEGER, and the method for retrieving values of that type is getInt.每行的第二列存储SQL类型INTEGER的值,检索该类型值的方法是getInt

Note that although the method getString is recommended for retrieving the SQL types CHAR and VARCHAR, it is possible to retrieve any of the basic SQL types with it. 请注意,尽管建议使用getString方法检索SQL类型CHARVARCHAR,但也可以使用它检索任何基本SQL类型。Getting all values with getString can be very useful, but it also has its limitations. 使用getString获取所有值非常有用,但也有其局限性。For instance, if it is used to retrieve a numeric type, getString converts the numeric value to a Java String object, and the value has to be converted back to a numeric type before it can be operated on as a number. 例如,如果用于检索数值类型,则getString将数值转换为JavaString对象,并且必须将该值转换回数值类型,然后才能将其作为数字进行操作。In cases where the value is treated as a string anyway, there is no drawback. Furthermore, if you want an application to retrieve values of any standard SQL type other than SQL3 types, use the getString method.在值被视为字符串的情况下,没有缺点。此外,如果希望应用程序检索SQL3类型以外的任何标准SQL类型的值,请使用getString方法。

Cursors游标

As mentioned previously, you access the data in a ResultSet object through a cursor, which points to one row in the ResultSet object. 如前所述,您可以通过游标访问ResultSet对象中的数据,游标指向ResultSet对象中的一行。However, when a ResultSet object is first created, the cursor is positioned before the first row. 但是,当第一次创建ResultSet对象时,游标位于第一行之前。The method CoffeeTables.viewTable moves the cursor by calling the ResultSet.next method. 方法CoffeeTables.viewTable通过调用ResultSet.next方法来移动游标。There are other methods available to move the cursor:还有其他方法可用于移动游标:

Note that the default sensitivity of a ResultSet is TYPE_FORWARD_ONLY, which means that it cannot be scrolled; you cannot call any of these methods that move the cursor, except next, if your ResultSet cannot be scrolled. 请注意,ResultSet的默认敏感度为TYPE_FORWARD_ONLY,这意味着它无法滚动;如果无法滚动结果集,则不能调用这些移动游标的方法中的任何一个,除非调用nextThe method CoffeesTable.modifyPrices, described in the following section, demonstrates how you can move the cursor of a ResultSet.下一节介绍的方法CoffeesTable.modifyPrices演示了如何移动ResultSet的游标。

Updating Rows in ResultSet Objects更新ResultSet对象中的行

You cannot update a default ResultSet object, and you can only move its cursor forward. 无法更新默认的ResultSet对象,只能向前移动其游标。However, you can create ResultSet objects that can be scrolled (the cursor can move backwards or move to an absolute position) and updated.但是,您可以创建可以ResultSet(游标可以向后移动或移动到绝对位置)和更新的ResultSet对象。

The following method, CoffeesTable.modifyPrices, multiplies the PRICE column of each row by the argument percentage:以下方法CoffeesTable.modifyPrices将每行的PRICE列乘以参数percentage

public void modifyPrices(float percentage) throws SQLException {
    try (Statement stmt =
      con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) {
      ResultSet uprs = stmt.executeQuery("SELECT * FROM COFFEES");
      while (uprs.next()) {
        float f = uprs.getFloat("PRICE");
        uprs.updateFloat("PRICE", f * percentage);
        uprs.updateRow();
      }
    } catch (SQLException e) {
      JDBCTutorialUtilities.printSQLException(e);
    }
  }

The field ResultSet.TYPE_SCROLL_SENSITIVE creates a ResultSet object whose cursor can move both forward and backward relative to the current position and to an absolute position. 字段ResultSet.TYPE_SCROLL_SENSITIVE创建一个ResultSet对象,其游标可以相对于当前位置和绝对位置向前和向后移动。The field ResultSet.CONCUR_UPDATABLE creates a ResultSet object that can be updated. 字段ResultSet.CONCUR_UPDATABLE创建一个可以更新的ResultSet对象。See the ResultSet Javadoc for other fields you can specify to modify the behavior of ResultSet objects.请参阅ResultSet Javadoc,了解可以指定用于修改ResultSet对象行为的其他字段。

The method ResultSet.updateFloat updates the specified column (in this example, PRICE with the specified float value in the row where the cursor is positioned. 方法ResultSet.updateFloat使用游标所在行中指定的float值更新指定列(在本例中为PRICE)。ResultSet contains various updater methods that enable you to update column values of various data types. ResultSet包含各种更新程序方法,使您能够更新各种数据类型的列值。However, none of these updater methods modifies the database; you must call the method ResultSet.updateRow to update the database.但是,这些更新程序方法都不会修改数据库;必须调用ResultSet.updateRow方法来更新数据库。

Using Statement Objects for Batch Updates使用语句对象进行批更新

Statement, PreparedStatement and CallableStatement objects have a list of commands that is associated with them. StatementPreparedStatementCallableStatement对象具有与其关联的命令列表。This list may contain statements for updating, inserting, or deleting a row; and it may also contain DDL statements such as CREATE TABLE and DROP TABLE. 此列表可能包含用于更新、插入或删除行的语句;它还可能包含DDL语句,如CREATE TABLEDROP TABLEIt cannot, however, contain a statement that would produce a ResultSet object, such as a SELECT statement. 但是,它不能包含将生成ResultSet对象的语句,例如SELECT语句。In other words, the list can contain only statements that produce an update count.换句话说,列表只能包含生成更新计数的语句。

The list, which is associated with a Statement object at its creation, is initially empty. 创建时与Statement对象关联的列表最初为空。You can add SQL commands to this list with the method addBatch and empty it with the method clearBatch. 您可以使用addBatch方法将SQL命令添加到此列表,并使用clearBatch方法将其清空。When you have finished adding statements to the list, call the method executeBatch to send them all to the database to be executed as a unit, or batch.将语句添加到列表后,调用executeBatch方法将它们全部发送到数据库,作为一个单元或批处理执行。

For example, the following method CoffeesTable.batchUpdate adds four rows to the COFFEES table with a batch update:例如,以下方法CoffeesTable.batchUpdate通过批更新将四行添加到COFFEES表中:

public void batchUpdate() throws SQLException {
    con.setAutoCommit(false);
    try (Statement stmt = con.createStatement()) {

      stmt.addBatch("INSERT INTO COFFEES " +
                    "VALUES('Amaretto', 49, 9.99, 0, 0)");
      stmt.addBatch("INSERT INTO COFFEES " +
                    "VALUES('Hazelnut', 49, 9.99, 0, 0)");
      stmt.addBatch("INSERT INTO COFFEES " +
                    "VALUES('Amaretto_decaf', 49, 10.99, 0, 0)");
      stmt.addBatch("INSERT INTO COFFEES " +
                    "VALUES('Hazelnut_decaf', 49, 10.99, 0, 0)");

      int[] updateCounts = stmt.executeBatch();
      con.commit();
    } catch (BatchUpdateException b) {
      JDBCTutorialUtilities.printBatchUpdateException(b);
    } catch (SQLException ex) {
      JDBCTutorialUtilities.printSQLException(ex);
    } finally {
      con.setAutoCommit(true);
    }
  }

The following line disables auto-commit mode for the Connection object con so that the transaction will not be automatically committed or rolled back when the method executeBatch is called.下一行禁用Connection对象con的自动提交模式,以便在调用方法executeBatch时不会自动提交或回滚事务。

con.setAutoCommit(false);

To allow for correct error handling, you should always disable auto-commit mode before beginning a batch update.为了允许正确的错误处理,您应该在开始批处理更新之前始终禁用自动提交模式。

The method Statement.addBatch adds a command to the list of commands associated with the Statement object stmt. 方法Statement.addBatch将命令添加到与Statement对象stmt关联的命令列表中。In this example, these commands are all INSERT INTO statements, each one adding a row consisting of five column values. 在本例中,这些命令都是INSERT INTO语句,每个命令添加一行,该行由五个列值组成。The values for the columns COF_NAME and PRICE are the name of the coffee and its price, respectively. COF_NAMEPRICE列的值分别是咖啡的名称和价格。The second value in each row is 49 because that is the identification number for the supplier, Superior Coffee. 每行的第二个值是49,因为这是供应商Superior Coffee的标识号。The last two values, the entries for the columns SALES and TOTAL, all start out being zero because there have been no sales yet. 最后两个值,即SALESTOTAL列的条目,由于还没有销售,所有值都开始为零。(SALES is the number of pounds of this row's coffee sold in the current week; TOTAL is the total of all the cumulative sales of this coffee.)SALES是指该行咖啡在本周售出的磅数;TOTAL是该咖啡所有累计销售额的总和。)

The following line sends the four SQL commands that were added to its list of commands to the database to be executed as a batch:下一行将添加到其命令列表中的四个SQL命令发送到要作为批处理执行的数据库:

int[] updateCounts = stmt.executeBatch();

Note that stmt uses the method executeBatch to send the batch of insertions, not the method executeUpdate, which sends only one command and returns a single update count. 请注意,stmt使用方法executeBatch发送插入批,而不是方法executeUpdate,后者只发送一个命令并返回一个更新计数。The DBMS executes the commands in the order in which they were added to the list of commands, so it will first add the row of values for Amaretto, then add the row for Hazelnut, then Amaretto decaf, and finally Hazelnut decaf. DBMS按照命令添加到命令列表的顺序执行命令,因此它将首先为Amaretto添加值行,然后为Hazelnut添加值行,然后为Amaretto decaf添加值行,最后为Hazelnut decaf添加值行。If all four commands execute successfully, the DBMS will return an update count for each command in the order in which it was executed. 如果所有四个命令都成功执行,DBMS将按照执行顺序返回每个命令的更新计数。The update counts that indicate how many rows were affected by each command are stored in the array updateCounts.表示每个命令影响多少行的更新计数存储在数组updateCounts中。

If all four of the commands in the batch are executed successfully, updateCounts will contain four values, all of which are 1 because an insertion affects one row. 如果批处理中的所有四个命令都成功执行,updateCounts将包含四个值,因为插入会影响一行,所以所有值都是1。The list of commands associated with stmt will now be empty because the four commands added previously were sent to the database when stmt called the method executeBatch. stmt关联的命令列表现在将为空,因为以前添加的四个命令是在stmt调用方法executeBatch时发送到数据库的。You can at any time explicitly empty this list of commands with the method clearBatch.您可以随时使用clearBatch方法显式清空此命令列表。

The Connection.commit method makes the batch of updates to the COFFEES table permanent. Connection.commit方法使对COFFEES表的批量更新永久化。This method needs to be called explicitly because the auto-commit mode for this connection was disabled previously.需要显式调用此方法,因为此连接的自动提交模式以前已禁用。

The following line enables auto-commit mode for the current Connection object.下一行为当前Connection对象启用自动提交模式。

con.setAutoCommit(true);

Now each statement in the example will automatically be committed after it is executed, and it no longer needs to invoke the method commit.现在,示例中的每个语句将在执行后自动提交,并且不再需要调用commit方法。

Performing Parameterized Batch Update执行参数化批处理更新

It is also possible to have a parameterized batch update, as shown in the following code fragment, where con is a Connection object:还可以进行参数化批量更新,如以下代码片段所示,其中conConnection对象:

con.setAutoCommit(false);
PreparedStatement pstmt = con.prepareStatement(
                              "INSERT INTO COFFEES VALUES( " +
                              "?, ?, ?, ?, ?)");
pstmt.setString(1, "Amaretto");
pstmt.setInt(2, 49);
pstmt.setFloat(3, 9.99);
pstmt.setInt(4, 0);
pstmt.setInt(5, 0);
pstmt.addBatch();

pstmt.setString(1, "Hazelnut");
pstmt.setInt(2, 49);
pstmt.setFloat(3, 9.99);
pstmt.setInt(4, 0);
pstmt.setInt(5, 0);
pstmt.addBatch();

// ... and so on for each new
// type of coffee

int[] updateCounts = pstmt.executeBatch();
con.commit();
con.setAutoCommit(true);

Handling Batch Update Exceptions处理批更新异常

You will get a BatchUpdateException when you call the method executeBatch if (1) one of the SQL statements you added to the batch produces a result set (usually a query) or (2) one of the SQL statements in the batch does not execute successfully for some other reason.如果(1)添加到批处理中的某个SQL语句生成结果集(通常为查询)或(2)批处理中的某个SQL语句由于某些其他原因未成功执行,则在调用方法executeBatch时,您将获得BatchUpdateException

You should not add a query (a SELECT statement) to a batch of SQL commands because the method executeBatch, which returns an array of update counts, expects an update count from each SQL statement that executes successfully. 您不应该将查询(SELECT语句)添加到一批SQL命令中,因为返回更新计数数组的方法executeBatch希望成功执行的每个SQL语句都有一个更新计数。This means that only commands that return an update count (commands such as INSERT INTO, UPDATE, DELETE) or that return 0 (such as CREATE TABLE, DROP TABLE, ALTER TABLE) can be successfully executed as a batch with the executeBatch method.这意味着只有返回更新计数的命令(如INSERT INTOUPDATEDELETE等命令)或返回0的命令(如CREATE TABLEDROP TABLEALTER TABLE)才能使用executeBatch方法作为批处理成功执行。

A BatchUpdateException contains an array of update counts that is similar to the array returned by the method executeBatch. BatchUpdateException包含更新计数数组,该数组类似于方法executeBatch返回的数组。In both cases, the update counts are in the same order as the commands that produced them. 在这两种情况下,更新计数的顺序与生成它们的命令的顺序相同。This tells you how many commands in the batch executed successfully and which ones they are. 这将告诉您批处理中有多少命令成功执行,以及它们是哪些命令。For example, if five commands executed successfully, the array will contain five numbers: the first one being the update count for the first command, the second one being the update count for the second command, and so on.例如,如果成功执行了五个命令,数组将包含五个数字:第一个是第一个命令的更新计数,第二个是第二个命令的更新计数,依此类推。

BatchUpdateException is derived from SQLException. BatchUpdateException是从SQLException派生的。This means that you can use all of the methods available to an SQLException object with it. 这意味着您可以使用SQLException对象可用的所有方法。The following method, JDBCTutorialUtilities.printBatchUpdateException prints all of the SQLException information plus the update counts contained in a BatchUpdateException object. 以下方法JDBCTutorialUtilities.printBatchUpdateException打印所有SQLException信息以及BatchUpdateException对象中包含的更新计数。Because BatchUpdateException.getUpdateCounts returns an array of int, the code uses a for loop to print each of the update counts:由于BatchUpdateException.getUpdateCounts返回int数组,因此代码使用for循环打印每个更新计数:

public static void printBatchUpdateException(BatchUpdateException b) {
    System.err.println("----BatchUpdateException----");
    System.err.println("SQLState:  " + b.getSQLState());
    System.err.println("Message:  " + b.getMessage());
    System.err.println("Vendor:  " + b.getErrorCode());
    System.err.print("Update counts:  ");
    int[] updateCounts = b.getUpdateCounts();
    for (int i = 0; i < updateCounts.length; i++) {
      System.err.print(updateCounts[i] + "   ");
    }
  }

Inserting Rows in ResultSet Objects在ResultSet对象中插入行

Note: Not all JDBC drivers support inserting new rows with the ResultSet interface. :并非所有JDBC驱动程序都支持使用ResultSet接口插入新行。If you attempt to insert a new row and your JDBC driver database does not support this feature, a SQLFeatureNotSupportedException exception is thrown.如果尝试插入新行,而JDBC驱动程序数据库不支持此功能,则会引发SQLFeatureNotSupportedException异常。

The following method, CoffeesTable.insertRow, inserts a row into the COFFEES through a ResultSet object:以下方法CoffeesTable.insertRow通过ResultSet对象将一行插入COFFEES中:

public void insertRow(String coffeeName, int supplierID, float price,
                        int sales, int total) throws SQLException {
    
    try (Statement stmt =
          con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE))
    {      
      ResultSet uprs = stmt.executeQuery("SELECT * FROM COFFEES");
      uprs.moveToInsertRow();
      uprs.updateString("COF_NAME", coffeeName);
      uprs.updateInt("SUP_ID", supplierID);
      uprs.updateFloat("PRICE", price);
      uprs.updateInt("SALES", sales);
      uprs.updateInt("TOTAL", total);

      uprs.insertRow();
      uprs.beforeFirst();

    } catch (SQLException e) {
      JDBCTutorialUtilities.printSQLException(e);
    }
  }

This example calls the Connection.createStatement method with two arguments, ResultSet.TYPE_SCROLL_SENSITIVE and ResultSet.CONCUR_UPDATABLE. 此示例使用两个参数调用Connection.createStatement方法,即ResultSet.TYPE_SCROLL_SENSITIVEResultSet.CONCUR_UPDATABLEThe first value enables the cursor of the ResultSet object to be moved both forward and backward. 第一个值使ResultSet对象的游标能够前后移动。The second value, ResultSet.CONCUR_UPDATABLE, is required if you want to insert rows into a ResultSet object; it specifies that it can be updatable.如果要在ResultSet对象中插入行,则需要第二个值ResultSet.CONCUR_UPDATABLE;它指定它是可更新的。

The same stipulations for using strings in getter methods also apply to updater methods.在getter方法中使用字符串的相同规定也适用于updater方法。

The method ResultSet.moveToInsertRow moves the cursor to the insert row. 方法ResultSet.moveToInsertRow将游标移动到插入行。The insert row is a special row associated with an updatable result set. 插入行是与可更新结果集关联的特殊行。It is essentially a buffer where a new row can be constructed by calling the updater methods prior to inserting the row into the result set. 它本质上是一个缓冲区,在将行插入结果集中之前,可以通过调用updater方法来构造新行。For example, this method calls the method ResultSet.updateString to update the insert row's COF_NAME column to Kona.例如,此方法调用方法ResultSet.updateString将插入行的COF_NAME列更新为Kona

The method ResultSet.insertRow inserts the contents of the insert row into the ResultSet object and into the database.方法ResultSet.insertRow将插入行的内容插入ResultSet对象和数据库。

Note: After inserting a row with the ResultSet.insertRow, you should move the cursor to a row other than the insert row. :插入带有ResultSet.insertRow的行后,应将游标移动到插入行以外的行。For example, this example moves it to before the first row in the result set with the method ResultSet.beforeFirst. 例如,本例使用ResultSet.beforeFirst方法将其移动到结果集中第一行之前。Unexpected results can occur if another part of your application uses the same result set and the cursor is still pointing to the insert row.如果应用程序的另一部分使用相同的结果集,并且游标仍指向插入行,则可能会出现意外结果。


Previous page: Setting Up Tables
Next page: Using Prepared Statements