Cheers Ralf,

I'd guessed as much and have set the cache to none for that object. Preliminary indications from running my tests show that the application still works correctly using this hybrid approach of Castor and JDBC. This application should be the only thing writing to that database, so otherwise the cache should work correctly, but I might need to judiciously disable it for certain domain objects. Shouldn't be a problem.

I do have one question about it though. Obviously, I'd like to utilise the same mechanism that Castor uses for retrieving a JDBC Connection. Initial browsing of the code makes me think that I can do it fairly easily using this:

/**
 * Return a Connection, using the same mechanisms that Castor uses, so
 * hopefully doing the same ConnectionPool / JNDI lookup whatever, that
 * Castor is configured to use.
 *
 * @return a Connection - not null.
 * @throws SQLException if there was a problem.
 */
private Connection getConnection() throws SQLException {

    // We know the name of the Database entry in the configuration is
    // "default"
    DatabaseRegistry databaseRegistry = DatabaseRegistry
            .getDatabaseRegistry("default");
    return databaseRegistry.createConnection();
}

It seems to work, but it would be nice to have it confirmed by someone more familiar with the code!

Cheers,

James

Ralf Joachim wrote:
Hi James,

as far as I remember, CALL SQL does only work for select statements but
not for update or insert. You have to use JDBC for this kind of things.

Having said that you have to take care on cached objects that you have
updated through JDBC. Castor does not know about the database changes
and will hold dirthy objects in its cache. This will lead to
ObjectModifiedExceptions thrown when updating these objects through
Castor. Another problem is that you do not instantly see your changes
done by JDB statements. Therefore you need to set cache type to none or
remove the updated object from cache. While I have used the first myself
I have no experience about the second solution.

Regards
Ralf


James Abley schrieb:
Actually, it doesn't look like I can drop into raw SQL in this way.

CALL SQL UPDATE myObject SET field = $1 WHERE ID = $2

That doesn't get parsed properly by OQLQueryImpl.createCall - it looks
for the WHERE clause and examines the statement for $x tokens after the
string value WHERE, rather than checking the whole statement. Later,
OQLQueryImpl.bind(Object) throws a NullPointerException when it tries to
bind the first parameter, and can't find a ParamInfo object in the
_paramInfo field keyed on Integer(1).

So it looks like I will have to drop into JDBC to use this sort of
update approach.

Should I raise a JIRA ticket about the OQL parsing?

Cheers,

James

James Abley wrote:
To provide more context, I'm seeing locking and
LockNotGrantedException problems with a part of the application that
tries to update a single field in a root object, and
LockNotGrantedExceptions happen over the root object, or something in
the related object graph. I'm leaning towards the idea of swapping out
the current implementation for a simple raw SQL 'UPDATE MyObject SET
field = ? WHERE ID = ' approach to see if that removes the problem and
was wondering if anyone else has seen similar issues or resorted to
that type of thing?

Cheers,

James

James Abley wrote:
Cheers Ralf and Werner,

That tallies with my understanding.

Does anyone have real-world examples they can share about complexity
of objects graphs that they have in their domain? One of the
applications I deal with locks a lot of objects (maybe ten objects)
when a root object is loaded.

Some of this (I believe) is mitigated since some of the domain
objects can be marked in the mapping file as read-only, and so I
would hope that Castor never gets any lock on that; e.g. if one of
the objects references a Country object that is marked as read-only
in the mapping file, any attempt to load something referencing a
Country object will always return that Country object as read-only
and thus no transaction should experience race-conditions on
attempting to gain a lock on a Country object, no matter what
AccessMode is being used by the client transaction.

But my main concern is whether having such a complex object graph is
damaging to concurrency, and whether I should look at
de-normalisation to flatten it a bit.

Cheers,

James

Werner Guttmann wrote:
In addition to what Ralf has said, please note that loading objects as
read-only mode (in one way or the other) will help you improving
performance as Castor will perform less checks at the end of the
transaction.

In other words, make sure that you know your domain model, especially
when it comes down to categorizations such as 'stability',
'cacheability', etc.

Regards
Werner

Ralf Joachim wrote:
Hi James,

Castor locks the whole object graph from the time when it gets loaded
until the end of the transaction which is _db.commit(). If Castor
would
not lock the whole object graph that could lead to inconsistenties.
With
the default access mode 'Shared' these locks are handled by Castor
internally.

As the transaction at your first example is open during 'some long
operation' the whole graph gets locked until the end of this
transaction.

At the second example you have 2 short transaction. The first one
loads
the object and thereafter releases any locks at first _db.commit().
According to this no object is locked during the 'some long
operation'.
After that operation you start the second transaction which again
loads
and locks the object including all related ones. Then you do some
changes to the objects and commit them. At this commit the changes are
written to database and the locks get released again.

As the objects are not locked during 'some lock operation' at the
second
example, you need to be aware that your object may have changed in the
meantime.

Hope this helps
Ralf


James Abley schrieb:
Hi,

I'm trying to understand Castor's locking mechanism for object
graphs.

Say I have the following classes:

class Book {

    int id;

    String author;

    ...
}

class Customer {

    int id;

    // Assume this will be a collection of Books that
    // has been browsed by each customer.
    Collection booksBrowsed;

    // Assume that this is the transaction history of
    // each customer, so a collection of Transaction
    // objects
    Collection transactions;

    Date lastLoginTime;

    ...
}

class Transaction {

    int id;

    Date purchaseTime;

    Book item;

    ...
}

If I have client code that does something like the following:


Database db = getDatabase();
db.begin();
db.load(Customer.class, 3, Database.Shared);

// do some long operation here

customer.setLastLoginTime(Calendar.getInstance().getTime());
db.commit();
db.close();


Is there a lock held on all of the objects in the collections in the
Customer object? Or is a lock only obtained on the Customer object
when
the transaction is ending and Castor can examine each object, see if
it's dirty and thus needs to get a lock to update the object?

Second related part. I'm very familiar with
http://www.castor.org/jdo-best-practice.html, but I was curious about
another aspect. Assume that I re-write the client to try to
minimize the
transaction:


Database db = getDatabase();
db.begin();
db.load(Customer.class, 3, Database.ReadOnly);
db.commit();
db.close();

// do some long operation here
db.begin();
db.load(Customer.class, 3, Database.Shared);
customer.setLastLoginTime(Calendar.getInstance().getTime());
db.commit();
db.close();


Again, what gets locked? Is it the entire object graph, or just the
dirty objects?

Presumably the latter code sample is the recommended way to go,
irrespective of how the object graph gets locked?

Cheers,

James

---------------------------------------------------------------------
To unsubscribe from this list please visit:

   http://xircles.codehaus.org/manage_email

---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email


---------------------------------------------------------------------
To unsubscribe from this list please visit:

   http://xircles.codehaus.org/manage_email


---------------------------------------------------------------------
To unsubscribe from this list please visit:

   http://xircles.codehaus.org/manage_email


---------------------------------------------------------------------
To unsubscribe from this list please visit:

   http://xircles.codehaus.org/manage_email



---------------------------------------------------------------------
To unsubscribe from this list please visit:

   http://xircles.codehaus.org/manage_email

Reply via email to