RowSet 是 JDBC 里「可以断开连接的结果集」。离线修改后怎么写回?别人同时改了同一行会怎样?这篇用真实的 PostgreSQL 跑 CachedRowSet、WebRowSet、FilteredRowSet、JoinRowSet 和分页。
1 RowSetProvider.newFactory() 的实现:com.sun.rowset.RowSetFactoryImpl execute(conn) 之后行数 3;内容 [1:apple:10, 2:pear:20, 3:plum:30] 2 原连接已 close(isClosed=true),CachedRowSet 仍可浏览与修改: 离线修改后:[2:pear:99, 4:cherry:40, 3:plum:30](此时数据库还没有变化) 数据库里现在是:1:10,2:20,3:30 3 autocommit=false 时 acceptChanges(conn) 并 commit 之后数据库里:2:99,3:30,4:40 acceptChanges 时服务器收到的写语句(pg.log): ['SELECT id, name, qty FROM item WHERE id = $1 ', 'DELETE FROM item WHERE id = $1 ', 'SELECT id, name, qty FROM item WHERE id = $1 ', 'UPDATE item SET qty = $1 WHERE id = $2 ', 'SELECT id, name, qty FROM item ', "SELECT result.TABLE_CAT, result.TABLE_SCHEM, result.TABLE_NAME, result.COLUMN_NAME, result.KEY_SEQ, result.PK_NAME FROM (SELECT NULL AS TABLE_CAT, n.nspname AS TABLE_SCHEM, ct.relname AS TABLE_NAME, a.attname AS COLUMN_NAME, (information_schema._pg_expandarray(i.indkey)).n AS KEY_SEQ, ci.relname AS PK_NAME, information_schema._pg_expandarray(i.indkey) AS KEYS, a.attnum AS A_ATTNUM FROM pg_catalog.pg_class ct JOIN pg_catalog.pg_attribute a ON (ct.oid = a.attrelid) JOIN pg_catalog.pg_namespace n ON (ct.relnamespace = n.oid) JOIN pg_catalog.pg_index i ON ( a.attrelid = i.indrelid) JOIN pg_catalog.pg_class ci ON (ci.oid = i.indexrelid) WHERE true AND ct.relname = 'item' AND i.indisprimary ) result where result.A_ATTNUM = (result.KEYS).x ORDER BY result.table_name, result.pk_name, result.key_seq", 'INSERT INTO item (id, name, qty) VALUES ($1, $2, $3)']
3b autocommit=true 的连接上 acceptChanges 抛 SyncProviderException(null): Cannot commit when autoCommit is enabled. 抛异常之后数据库里实际是:2:99,3:30(修改与删除已经生效并自动提交了) 再调一次 acceptChanges:SyncProviderException(null): 2 conflicts while synchronizing org.postgresql.util.PSQLException: Cannot commit when autoCommit is enabled. at org.postgresql.jdbc.PgConnection.commit(PgConnection.java:998) at java.sql.rowset/com.sun.rowset.internal.CachedRowSetWriter.commit(CachedRowSetWriter.java:1410) at java.sql.rowset/com.sun.rowset.CachedRowSetImpl.acceptChanges(CachedRowSetImpl.java:911) at java.sql.rowset/com.sun.rowset.CachedRowSetImpl.acceptChanges(CachedRowSetImpl.java:960) at Main.main(Main.java:32)
4 acceptChanges 抛 SyncProviderException:SyncProviderException(null): 1 conflicts while synchronizing 冲突类型 0(UPDATE_ROW_CONFLICT=0);我的值 qty=99,数据库当前值 qty=555 冲突行数 1 数据库里 id=2 的 qty:555
5 WebRowSet.writeXml:3934 字符,109 行;前 12 行:
<?xml version="1.0"?>
<webRowSet xmlns="http://java.sun.com/xml/ns/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jdbc http://java.sun.com/xml/ns/jdbc/webrowset.xsd">
<properties>
<command>select id, name, qty from item order by id</command>
<concurrency>1008</concurrency>
<datasource><null/></datasource>
<escape-processing>true</escape-processing>
<fetch-direction>1000</fetch-direction>
<fetch-size>0</fetch-size>
<isolation-level>2</isolation-level>
<key-columns>
readXml 读回:行数 3,内容 [1:apple:10, 2:pear:20, 3:plum:30]
6 Java 序列化 CachedRowSet:5440 字节;反序列化后行数 3,内容 [1:apple:10, 2:pear:20, 3:plum:30]7 FilteredRowSet(qty >= 20):[2:pear:20, 3:plum:30] 去掉过滤器:[1:apple:10, 2:pear:20, 3:plum:30] 8 JoinRowSet(两个离线结果集按 id 内连接):[2:pear:bob, 1:apple:ann] 9 分页(setPageSize(5),表共 18 行):每页行数 [5, 5, 5, 3],每页第一行 id [1, 12, 17, 22] 10 JdbcRowSet(保持连接,当作 JavaBean 用 setUrl/setCommand/execute):行数 3,最后一行 plum