Tags:

Đọc dữ liệu từ database vào ResultSet trong JDBC

Trong SQL mệnh đề SELECT được dùng để truy vấn dữ liệu, kết quả trả về sẽ là một tập các dòng dữ liệu phù hợp với điều kiện đã cho hoặc là tất cả các dòng chứa trong bảng nếu không có điều kiện nào được đi kèm. ResultSet interface đại diện cho một tập kết quả trả về từ câu truy vấn SELECT này.

Một ResultSet object duy trì một con trỏ trỏ đến dòng dữ liệu hiện tại trong tập kết quả. Tương ứng với mỗi dòng sẽ có các cột tương ứng mà mệnh đề SELECT trả về.

Trong ResultSet có 3 hoạt động chính:

  • Navigational methods – dùng để duy chuyển con trỏ đến các dòng dữ liệu khác trong tập kết quả
  • Get methods – dùng để xem dữ liệu của dòng hiện tại đang được con trỏ trỏ đến thông qua các cột xác định.
  • Update methods – dùng để cập nhập dữ liệu trong các cột tương ứng với dòng hiện tại. Những thay đổi này có thể đồng bộ xuống database.

Con trỏ có thể di chuyển dựa trên các thuộc tính của ResultSet. Các thuộc tính này xác định thông qua các method dùng để tạo ra các Statement.

  • createStatement(int RSType, int RSConcurrency).

  • prepareStatement(String SQL, int RSType, int RSConcurrency);

  • prepareCall(String sql, int RSType, int RSConcurrency);

Trong đó RSType được dùng để chỉ định kiểu ResultSet object và RSConcurrency quyết định xem tập kết quả có được cập nhật hay chỉ dạng read-only.

Type Description
ResultSet.TYPE_FORWARD_ONLY Con trỏ chỉ có thể di chuyển đến phần tử tiếp theo trong tập kết quả, không thể lùi lại
ResultSet.TYPE_SCROLL_INSENSITIVE Con trỏ có thể di chuyển tới hoặc lui trong tập kết quả. Khi có những thay đổi dưới database thì tập dữ liệu này sẽ không được cập nhật theo đó.
ResultSet.TYPE_SCROLL_SENSITIVE. Con trỏ có thể di chuyển tới hoặc lui trong tập kết quả. Khi có những thay đổi dưới database thì tập dữ liệu này sẽ được cập nhật theo đó.

RSConcurrency bao gồm 2 thuộc tính với ý nghĩa sẽ được liệt kê ngay sau đây. Nếu bạn không chỉ định bất kỳ loại Concurrency nào, giá trị mặc định là CONCUR_READ_ONLY.

Concurrency Description
ResultSet.CONCUR_READ_ONLY Khởi tạo một tập dữ liệu read-only
ResultSet.CONCUR_UPDATABLE Khởi tạo một tập dữ liệu có thể được chỉnh sửa

Ví dụ tạo một Statement mà tập ResultSet trả về có con trỏ chỉ có thể di chuyển tuần tự đến các phần tử tiếp theo, và chỉ được đọc dữ liệu mà không thể chỉnh sửa.

try {
   Statement stmt = conn.createStatement(
                           ResultSet.TYPE_FORWARD_ONLY,
                           ResultSet.CONCUR_READ_ONLY);
}
catch(Exception ex) {
   ....
}
finally {
   ....
}

Duyệt từng phần tử trong ResultSet

Để duyệt từng phần tử tương ứng với mỗi dòng kết quả trả về, chúng ta sẽ gọi next() method. next() trả về true nếu ResultSet còn tồn tại những phần tử tiếp theo và đồng thời di chuyển con trỏ đến phần tử đó. Nếu không còn một phần tử nào nữa, hàm next() trả về false và bạn không thể thực hiện được nữa. Khi phương thức next() trả về false, bạn không nên gọi nó thêm nữa. Làm như vậy có thể dẫn đến một ngoại lệ.

while(result.next()) {
    // ... get column values from this record
}

Như các bạn thấy, hàm next() sẽ được gọi trước khi chúng ta truy xuất dữ liệu từ các cột tương ứng với dòng hiện tại. Tại lần đầu chạy, hàm này sẽ chuyển con trỏ đến phần tử đầu tiên trong ResultSet.

Tương tự như vậy, khi next() được gọi và trả về false có nghĩa là chúng ta đã đi đến phần tử cuối cùng trong Resultset.

Truy cập các cột trong ResultSet

Khi duyệt qua các dòng dữ liệu trong ResultSet, các bạn có thể truy cập dữ liệu của từng cột tương ứng thông qua các getter method được ResultSet cung cấp sẵn.

while(result.next()) {

    result.getString    ("name");
    result.getInt       ("age");
    result.getBigDecimal("coefficient");

    // etc.
}

Có rất nhiều getter method được xây dựng để lấy các kiểu dữ liệu khác nhau trong Java như Boolean, Int, Long, Double, BigDecimal v.v

result.getArray("columnName");
result.getAsciiStream("columnName");
result.getBigDecimal("columnName");
result.getBinaryStream("columnName");
result.getBlob("columnName");
result.getBoolean("columnName");
result.getBlob("columnName");
result.getBoolean("columnName");
result.getByte("columnName");
result.getBytes("columnName");
result.getCharacterStream("columnName");
result.getClob("columnName");
result.getDate("columnName");
result.getDouble("columnName");
result.getFloat("columnName");
result.getInt("columnName");
result.getLong("columnName");
result.getNCharacterStream("columnName");
result.getObject("columnName");
result.getRef("columnName");
result.getRowId("columnName");
result.getShort("columnName");
result.getSQLXML("columnName");
result.getString("columnName");
result.getTime("columnName");
result.getTimestamp("columnName");
result.getUnicodeStream("columnName");
result.getURL("columnName");

Ngoài việc chỉ định tên các cột cùng lấy, thì chúng ta cũng có thể sử dụng index, tuy nhiên cách này không được khuyến khích sử dụng vì dễ gây lỗi, và khiến cho mã nguồn khó đọc hiểu.

while(result.next()) {

    result.getString    (1);
    result.getInt       (2);
    result.getBigDecimal(3);

    // etc.
}

Navigation method

ResultSet chứa các hàm điều hướng sau. Hãy nhớ rằng, không phải tất cả các phương pháp đều hoạt động với tất cả các loại ResultSet. Phương thức nào hoạt động phụ thuộc vào cơ sở dữ liệu, trình điều khiển JDBC và kiểu ResultSet của bạn

S.N. Methods & Description
1 public void beforeFirst() throws SQLException

Di chuyển con trỏ đến trước dòng đầu tiên

2 public void afterLast() throws SQLException

Di chuyển con trỏ đến ngay sau dòng cuối cùng

3 public boolean first() throws SQLException

Di chuyển con trỏ đến dòng đầu tiên

4 public void last() throws SQLException

Di chuyển con trỏ đến dòng cuối cùng

5 public boolean absolute(int row) throws SQLException

Di chuyển con trỏ đến một dòng có index = row.

6 public boolean relative(int row) throws SQLException

Di chuyển con trỏ tới một dòng nhất định về phía trước hoặc phía sau, từ vị trí nó hiện đang trỏ.

7 public boolean previous() throws SQLException

Di chuyển con trỏ đến hàng trước đó. Phương thức này trả về false nếu hàng trước đó nằm ngoài tập kết quả

8 public boolean next() throws SQLException

Di chuyển con trỏ đến hàng tiếp theo. Phương thức này trả về false nếu không còn hàng nào trong tập kết quả

9 public int getRow() throws SQLException

Trả về số hàng mà con trỏ đang trỏ tới.

10 public void moveToInsertRow() throws SQLException

Di chuyển con trỏ đến một hàng đặc biệt trong tập kết quả có thể được sử dụng để chèn một hàng mới vào cơ sở dữ liệu. Vị trí con trỏ hiện tại được ghi nhớ.

11 public void moveToCurrentRow() throws SQLException

Di chuyển con trỏ đến một hàng đặc biệt trong tập kết quả có thể được sử dụng để chèn một hàng mới vào cơ sở dữ liệu. Vị trí con trỏ hiện tại được ghi nhớ.

Update ResultSet

Nếu cấu hình ResultSet có thể cập nhật dữ liệu thì chúng ta có thể cập nhật dữ liệu của các cột trong mỗi dòng tương ứng với các update method được dựng sẵn.

 result.updateString     ("name"       , "Alex");
 result.updateInt        ("age"        , 55);
 result.updateBigDecimal ("coefficient", new BigDecimal("0.1323");
 result.updateRow();

Ngoài ra có thể sử dụng vị trí thay cho tên cột

 result.updateString     (1, "Alex");
 result.updateInt        (2, 55);
 result.updateBigDecimal (3, new BigDecimal("0.1323");
 result.updateRow();

Lưu ý: Khi updateRow() được gọi thì cơ sở dữ liệu được cập nhật các giá trị của hàng. Nếu bạn không gọi updateRow() thì những dữ liệu này sẽ không được đồng bộ xuống db. Còn nếu nó được gọi trong một transaction thì những thay đổi sẽ được đồng bộ một lần khi transaction hoàn tất.

Insert ResultSet

Nếu ResultSet có thể cập nhật được, bạn cũng có thể chèn các hàng vào đó. Bạn làm như vậy bằng cách:

  1. Gọi ResultSet.moveToInsertRow()
  2. Cập nhật các giá trị
  3. Gọi ResultSet.insertRow()
result.moveToInsertRow();
result.updateString     (1, "Alex");
result.updateInt        (2, 55);
result.updateBigDecimal (3, new BigDecimal("0.1323");
result.insertRow();

result.beforeFirst();

Nơi được trỏ tới sau khi gọi moveToInsertRow() là một nơi đặc biệt, một vùng bộ nhớ đệm để lưu trữ các dòng dữ liệu mới được thêm vào.

Khi dữ liệu thêm mới đã được chuẩn bị xong, chúng ta có thể gọi insertRow() method để thêm dữ liệu vào db.

Sau khi thêm dữ liệu thành công, con trỏ lúc này vẫn nằm ở vùng nhớ đệm, hãy nhớ dii chuyển con trỏ về đến vị trí hợp lệ ngay sau đó.

Nguồn 

http://tutorials.jenkov.com/jdbc/resultset.html#a-result-set-contains-records

https://www.tutorialspoint.com/jdbc/jdbc-result-sets.htm

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x