Author: arminw
Date: Wed Jun 7 09:37:42 2006
New Revision: 412448
URL: http://svn.apache.org/viewvc?rev=412448&view=rev
Log:
add new section, update sections
Modified:
db/ojb/branches/OJB_1_0_RELEASE/src/doc/forrest/src/documentation/content/xdocs/docu/howtos/howto-use-lobs.xml
Modified:
db/ojb/branches/OJB_1_0_RELEASE/src/doc/forrest/src/documentation/content/xdocs/docu/howtos/howto-use-lobs.xml
URL:
http://svn.apache.org/viewvc/db/ojb/branches/OJB_1_0_RELEASE/src/doc/forrest/src/documentation/content/xdocs/docu/howtos/howto-use-lobs.xml?rev=412448&r1=412447&r2=412448&view=diff
==============================================================================
---
db/ojb/branches/OJB_1_0_RELEASE/src/doc/forrest/src/documentation/content/xdocs/docu/howtos/howto-use-lobs.xml
(original)
+++
db/ojb/branches/OJB_1_0_RELEASE/src/doc/forrest/src/documentation/content/xdocs/docu/howtos/howto-use-lobs.xml
Wed Jun 7 09:37:42 2006
@@ -160,7 +160,7 @@
public Clob getClob() {return clob;}
public void setClob(Clob clob) {this.clob = clob;}
}
- ]]></source>
+]]></source>
<p>
Then the mapping would look like this:
</p>
@@ -187,7 +187,7 @@
jdbc-type="CLOB"
/>
</class-descriptor>
- ]]></source>
+]]></source>
<p>
More information about how to map columns in OJB see
<a href="site:repository">repository section</a>.
@@ -224,13 +224,13 @@
public Clob newClob(Reader reader);
public Clob newClob(String value);
public Clob newClob();
- ]]></source>
+]]></source>
<p>
To access this class use the service method in
<code>PersistenceBroker</code> class:
</p>
<source><![CDATA[
LobHelper lh = broker.serviceLobHelper();
- ]]></source>
+]]></source>
<p>
Assume we want to insert an object of class
<code>LobObject</code> (described in the
<a href="#lobMapping">example above</a>). The LOB content
is an image file.
@@ -246,7 +246,7 @@
obj.setBlob(b);
broker.store(obj);
broker.commitTransaction();
- ]]></source>
+]]></source>
<p>
The <code>InputStream</code> <em>in</em> will normally be
closed by the jdbc-driver.
</p>
@@ -275,34 +275,40 @@
// create new object
LOBTest.LobObject obj = new LobObject();
// insert new object to get a valid PK
-broker.store(obj);
+broker.store(obj, ObjectModification.INSERT);
+
// get the current Connection
Connection con = broker.serviceConnectionManager().getConnection();
Statement stmt = con.createStatement();
-// use database specific function to create an empty LOB
+// use database specific function to create an empty LOB on DB
stmt.execute ("UPDATE BLOB_TEST SET BLOB_VALUE_ = empty_blob() WHERE ID = " +
obj.getId());
stmt.close();
-// Lookup identity
-Identity oid = broker.serviceIdentity().buildIdentity(obj);
-// remove object from cache to force DB roundup
-broker.removeFromCache(oid);
-// lookup from DB
-obj = (LobObject) broker.getObjectByIdentity(oid);
-
+// Refresh LOB field to get the empty LOB-locator
+broker.serviceLobHelper().refreshLob(obj);
Blob blob = obj.getBlob();
+// writing to oracle Blob-OutputStream, this writes directly to
+// the database
OutputStream outstream = blob.setBinaryStream(1);
byte[] buffer = new byte[100];
int length = -1;
while ((length = instream.read(buffer)) != -1)
outstream.write(buffer, 0, length);
+// in/out-stream cleanup
instream.close();
outstream.close();
-// writing to oracle Blob OutputStream write directly to
-// the database, thus no need to store/update the LobObject instance
-// broker.store(obj);
+// this method call help to synchronize the cache and
+// will update all non-PK, non LOB fields.
+broker.store(obj, ObjectModification.UPDATE);
+// mandatory, commit transaction
broker.commitTransaction();
- ]]></source>
+]]></source>
+ <p>
+ The last <code>broker.store(obj)</code> call will not
update the LOB field again,
+ because Oracle java-LOB's updates made directly to the
LOB and OJB will skip
+ these fields on persistence capable object update
calls (because Oracle database
+ metadata return <em>locatorsUpdateCopy</em> false -
see JDBC 3.0 section 16.3.3).
+ </p>
<p>
More detailed information about
<a href="site:connection/obtain-connection">
@@ -317,6 +323,87 @@
</section>
+ <anchor id="lifecycle"/>
+ <section>
+ <title>LOB object lifecycle and wrapper classes</title>
+ <p>
+ In all requested <em>persistence capable objects</em> with
LOB fields OJB wraps the
+ <code>java.sql.Blob</code> and <code>java.sql.Clob</code>
instances (provided by the jdbc-driver)
+ with wrapper classes (see class <a
href="ext:blob-handle"><code>BlobHandle</code></a> and
+ <a href="ext:clob-handle"><code>ClobHandle</code></a>).
These wrapper classes restrict the
+ life of the wrapped LOB instances independent from the
used database (except when using
+ <a href="#reportQueries">Report Queries</a> to query LOB
content).
+ </p>
+ <p>
+ LOB fields behavior is different from <em>normal</em>
fields.
+ LOB fields will become <em>invalid</em> when
+ </p>
+ <ul>
+ <li>
+ the current transaction commits or rollback
+ </li>
+ <li>
+ the current <code>PersistenceBroker</code>
+ instance was closed
+ </li>
+ </ul>
+ <p>
+ The access of LOB content is only valid within an active
+ transaction else a <code>LobException</code> will be
thrown. To access LOB content
+ first begin the tx and then lookup/query the persistent
object:
+ </p>
+ <source><![CDATA[
+// mandatory to start a tx
+broker.beginTransaction();
+// query/lookup object with LOB content
+LobObject obj = (LobObject) broker.getObjectByQuery(...);
+Blob b = obj.getBlob();
+// access LOB
+....
+broker.commitTransaction();
+]]></source>
+ <p>
+ If you query the <code>LobObject</code> without running tx
it's not allowed to access
+ the LOB content.
+ </p>
+ <p>
+ If the persistent object already exists from a previous tx
you have to
+ <a href="#refreshLobs">refresh the LOB instances</a>
within the current transaction.
+ </p>
+
+
+ <anchor id="unwrap"/>
+ <section>
+ <title>Excursus: Access wrapped LOB content</title>
+ <p>
+ All LOB content (of persistence capable objects)
provided by the jdbc-driver
+ (e.g. <code>java.sql.Blob</code> and
<code>java.sql.Clob</code> instances) is wrapped with
+ OJB specific classes.
+ </p>
+ <p>
+ It is possible to access the jdbc-driver specific LOB
implementation instances using
+ methods to get the innermost LOB object - after cast
to wrapper class (these classes
+ are described in <a href="#lifecycle">section
above</a>). For the
+ <a href="#lobMapping">example mapping</a> it would
look like this
+ (for <code>java.sql.Blob</code> and
<code>java.sql.Clob</code> instances):
+ </p>
+ <source><![CDATA[
+// get the wrapped LOB instance from the
+// persistence capable object
+Blob b = lobObject.getBlob();
+// now cast to wrapper class and lookup
+// innermost Blob instance
+Blob realBlob = ((BlobHandle) b).getBlob();
+
+Clob c = lobObject.getClob();
+// now cast to wrapper class and lookup
+// innermost Clob instance
+Clob realClob = ((ClobHandle) c).getClob();
+]]></source>
+ </section>
+ </section>
+
+
<anchor id="queryLobs"/>
<section>
<title>Querying LOB content</title>
@@ -325,15 +412,24 @@
compared to objects without. All about how to query
objects in OJB you can find
in the <a href="site:query">query-</a> and api-guides.
</p>
- </section>
-
-
- <anchor id="lifecycle"/>
- <section>
- <title>Lifecycle of LOB fields</title>
<p>
-
+ The only difference is that the access of LOB-fields
(<code>java.sql.Blob</code>
+ and <code>java.sql.Clob</code> fields in persistence
capable objects) is only valid within
+ active transactions - see <a href="#lifecycle">LOB content
lifecycle</a>
</p>
+
+ <anchor id="reportQueries"/>
+ <section>
+ <title>LOB content via <a
href="site:query/report-queries">Report Query</a></title>
+ <p>
+ Using <a href="site:query/report-queries">Report
Query</a> to lookup LOB content
+ will return the <code>java.sql.Blob</code> and
<code>java.sql.Clob</code> instances
+ provided by the jdbc-driver - in contrast to
persistence capable objects with LOB content
+ OJB <strong>do not wrap</strong> these instances with
specific
+ <a href="#lifecycle">wrapper objects</a>.
+ </p>
+ </section>
+
</section>
@@ -341,26 +437,83 @@
<section>
<title>Refresh LOB's</title>
<p>
- ########## to be written #########
+ As said in the <a href="#lifecycle">lifecycle section</a>
the access of LOB content in
+ persistence capable objects is only valid in context of a
transaction and only till
+ commit/rollback or close of the associated
<code>PersistenceBroker</code> instance.
+ <br/>
+ If the persistent object already exists from a previous tx
you have to refresh the
+ LOB instances within the current transaction using method
+ <code>LobHelper.refreshLob(...)</code>:
</p>
+ <source><![CDATA[
+// existing object
+LobObject obj = ...;
+// mandatory to start a tx
+broker.beginTransaction();
+// refresh the LOB content
+broker.serviceLob().refreshLob(obj);
+Blob b = obj.getBlob();
+// access LOB
+....
+broker.commitTransaction();
+]]></source>
+
<anchor id="autoRefresh"/>
<section>
- <title>Enable automatic refresh of LOB content</title>
+ <title>Automatic LOB refresh</title>
<p>
-
+ By default OJB automatically refresh the LOB-content
of cached persistent objects on
+ request of objects by query or identity lookup.
</p>
+ <source><![CDATA[
+# LOB-locator objects (Blob and Clob fields in persistence capable objects)
are only
+# valid as long as the current PersistenceBroker transaction is active. After
commit or
+# rollback the LOB-object will be invalidated and before next access to the
LOB-locator
+# object it must be refreshed. Cached persistent objects with LOB-content need
refresh
+# too. OJB will automatically refresh all objects requested by query or
identity lookup.
+# Set this property to 'false' to disable this service.
+LobAutoRefresh=true
+]]></source>
</section>
</section>
-
- <anchor id="updateLobs"/>
+ <anchor id="caching"/>
<section>
- <title>Update LOB's</title>
+ <title>Caching and LOB fields</title>
<p>
- ########## to be written #########
+ OJB wraps all LOB fields of persistence capable objects to
allow caching of
+ these objects. But dependend on the used <a
href="site:object-cache">object cache</a>
+ you have to take care:
</p>
+ <ul>
+ <li>
+ <p><a href="site:object-cache/session">session
cache</a></p>
+ <p>
+ Save for use, because each
<code>PersistenceBroker</code> instance use it's
+ own cache (no shared cache) and the cache will be
cleared when broker is closed.
+ </p>
+ </li>
+ <li>
+ <p><a href="site:object-cache/two-level">two-level
cache</a></p>
+ <p>
+ Save for use, the first level cache is used within
transactions and
+ the shared second level cache is based on field
copies. All LOB fields
+ will be copied using placeholder.
+ </p>
+ </li>
+ <li>
+ <p><a href="site:object-cache/shared">shared
cache</a></p>
+ <p>
+ Read carefully the documentation about this cache
implementation. It's
+ important to avoid concurrent modification of
objects by different
+ sessions/threads. Also concurrent read of the same
object (with LOB content)
+ will cause problems, because the LOB content can
only be assigned to one
+ <code>PersistenceBroker</code> at the same time.
+ </p>
+ </li>
+ </ul>
</section>
</section>
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]