JDBC的结果集
以下内容引用自http://wiki.jikexueyuan.com/project/jdbc/result-sets.html:
SQL语句从数据库查询中获取数据,并将数据返回到结果集中。SELECT语句是一种标准的方法,它从一个数据库中选择行记录,并显示在一个结果集中。java.sql.ResultSet接口表示一个数据库查询的结果集。
一个ResultSet对象控制一个光标指向当前行的结果集。术语“结果集”是指包含在ResultSet对象中的行和列的数据。
ResultSet接口的方法可细分为三类:
- 导航方法(Navigational):用于移动光标。
- 获取方法(Get):用于查看当前行被光标所指向的列中的数据。
- 更新方法(Update):用于更新当前行的列中的数据。这些更新也会更新数据库中的数据。
光标的移动基于ResultSet的属性。用相应的语句生成ResultSet对象时,同时生成ResultSet的属性。
JDBC提供了连接方法通过下列创建语句来生成所需的ResultSet对象:
- createStatement(int RSType, int RSConcurrency);
- prepareStatement(String SQL, int RSType, int RSConcurrency);
- prepareCall(String sql, int RSType, int RSConcurrency);
第一个参数表示ResultSet对象的类型,第二个参数是两个ResultSet常量之一,该常量用于判断该结果集是只读的还是可修改的。
一、ResultSet的类型
可能的RSType如下所示。如果不指定ResultSet类型,将自动获得的值是TYPE_FORWARD_ONLY。
类型 | 描述 |
---|---|
ResultSet.TYPE_FORWARD_ONLY | 光标只能在结果集中向前移动。 |
ResultSet.TYPE_SCROLL_INSENSITIVE | 光标可以向前和向后移动。当结果集创建后,其他人对数据库的操作不会影响结果集的数据。 |
ResultSet.TYPE_SCROLL_SENSITIVE. | 光标可以向前和向后移动。当结果集创建后,其他人对数据库的操作会影响结果集的数据。 |
二、ResultSet的并发性
RSConcurrency的值如下所示,如果不指定并发类型,将自动获得的值是CONCUR_READ_ONLY。
并发性 | 描述 |
---|---|
ResultSet.CONCUR_READ_ONLY | 创建一个只读结果集,这是默认的值。 |
ResultSet.CONCUR_UPDATABLE | 创建一个可修改的结果集。 |
到目前为止示例可以如下所示,可以写成初始化一个Statement对象来创建一个只能前进,而且只读的ResultSet对象:
try { Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); } catch(Exception ex) { .... } finally { .... }
三、导航结果集
在ResultSet接口中包括如下几种方法涉及移动光标:
方法 | 描述 |
---|---|
public void beforeFirst() throws SQLException |
将光标移动到第一行之前。 |
public void afterLast() throws SQLException |
将光标移动到最后一行之后。 |
public boolean first() throws SQLException |
将光标移动到第一行。 |
public void last() throws SQLException |
将光标移动到最后一行。 |
public boolean absolute(int row) throws SQLException |
将光标移动到指定的第row行。 |
public boolean relative(int row) throws SQLException |
将光标移动到当前指向的位置往前或往后第row行的位置。 |
public boolean previous() throws SQLException |
将光标移动到上一行,如果超过结果集的范围则返回false。 |
public boolean next() throws SQLException |
将光标移动到下一行,如果是结果集的最后一行则返回false。 |
public int getRow() throws SQLException |
返回当前光标指向的行数的值。 |
public void moveToInsertRow() throws SQLException |
将光标移动到结果集中指定的行,可以在数据库中插入新的一行。当前光标位置将被记住。 |
public void moveToCurrentRow() throws SQLException |
如果光标处于插入行,则将光标返回到当前行,其他情况下,这个方法不执行任何操作。 |
示例:
//STEP 1. Import required packages import java.sql.*; public class JDBCExample { // JDBC driver name and database URL static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost/Test?serverTimezone=UTC"; // Database credentials static final String USER = "root"; static final String PASS = "root"; public static void main(String[] args) { Connection conn = null; Statement stmt = null; try { // STEP 2: Register JDBC driver Class.forName("com.mysql.jdbc.Driver"); // STEP 3: Open a connection System.out.println("Connecting to database..."); conn = DriverManager.getConnection(DB_URL, USER, PASS); // STEP 4: Execute a query to create statment with // required arguments for RS example. System.out.println("Creating statement..."); stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); String sql; sql = "SELECT id, first, last, age FROM Employees"; ResultSet rs = stmt.executeQuery(sql); // Move cursor to the last row. System.out.println("Moving cursor to the last..."); rs.last(); // STEP 5: Extract data from result set System.out.println("Displaying record..."); // Retrieve by column name int id = rs.getInt("id"); int age = rs.getInt("age"); String first = rs.getString("first"); String last = rs.getString("last"); // Display values System.out.print("ID: " + id); System.out.print(", Age: " + age); System.out.print(", First: " + first); System.out.println(", Last: " + last); // Move cursor to the first row. System.out.println("Moving cursor to the first row..."); rs.first(); // STEP 6: Extract data from result set System.out.println("Displaying record..."); // Retrieve by column name id = rs.getInt("id"); age = rs.getInt("age"); first = rs.getString("first"); last = rs.getString("last"); // Display values System.out.print("ID: " + id); System.out.print(", Age: " + age); System.out.print(", First: " + first); System.out.println(", Last: " + last); // Move cursor to the first row. System.out.println("Moving cursor to the next row..."); rs.next(); // STEP 7: Extract data from result set System.out.println("Displaying record..."); id = rs.getInt("id"); age = rs.getInt("age"); first = rs.getString("first"); last = rs.getString("last"); // Display values System.out.print("ID: " + id); System.out.print(", Age: " + age); System.out.print(", First: " + first); System.out.println(", Last: " + last); // STEP 8: Clean-up environment rs.close(); stmt.close(); conn.close(); } catch (SQLException se) { // Handle errors for JDBC se.printStackTrace(); } catch (Exception e) { // Handle errors for Class.forName e.printStackTrace(); } finally { // finally block used to close resources try { if (stmt != null) stmt.close(); } catch (SQLException se2) { } // nothing we can do try { if (conn != null) conn.close(); } catch (SQLException se) { se.printStackTrace(); } // end finally try } // end try System.out.println("Goodbye!"); }// end main }// end JDBCExample
这将产生如下所示结果:
四、查看结果集
ResultSet接口中含有几十种从当前行获取数据的方法。
每个可能的数据类型都有一个get方法,并且每个get方法有两个版本:
- 一个需要列名。
- 一个需要列的索引。
例如,如果想查看的列包含一个int类型,需要在ResultSet中调用getInt()方法:
方法 | 描述 |
---|---|
public int getInt(String columnName) throws SQLException |
返回当前行中名为columnName的列的int值。 |
public int getInt(int columnIndex) throws SQLException |
返回当前行中指定列的索引的int值。列索引从1开始,意味着行中的第一列是1 ,第二列是2 ,以此类推。 |
同样的,在ResultSet接口中还有获取八个Java原始类型的get方法,以及常见的类型,比如java.lang.String,java.lang.Object和java.net.URL。
也有用于获取SQL数据类型java.sql.Date,java.sql.Time,java.sql.Timestamp,java.sql.Clob,java.sql.Blob中的方法。查看官方Java文档可以了解使用这些SQL数据类型的更多的信息。
示例:
//STEP 1. Import required packages import java.sql.*; public class JDBCExample2 { // JDBC driver name and database URL static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost/Test?serverTimezone=UTC"; // Database credentials static final String USER = "root"; static final String PASS = "root"; public static void main(String[] args) { Connection conn = null; Statement stmt = null; try { // STEP 2: Register JDBC driver Class.forName("com.mysql.jdbc.Driver"); // STEP 3: Open a connection System.out.println("Connecting to database..."); conn = DriverManager.getConnection(DB_URL, USER, PASS); // STEP 4: Execute a query to create statment with // required arguments for RS example. System.out.println("Creating statement..."); stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); String sql; sql = "SELECT id, first, last, age FROM Employees"; ResultSet rs = stmt.executeQuery(sql); // Move cursor to the last row. System.out.println("Moving cursor to the last..."); rs.last(); // STEP 5: Extract data from result set System.out.println("Displaying record..."); // Retrieve by column name int id = rs.getInt("id"); int age = rs.getInt("age"); String first = rs.getString("first"); String last = rs.getString("last"); // Display values System.out.print("ID: " + id); System.out.print(", Age: " + age); System.out.print(", First: " + first); System.out.println(", Last: " + last); // Move cursor to the first row. System.out.println("Moving cursor to the first row..."); rs.first(); // STEP 6: Extract data from result set System.out.println("Displaying record..."); // Retrieve by column name id = rs.getInt("id"); age = rs.getInt("age"); first = rs.getString("first"); last = rs.getString("last"); // Display values System.out.print("ID: " + id); System.out.print(", Age: " + age); System.out.print(", First: " + first); System.out.println(", Last: " + last); // Move cursor to the first row. System.out.println("Moving cursor to the next row..."); rs.next(); // STEP 7: Extract data from result set System.out.println("Displaying record..."); id = rs.getInt(1);//The first column index age = rs.getInt("age"); first = rs.getString("first"); last = rs.getString("last"); // Display values System.out.print("ID: " + id); System.out.print(", Age: " + age); System.out.print(", First: " + first); System.out.println(", Last: " + last); // STEP 8: Clean-up environment rs.close(); stmt.close(); conn.close(); } catch (SQLException se) { // Handle errors for JDBC se.printStackTrace(); } catch (Exception e) { // Handle errors for Class.forName e.printStackTrace(); } finally { // finally block used to close resources try { if (stmt != null) stmt.close(); } catch (SQLException se2) { } // nothing we can do try { if (conn != null) conn.close(); } catch (SQLException se) { se.printStackTrace(); } // end finally try } // end try System.out.println("Goodbye!"); }// end main }// end JDBCExample
这将产生如下所示结果:
五、更新的结果集
ResultSet接口包含了一系列的更新方法,该方法用于更新结果集中的数据。
用get方法可以有两个更新方法来更新任一数据类型:
- 一个需要列名。
- 一个需要列的索引。
例如,要更新一个结果集的当前行的String列,可以使用任一如下所示的updateString()方法:
方法 | 描述 |
---|---|
public void updateString(int columnIndex, String s) throws SQLException |
将指定列的字符串的值改为s。 |
public void updateString(String columnName, String s) throws SQLException |
类似于前面的方法,不同之处在于指定的列是用名字来指定的,而不是它的索引。 |
八个原始数据类型都有其更新方法,比如String,Object,URL,和在java.sql包中的SQL数据类型。
更新结果集中的行将改变当前行的列中的ResultSet对象,而不是基础数据库中的数据。要更新数据库中一行的数据,需要调用以下的任一方法:
方法 | 描述 |
---|---|
public void updateRow() |
通过更新数据库中相对应的行来更新当前行。 |
public void deleteRow() |
从数据库中删除当前行。 |
public void refreshRow() |
在结果集中刷新数据,以反映数据库中最新的数据变化。 |
public void cancelRowUpdates() |
取消对当前行的任何修改。 |
public void insertRow() |
在数据库中插入一行。本方法只有在光标指向插入行的时候才能被调用。 |
示例:
//STEP 1. Import required packages import java.sql.*; public class JDBCExample3 { // JDBC driver name and database URL static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost/Test?serverTimezone=UTC"; // Database credentials static final String USER = "root"; static final String PASS = "root"; public static void main(String[] args) { Connection conn = null; try { // STEP 2: Register JDBC driver Class.forName("com.mysql.jdbc.Driver"); // STEP 3: Open a connection System.out.println("Connecting to database..."); conn = DriverManager.getConnection(DB_URL, USER, PASS); // STEP 4: Execute a query to create statment with // required arguments for RS example. System.out.println("Creating statement..."); Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); // STEP 5: Execute a query String sql = "SELECT id, first, last, age FROM Employees"; ResultSet rs = stmt.executeQuery(sql); System.out.println("List result set for reference...."); printRs(rs); // STEP 6: Loop through result set and add 5 in age // Move to BFR postion so while-loop works properly rs.beforeFirst(); // STEP 7: Extract data from result set while (rs.next()) { // Retrieve by column name int newAge = rs.getInt("age") + 5; rs.updateDouble("age", newAge); rs.updateRow(); } System.out.println("List result set showing new ages..."); printRs(rs); // Insert a record into the table. // Move to insert row and add column data with updateXXX() System.out.println("Inserting a new record..."); rs.moveToInsertRow(); rs.updateInt("id", 104); rs.updateString("first", "John"); rs.updateString("last", "Paul"); rs.updateInt("age", 40); // Commit row rs.insertRow(); System.out.println("List result set showing new set..."); printRs(rs); // Delete second record from the table. // Set position to second record first rs.absolute(2); System.out.println("List the record before deleting..."); // Retrieve by column name int id = rs.getInt("id"); int age = rs.getInt("age"); String first = rs.getString("first"); String last = rs.getString("last"); // Display values System.out.print("ID: " + id); System.out.print(", Age: " + age); System.out.print(", First: " + first); System.out.println(", Last: " + last); // Delete row rs.deleteRow(); System.out.println("List result set after deleting one records..."); printRs(rs); // STEP 8: Clean-up environment rs.close(); stmt.close(); conn.close(); } catch (SQLException se) { // Handle errors for JDBC se.printStackTrace(); } catch (Exception e) { // Handle errors for Class.forName e.printStackTrace(); } finally { // finally block used to close resources try { if (conn != null) conn.close(); } catch (SQLException se) { se.printStackTrace(); } // end finally try } // end try System.out.println("Goodbye!"); }// end main public static void printRs(ResultSet rs) throws SQLException { // Ensure we start with first row rs.beforeFirst(); while (rs.next()) { // Retrieve by column name int id = rs.getInt("id"); int age = rs.getInt("age"); String first = rs.getString("first"); String last = rs.getString("last"); // Display values System.out.print("ID: " + id); System.out.print(", Age: " + age); System.out.print(", First: " + first); System.out.println(", Last: " + last); } System.out.println(); }// end printRs() }// end JDBCExample
这将产生如下所示结果:
测试工程:https://github.com/easonjim/5_java_example/tree/master/jdbcbasics/test2