通过查询获取记录列表时,我们经常需要将它们存储在允许来回遍历的对象中,并根据需要进行更新。本文通过显式代码和示例场景说明了数据库编程中常用的技术。
关于ResultSet
该结果集是在定义的接口的java.sql包。它表示Statement对象返回的数据表。一个语句对象用于执行SQL查询到数据库。ResultSet对象维护一个指向数据库表中当前记录的游标。因此,它可以有效地用于根据需要使用first(),previous(),next()和last()方法来回定位不同的行。最初,ResultSet对象位于第一行之前的位置。这就是ResultSet的原因 遍历始终如下:
while(resultSet.next()){ // ... }
请注意,在进入循环时,ResultSet对象通过执行next()方法定位在第一行,因为如前所述,ResultSet对象最初位于第一行之前的位置。因此,必须至少放在第一行,例如,获取有效记录。它可以被视为指针/索引指向的数组位置中的值-1。必须首先将其重新定位到至少第0 个位置才能从数组中获取任何类型的有效值。
现在,正如我们已经提到的,我们可以在ResultSet对象的帮助下滚动记录。但是,这种能力默认不会出现。ResultSet对象的默认行为是它不可更新,它拥有的光标实际上只向一个方向移动,仅向前移动。这意味着我们只能在记录中迭代一次并且只能在前进方向上迭代。但是,有一些方法可以使其灵活,以便ResultSet不仅可以更新,而且可以滚动。
我们将在两个单独的程序中看到它们。
可滚动的ResultSet
让我们首先使ResultSet对象可滚动。Scrollable意味着一旦创建了ResultSet对象,我们可以按照我们的喜好遍历任何方向(前向和后向)的已获取记录。这提供了读取最后一条记录,第一条记录,下一条记录和前一条记录的功能。
package org.mano.example; import java.sql.*; public class App { static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost:3306/employees"; static final String USER = "root"; static final String PASS = "secret"; static final String SQL = "SELECT * FROM employees ORDER BY first_name"; public static void main( String[] args ) { Connection connection = null; ResultSet rs = null; try { Class.forName(JDBC_DRIVER); connection = DriverManager.getConnection (DB_URL, USER, PASS); System.out.println("\n1. Connection established"); }catch(Exception ex) { ex.printStackTrace(); } try (PreparedStatement pstmt = connection.prepareStatement(SQL, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);){ System.out.println("\n2. Executing SQL query..."); rs = pstmt.executeQuery(); System.out.println("\n3. ResultSet object created successfully."); System.out.println("\n4. Now some RecordSet scrolling starts..."); rs.first(); show(rs); rs.last(); show(rs); rs.previous(); rs.previous(); show(rs); rs.next(); show(rs); System.out.println("\n\n5. That's all. RecordSet scrolling ends."); }catch(SQLException ex){ ex.printStackTrace(); }finally{ try { connection.close(); }catch(SQLException ex){ } } } public static void show(ResultSet rs) throws SQLException{ System.out.printf ("\n--------------------------------"+ "-------------------------------------"); System.out.printf("\n%7d | %10s | %10s | %s | %s | %s ",rs.getLong("emp_no"), rs.getString("first_name"), rs.getString("last_name"), rs.getDate("birth_date").toString(), rs.getDate("hire_date"), rs.getString("gender")); System.out.printf ("\n---------------------------------"+ "------------------------------------"); } }
产量
- 连接已建立。
- 执行SQL查询...
- ResultSet对象已成功创建。
- 现在,一些RecordSet滚动开始......
-------------------------------------------------- ----------- 497615 | Aamer | 麦克德米德| 1954-11-18 | 1985-04-24 | M ------------------------------------------------- ------------ -------------------------------------- ----------------------- 484995 | Zvonko | Lakshmanan | 1964-11-04 | 1992-12-04 | M ------------------------------------------------- ------------ -------------------------------------- ----------------------- 482000 | Zvonko | Cannata | 1960-11-23 | 1986-08-13 | M ------------------------------------------------- ------------ -------------------------------------- ----------------------- 483497 | Zvonko | Pollacia | 1961-12-26 | 1985-08-01 | 中号 -------------------------------------------------- -----------
5就这样。RecordSet滚动结束。
请注意,可滚动的ResultSet对象是执行通过Statement或PreparedStatement实例获取的executeQuery()方法的结果。我们要创建的ResultSet对象的类型必须通过定义的滚动类型常量显式声明到Statement对象。
- ResultSet.TYPE_FORWARD_ONLY:这是默认类型。
- ResultSet.TYPE_SCROLL_INSENSITIVE:启用来回移动,但对ResultSet更新不敏感。
- ResultSet.TYPE_SCROLL_SENSITIVE:启用来回移动,但对ResultSet更新敏感。
还有其他常量,例如CONCUR_READ_ONLY,这意味着ResultSet不可更新。还有另一个常量CONCUR_UPDATABLE,表示相反,表示ResultSet是可更新的。
可更新的ResultSet
创建可更新的ResultSet意味着它指向的记录不仅可以遍历,而且可以更新。更改将立即保留在数据库中,并由ResultSet对象实时反映。
package org.mano.example; import java.sql.*; public class App { static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost:3306/employees"; static final String USER = "root"; static final String PASS = "secret"; static final String SQL = "SELECT * FROM employees WHERE emp_no = ?"; public static void main( String[] args ) { Connection connection = null; ResultSet rs = null; long emp_no = 484995; try { Class.forName(JDBC_DRIVER); connection = DriverManager.getConnection (DB_URL, USER, PASS); System.out.println("\n1. Connection established"); }catch(Exception ex) { ex.printStackTrace(); } try(PreparedStatement pstmt = connection.prepareStatement(SQL, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);){ pstmt.setLong(1,emp_no); System.out.println("\n2. Executing SQL query..."); rs = pstmt.executeQuery(); System.out.println("\n3. ResultSet object created successfully."); while(rs.next()){ show(rs); String fname = rs.getString("first_name"); System.out.println("\n4. Updating name "+fname+" to Subham"); rs.updateString("first_name", "Subham"); rs.updateRow(); } System.out.println("\n\n5. Record updated. See below."); rs.previous(); show(rs); }catch(SQLException ex){ ex.printStackTrace(); }finally{ try { rs.close(); connection.close(); }catch(SQLException ex){ } } } public static void show(ResultSet rs) throwsSQLException{ System.out.printf ("\n--------------------------------"+ "-------------------------------------"); System.out.printf("\n%7d | %10s | %10s | %s | %s | %s ",rs.getLong("emp_no"), rs.getString("first_name"), rs.getString("last_name"), rs.getDate("birth_date").toString(), rs.getDate("hire_date"), rs.getString("gender")); System.out.printf ("\n---------------------------------"+ "------------------------------------"); } }
当我们想要通过在提取的记录中来回遍历进行一些比较后更新某些值时,可更新的ResultSet特别有用。创建过程与前面的程序类似,但此处使用的ResultSet常量是TYPE_SCROLL_SENSITIVE和CONCUR_UPDATABLE。
结论
与ResultSet的默认行为相反,它使对象具有更大的灵活性。应用程序可以利用此功能不仅遍历记录,还可以使它们可更新,以便它们可以提供更好的服务。尽管与可滚动的ResultSet相比,结果集的标准行为似乎效率很低,但它有其自身的用途,因此是不可替代的。
整理不易,请大家多多关注,您的支持是我最大的动力。