LOBs should be valid until end of transaction?

閲覧: 135 回
最初の未読メッセージにスキップ

cbauer

未読、
2011/11/28 8:29:502011/11/28
To: H2 Database
Found up some earlier reports, same issue I'm seeing in my tests:

http://groups.google.com/group/h2-database/browse_thread/thread/4feb31b18179a44b
http://groups.google.com/group/h2-database/browse_thread/thread/706872a45c32031d

I'm confused by Thomas' statement that H2 closes the LOB when the
ResultSet is closed. The JDBC4 spec says on page 138:

"Note – The closing of a ResultSet object does not close the Blob,
Clob, NClob or SQLXML objects created by the ResultSet. Blob, Clob,
NClob and SQLXML objects remain valid for at least the duration of the
transation in which they are created, unless their free method is
invoked."

It's certainly true that all (?) DBMS close the LOB when the
transaction ends but this is the first time I'm hearing that closing a
ResultSet invalidates the LOBs.

I'm seeing the following error on a Hibernate test:

[main ] FINE - 14:24:54,501 -
bernate.jdbc.ConnectionManager: opening JDBC connection
[main ] FINE - 14:24:54,501 - org.hibernate.SQL:
/* load org.jpwh.model.advanced.Item */ select
item0_.id as id0_0_,
item0_.description as descript2_0_0_,
item0_.imageBlob as imageBlob0_0_
from
Item item0_
where
item0_.id=?
[main ] FINEST - 14:24:54,502 -
hibernate.jdbc.AbstractBatcher: preparing statement
[main ] FINEST - 14:24:54,504 -
ype.descriptor.sql.BasicBinder: binding parameter [1] as [BIGINT] -
1000
[main ] FINEST - 14:24:54,505 -
org.hibernate.loader.Loader: Bound [2] parameters total
[main ] FINE - 14:24:54,509 -
hibernate.jdbc.AbstractBatcher: about to open ResultSet (open
ResultSets: 0, globally: 0)
[main ] FINEST - 14:24:54,509 -
org.hibernate.loader.Loader: processing result set
[main ] FINE - 14:24:54,509 -
org.hibernate.loader.Loader: result set row: 0
[main ] FINE - 14:24:54,510 -
org.hibernate.loader.Loader: result row:
EntityKey[org.jpwh.model.advanced.Item#1000]
[main ] FINEST - 14:24:54,510 -
org.hibernate.loader.Loader: Initializing object from ResultSet:
[org.jpwh.model.advanced.Item#1000]
[main ] FINEST - 14:24:54,511 -
entity.AbstractEntityPersister: Hydrating entity:
[org.jpwh.model.advanced.Item#1000]
[main ] FINEST - 14:24:54,513
- .descriptor.sql.BasicExtractor: found [This is some description.] as
column [descript2_0_0_]
[main ] FINEST - 14:24:54,518
- .descriptor.sql.BasicExtractor: found [blob0: CAST(REPEAT('00',
131072) AS BINARY /* table: 0 id: 0 */)] as column [imageBlob0_0_]
[main ] FINEST - 14:24:54,519 -
org.hibernate.loader.Loader: done processing result set (1 rows)
[main ] FINE - 14:24:54,519 -
hibernate.jdbc.AbstractBatcher: about to close ResultSet (open
ResultSets: 1, globally: 1)
[main ] FINE - 14:24:54,521 -
hibernate.jdbc.AbstractBatcher: about to close PreparedStatement (open
PreparedStatements: 1, globally: 1)
[main ] FINEST - 14:24:54,521 -
hibernate.jdbc.AbstractBatcher: closing statement
[main ] FINEST - 14:24:54,522 -
org.hibernate.loader.Loader: total objects hydrated: 1
[main ] FINE - 14:24:54,522
- .hibernate.engine.TwoPhaseLoad: resolving associations for
[org.jpwh.model.advanced.Item#1000]
[main ] FINE - 14:24:54,522
- .hibernate.engine.TwoPhaseLoad: done materializing entity
[org.jpwh.model.advanced.Item#1000]
[main ] FINE - 14:24:54,523 -
ine.StatefulPersistenceContext: initializing non-lazy collections
[main ] FINE - 14:24:54,523 -
org.hibernate.loader.Loader: done entity load
[main ] FINEST - 14:24:54,523 -
org.hibernate.impl.SessionImpl: setting cache mode to: NORMAL
#### NOW I'M TRIGGERING THE MATERIALIZATION OF THE BLOB THROUGH
HIBERNATE. THE FOLLOWING LINES ARE IN A finally{} BLOCK AND EXECUTED
AFTER THE EXCEPTION! ####
[main ] FINEST - 14:24:54,538 -
n.HibernateSynchronizationImpl: JTA sync : afterCompletion(4)
[main ] FINEST - 14:24:54,539 -
ronization.CallbackCoordinator: transaction after completion callback
[status=4]
[main ] FINEST - 14:24:54,539 -
org.hibernate.jdbc.JDBCContext: after transaction completion
[main ] FINE - 14:24:54,539 -
bernate.jdbc.ConnectionManager: aggressively releasing JDBC connection
[main ] FINE - 14:24:54,539 -
bernate.jdbc.ConnectionManager: releasing JDBC connection [ (open
PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
[main ] FINEST - 14:24:54,539 -
org.hibernate.impl.SessionImpl: after transaction completion
org.h2.jdbc.JdbcSQLException: File not found: "/private/var/folders/6g/
6gmKY4DQH5qiRof2QSZWok+++TI/-Tmp-/
h2.temp.de157a94a4c6fd40.1.temp.db" [90124-162]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:
329)
at org.h2.message.DbException.get(DbException.java:169)
at org.h2.message.DbException.get(DbException.java:146)
at org.h2.engine.SessionRemote.openFile(SessionRemote.java:634)
at org.h2.value.ValueLobDb.getInputStream(ValueLobDb.java:275)
at org.h2.jdbc.JdbcBlob.getBinaryStream(JdbcBlob.java:154)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
at java.lang.reflect.Method.invoke(Method.java:597)
at
org.hibernate.engine.jdbc.SerializableBlobProxy.invoke(SerializableBlobProxy.java:
74)
at $Proxy21.getBinaryStream(Unknown Source)
at
org.jpwh.test.advanced.LazyProperties.storeLoadLocator(LazyProperties.java:
101)

I'm using "jdbc:h2:tcp://localhost/mem:test", same error with
"jdbc:h2:tcp://localhost/test". However, everything works with
"jdbc:h2:mem:test".

cbauer

未読、
2011/11/28 9:15:282011/11/28
To: H2 Database
I'm running the same tests on Derby now but hitting another issue even
earlier (this one could be a Hibernate bug). So at this time I can't
really say who's fault it is.

Christian Bauer

未読、
2011/11/28 11:04:252011/11/28
To: h2-da...@googlegroups.com
The following test fails on H2 but works on Derby:

public static void main(String args[]) throws Exception {
Connection conn = DriverManager.getConnection("jdbc:derby:test;create=true");
//Connection conn = DriverManager.getConnection("jdbc:h2:tcp://localhost/mem:test", "sa", "");

conn.createStatement().executeUpdate("drop table ITEM");
//conn.createStatement().executeUpdate("drop table if exists ITEM");
conn.createStatement().executeUpdate("create table ITEM (FOO blob)");
conn.setAutoCommit(false);

// INSERT
PreparedStatement statement = conn.prepareStatement("insert into ITEM (FOO) values (?)");
byte[] bytes = new byte[131072];
new Random().nextBytes(bytes);
statement.setBinaryStream(1, new ByteArrayInputStream(bytes));
int result = statement.executeUpdate();
assert result == 1;
statement.close();
conn.commit();

// SELECT
ResultSet rs = conn.createStatement().executeQuery("select * from ITEM");
Blob blob = null;
while(rs.next()) {
blob = rs.getBlob(1);
// Works
//assert blob != null;
//bytes = blob.getBytes(1, (int)blob.length());
//assert bytes.length == 131072;
}

// Failure A
//assert blob != null;
//bytes = blob.getBytes(1, (int)blob.length());
//assert bytes.length == 131072;

rs.close();

// Failure B
//assert blob != null;
//bytes = blob.getBytes(1, (int)blob.length());
//assert bytes.length == 131072;

conn.commit();

// Failure C
//assert blob != null;
//bytes = blob.getBytes(1, (int)blob.length());
//assert bytes.length == 131072;

conn.close();
}

Expected is that Failure A and B pass, as they do on Derby. H2 seems to restrict the validity of the blob to the iteration of the ResultSet, not even the open/close status of the ResultSet. It should use the transaction scope.

Thomas Mueller

未読、
2011/11/28 13:36:102011/11/28
To: h2-da...@googlegroups.com
Hi,

Thanks!

You are right, this is a bug (only when using the server mode by the way). I didn't know the BLOB/CLOB needs to stay open when the result set is closed. The result set is also closed when there are no more rows, that's why case A fails as well.

This will be fixed in the next release. I hope I can completely get rid of the BLOB/CLOB temp files when using the server mode, but I'm not sure yet.

Regards,
Thomas



--
You received this message because you are subscribed to the Google Groups "H2 Database" group.
To post to this group, send email to h2-da...@googlegroups.com.
To unsubscribe from this group, send email to h2-database...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/h2-database?hl=en.

Thomas Mueller

未読、
2011/12/07 15:21:162011/12/07
To: h2-da...@googlegroups.com
Hi,

This bug is now fixed in the trunk. Thanks for reporting this issue,
and thanks a lot for the test case!

Regards,
Thomas

Sanjeev Sharma

未読、
2012/07/31 17:34:412012/07/31
To: h2-da...@googlegroups.com
Hi Thomas:
I am having almost a similar issue with Clobs.  I am trying to migrated my application form V1 to V2 and in the process reading the clob from V1 and altering it and putting it into V2 of my application. The H2 that we use is in embedded mode.  So in my scenario V1 is stopped - the H2 database is accessed via jdbc:file url and the V2 is accessed via jdbc:tcp url. The code that goes over the result set and does rs.getCharacterStream is failing.
Here is the trace:

org.h2.jdbc.JdbcSQLException: File not found: "C:/Users/ssharma/AppData/Local/Temp/v360-780471439001691522.lobs.db/4.t19.lob.db" [90124-168]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
    at org.h2.message.DbException.get(DbException.java:169)
    at org.h2.message.DbException.get(DbException.java:146)
    at org.h2.engine.Database.openFile(Database.java:458)
    at org.h2.value.ValueLob.getInputStream(ValueLob.java:627)
    at org.h2.value.ValueLob.getReader(ValueLob.java:620)
    at org.h2.value.ValueLob.getString(ValueLob.java:550)
    at org.h2.jdbc.JdbcResultSet.getString(JdbcResultSet.java:275)
    at com.infovista.v360mig.v360.Vista360Migration.migrateData(Vista360Migration.java:211) -- This line calls rs.getCharacterStream(index)
    at com.infovista.v360mig.v360.Vista360Migration.performDataMigration(Vista360Migration.java:53)

What should I be doing to get this working.  

Thanks
Sanjeev

Thomas Mueller

未読、
2012/08/06 2:42:572012/08/06
To: h2-da...@googlegroups.com
Hi,

Newer version of H2 store the LOB object in the database file. You seem to use the newest version of H2, but with an old database file, or with the "lob in database" setting disabled. Is there a reason to keep the LOBs in separate files? If not, I suggest to create a new database (see "migration" in the docs), with the default settings.

Regards,
Thomas
--
You received this message because you are subscribed to the Google Groups "H2 Database" group.
To view this discussion on the web visit https://groups.google.com/d/msg/h2-database/-/5UdHSqdD-1oJ.
全員に返信
投稿者に返信
転送
新着メール 0 件