Java Dataset CachedRowSet Phần 3

Rowset jdbc

Chương 3:CachedRowSet

Một cache rowset được dùng để nó có thể hoạt động mà không cần kết nối với dữ liệu nguồn., nó là một đối tượng RowSet disconnected, như tên của nó, dữ liệu sẽ được lưu trong bộ nhớ và nó có thể hoạt động nhanh hơn khi hoạt đông trên database.

Interface cachedRowSet là một interface cha cho tất cả các đối tượng Rowset ngắt kết nối, những điều tương ứng trong chương này hoàn toàn có thể áp dụng cho WebRowSet, JoinRowSet và FilterRowSet.

Cũng lưu ý rằng data source thì thường là cho một csdl quan hệ, tuy nhiên với cachedrowset thì nó có thể nhận dữ liệu từ bất cứ một nguồn nào khác với việc lưu trữ dạng bảng. tuy nhiên ở đây chỉ nói đến datasource cho database.

Setting Up a CachedRowSet Object

Bao gồm : tạo nó, thiết lập các thuộc tính và thiết lập các khóa.

Creating a CachedRowSet Object

Có thể tạo cache Rowset theo 2 cách:

Bằng sử dụng constructor mặc định,

Sử dụng một syncprovider cài đặt đến constructor.

Using the Default Constructor

Một cách để tạo cachedrowset là dùng constructor mặc định, theo đoạn mã sau:

CachedRowSet crs = new CachedRowSetImpl();

Ngoài những thuộc tính của một JdbcRowset nó còn thêm vào một thể hiện của một cài đặt SyncProvider - mặc định, RioptimisticProvider.

Một syncProvider cung cấp một đối tượng RowsetReader – để đọc và một RowsetWriter – cho ghi dữ liệu .

Cả 2 đối tượng RowsetReader và RowsetWriter làm việc hậu cảnh, nó dùng đọc dữ liệu nguồn và ghi ngược trở lại dữ liệu khi có yêu cầu.

Passing a SyncProvider Implementation

Cách thứ 2 để tạo một cachedRowset là sử dụng một syncProvider cài đặt một constructor CachedRowsetImpl().

CachedRowSet crs2 = CachedRowSetImpl("com.fred.providers.HighAvailabilityProvider");

Ví dụ vừa rồi sử dụng com.fred.providers.HighAvaibilityProvider để cài đặt interface SyncProvider . việc cài đặt là reader và writer thì khác từ những cài đặt RIOptimicsticProvider, sẽ bàn sau.

Setting Properties

Để lấy dữ liệu một Rowset disconnect cần kết nối với dữ liệu nguồn và chọn lại dữ liệu để dữ lại. bốn thuộc tính cần thiết để giữ một kết nối tới database.

username—the name a user supplies to a database as part of gaining access

password—the user’s database password

url—the JDBC URL for the database to which the user wants to connect

datasourceName—the name used to retrieve a DataSource object that has been

registered with a JNDI naming service

khi đề cập trong chương tổng quan những thuộc tính thiết lập thì phụ thuộc vào bạn dự định sử dụng kết nối .

một ví dụ về kết nối sử dụng bằng JDBC URL:

crs.setUsername("hardy");

crs.setPassword("oursecret");

crs.setUrl("jdbc:mySubprotocol:mySubname");

một thuộc tính khác cần được thiết lập là command. Dữ liệu trong Rowset được đọc từ ResultSet , câu truy vấn tạo ra ResultSet là giá trị của command

crs.setCommand("select * from COF_INVENTORY");

Setting Key Columns

Để update dữ liệu của cachedrowset lên database. Cần thiết lập một vài thông tin: trong đó có key column. Key column về cơ bản là giống với khóa chính trong database. Đoạn mã sau thiết lập key column cho crs đến cột đầu tiên :

int [] keys = {1};

crs.setKeyColumns(keys);

sẽ rõ hơn khi nghiên cứu trong phần syncprovider.

Populating a CachedRowSet Object

Việc thao tác dữ liệu :

crs.execute();

dữ liệu trong crs là dữ liệu trong ResultSet tạo ra bằng cách thi hành câu query trong thuộc tính command.

Lúc này cachedRowset là một reader.

What a Reader Does

Khi gọi execute() đối tượng đọc của Rowset disconnected làm việc hậu cảnh để thao tác dữ liệu .

Sau khi truy vấn dữ liệu, crs sẽ chứa dữ liệu và kết nối được đóng ngay lập tức bởi SyncProvider.

Updating a CachedRowSet Object

Updating a Column Value

int [] quantity = {873, 927, 985, 482, 358, 531};

int len = quantity.length;

crs.beforeFirst();

while (crs.next()) {

for(int i = 0; i <>

crs.updateInt("QUAN", quantity[i]);

crs.updateRow();

}

}

Sau khi insert một dòng dữ liệu mới, sử dụng phương thức updateRow để lưu giá trị mới vào bộ nhớ.

Inserting and Deleting Rows

Cũng như khi update, insert và Delete cũng như trong JdbcRowset.

crs.moveToInsertRow();

crs.updateInt("WAREHOUSE_ID", 1234);

crs.updateString("COF_NAME", "Supremo");

crs.updateInt("SUP_ID", 150);

crs.updateInt("QUAN", 580);

java.util.Date 2006_04_01 = java.util.Date.valueOf("2006-04-01");

crs.updateDate("DATE", 2006_04_01);

crs.insertRow();

crs.moveToCurrentRow();

lúc này bạn vẫn làm việc xa rời trung tâm đầu não-Database.

while (crs.next()) {

if (crs.getString("COF_NAME").equals("Espresso")) {

crs.deleteRow();

break;

}

}

Sẽ delete Espresso từ crs.

Updating the Data Source

Lúc này vẫn phải nhớ là:

JdbcRowset là connected.

CachedRowset là disconnected.

Cho nên có sự khác biệt về sự thay đổi dữ liệu.

Trong JdbcRowset khi gọi insert, delete, update thì dữ liệu nguồn thay đổi ngay.

Trong CachedRowset khi gọi insert, update, delete thì dữ liệu tồn tại trong bộ nhớ, để thay đổi dữ liệu nguồn gọi phương thức

crs.acceptChanges();

What a Writer Does

Cũng giống như phương thức execute(), acceptChanges làm việc hậu cảnh.

Execute làm việc như một reader, còn acceptChanges làm việc là một writer.

Trong hậu cảnh, writer mở một kết nối update dữ liệu vào database, sau đó đóng kết nối.

Using the Default Implementation

Một khó khăn là sẽ xảy ra xung đột dữ liệu, writer giải quyết đụng độ còn tùy theo cách nó được cài đặt. về bản chất writer thậm chí không kiểm tra đụng độ và chỉ ghi tất cả những thay đổi vào database, đây là trường hợp của RIXMLProvider cái mà sử dụng trong WebRowset.

Một khía cạnh khác writer đảm bảo không có xung đột bằng cách khóa database để ngăn chặn những thay đổi.

Writer cho crs-CachedRowSet được cung cấp bởi syncProvider mặc định là RIOptimisticProvider. Đây hiện là một mô hình tối ưu, nó không cần khóa database, writer kiểm tra nhữg xung đột nếu không có nó sẽ ghi những thay đổi vào database, nếu có xung đột mặc định nó sẽ không ghi gì vào database.

Using a SyncResolver Object

Trong trường hợp nảy sinh xung đột dữ liệu , RioptimisticProvider cung cấp một tùy chọn để xác định được giá trị bị xung đột từ đó xác định việc giải quyết. tùy chọn sử dụng đối tượng Resolver.

try {

crs.acceptChanges();

} catch (SyncProviderException spe) {

SyncResolver resolver = spe.getSyncResolver();

Resolver là một đối tượng Rowset mà là nhân bản của một crs ngoại trừ nó chỉ chứa những giá trị xung đột với database, còn lại là null.

Đoạn mã sau yêu cầu resolver sử dụng phương thức nextConflict để lặp lại những dòng xảy ra xung đột dữ liệu.

Nếu trạng thái resolver là UPDATE_ROW_CONFLICT có nghĩa đã có xung đột xảy ra khi update dữ liệu, resolver sẽ nhận ra số dòng của giá trị bị xung đột, kết hợp với crs ta sẽ tìm ra cột bị xung đột, nó sẽ khác NULL. Chúng ta so sánh 2 đối tượng này.

Đoạn mã thiết lập giá trị cho cả crs và database sử dụng phương thức setResolvedValue

try {

crs.acceptChanges();

} catch (SyncProviderException spe) {

SyncResolver resolver = spe.getSyncResolver();

Object crsValue; // value in crs

Object resolverValue; // value in the SyncResolver object

Object resolvedValue; // value to be persisted

while (resolver.nextConflict()) {

if (resolver.getStatus() == SyncResolver.UPDATE_ROW_CONFLICT) {

int row = resolver.getRow();

crs.absolute(row);

int colCount = crs.getMetaData().getColumnCount();

for (int j = 1; j <= colCount; j++) {

if (resolver.getConflictValue(j) != null) {

crsValue = crs.getObject(j);

resolverValue = resolver.getConflictValue(j);

. . . // compare crsValue and resolverValue to determine the

// value to be persisted

resolvedValue = crsValue;

resolver.setResolvedValue(j, resolvedValue);

}

}

}

}

}

Notifying Listeners

Là một JavaBeans, Rowset có thể thông báo khi có một điều gì đó xảy ra như là dữ liệu trong Rowset thay đổi. một điều tốt lành đối với lập trình viên đó là chúng ta chỉ cần quan tâm add or remove thành phần sẽ được thông báo.

Setting Up Listeners

Một Listerner cho Rowset là một thành phần theo những phương thức từ interface RowSetListerner.

cursorMoved—defines what the listener will do, if anything, when the cursor

in the RowSet object moves

rowChanged—defines what the listener will do, if anything, when one or

more column values in a row have changed, a row has been inserted, or a

row has been deleted

rowSetChanged—defines what the listener will do, if anything, when the

RowSet object has been populated with new data

Một ví dụ về thành phần cần có một listerner là BarGraph, một biểu đồ lấy dữ liệu trong RowSet, khi dữ liệu thay đổi đối tượng BarGraph cũng thay đổi theo và phản ánh dữ liệu.

Đoạn mã sau : mỗi lần cursor cho crs di chuyển , giá trị trong crs thay đổi hay crs nhận dữ liệu mới., BarGraph sẽ được thông báo.

crs.addRowSetListener(bar);

có thể ngừng việc thông báo :

crs.removeRowSetListener(bar);

How Notification Works

Những sự kiện sẽ được tự động thông báo cho tất cả listerner đăng ký nó :

Các phương thức:

Move gọi cursorMoved

Execute gọi RowsetChanged.

AcceptChanges gọi rowChanged.

Sending Large Amounts of Data

Một đối tượng CachedRowSet, giống như tất cả những đối tượng RowSet disconnect khác, lưu trữ dữ liệu trong bộ nhớ, và như các bạn biết, việc lưu trữ quá nhiều dữ liệu còn phải gặp vấn đề về giới hạn của bộ nhớ, bằng cách sử dụng paging (phân trang), một CachedRowSet có thể điều khiển một lượng lớn dữ liệu vượt quá cả khả năng giới hạn của bộ nhớ, paging bao gồm việc nhận dữ liệu trên từng phần của dữ liệu được gọi là pages. Ví dụ, nếu ta thiết lập kích thước của page là 100, thì ta sẽ nhận được 100 dòng dữ liệu trong CachedRowSet tại một thời điểm. Đoạn mã này sẽ thiết lập cho CachedRowSet với kích thước page là 100, nghĩa là dữ liệu sẽ được đem về với một khoanh là 100 dòng tại một thời điểm.

Crs.setPageSize(100);

Sau khi thiết lập kích thước cho page, chúng ta gọi phương thức execute hay populate. Vì page size được thiết lập là 100 cho nên sau khi chạy execute thì trả về 100 dòng đầu tiên từ kết quả của ResultSet.

Crs.execute();

Phương thức mà hỗ trợ cho việc nhận các dòng tiếp theo là nextPage , nó tăng page hiện thời lên và 100 dòng kế tiếp được đổ vào trong crs. Ta có thể sử dụng phương thức nextPage trong một vòng lặp while . . . loop cho tới khi nextPage trả về false ( nghĩa là về cuối rồi ).

ở đây tôi xin đưa ra một tình huống và ví dụ sau:

giả sử cần update một giá trị tại field quatity từ 1235 thành 99, cách mà chúng ta thường nghĩ tới là đưa nó vào trong một vòng lặp và tìm ra quatity=1235 sau đó sửa lại dòng này thành 99. Ở đây dùng page size thì như sau:

crs.setPageSize(50);

crs.execute();

while(crs.next()) {

if (crs.getInt("ITEM_ID") == 1235) {

System.out.println("QUAN value: " + crs.getInt("QUAN"));

crs.updateInt("QUAN", 99);

crs.updateRow();

while(crs.nextPage()) {

System.out.println("Page number: " + i);

while(crs.next()) {

if (crs.getInt("ITEM_ID") == 1235) {

System.out.println("QUAN value: " + crs.getInt("QUAN"));

crs.updateInt("QUAN", 99);

crs.updateRow();

crs.acceptChanges();

}

}

i++;

}

crs.acceptChanges();

phương thức previousPage hỗ trợ quay ngược trở về page trước đó. Phương thức sẽ trừ số đánh dấu của page hiện tại, và lấy dữ liệu đổ vào page.

About Langthang

This is a short description in the author block about the author. You edit it by entering text in the "Biographical Info" field in the user admin panel.
    Blogger Comment
    Facebook Comment

2 comments :

  1. Thanks a lot!
    Bài này rất hay. rất thực tế, nếu bạn còn tài liệu nào liên quan thì post lên chọ mọi người cùng học hỏi.
    thanks

    ReplyDelete
  2. Thanks a lot!
    Bài này rất hay. rất thực tế, nếu bạn còn tài liệu nào liên quan thì post lên chọ mọi người cùng học hỏi.
    Cho hỏi bạn có bài nào chuyển dữ liệu từ ADO.NET Dataset sang JdbcRowset không gửi cho mình với.
    email: lemontree1505@yahoo.com.vn
    thanks

    ReplyDelete