From: Gavin_King/Cirrus%<CI...@ci...> - 2002-05-20 10:51:05
|
Thanks everyone for the input. Havn't been responding in detail because I wanted to get other views and because I dont have a very strong view and also cos I've been busy coding some new functionality and reworking some older code to perform better. The next release will be a pretty major update :) It would be nice if some of you guys would try out the CVS version at this stage. Okay, Anton has convinced me of the need for _something_. I notice that some other OO persistence frameworks use a Manager interface and a Transaction interface, where the Transaction object is short-lived and implements only begin/commit/rollback and the Manager is a long-lived object. For Hibernate, I hadn't seen the need for a seperate Transaction object since the Session object is short-lived. I'm now happy to reverse this decision. Rather than mix begin/commit/rollback methods onto the Session, where they dont really fit very comfortably, lets have a seperate object that controls transaction boundaries for a Session (and abstracts the underlying JTA or JDBC transactions). A Session can span multiple Transactions, to support the "long transactions with versioning" approach. ie. What I'm suggesting is, rather than having the user create the Session by passing a TransactionStrategy object and then having the Session delegate begin/commit/rollback, just let the user manipulate the transaction strategy object directly. This leaves us the freedom to change all this at a later date, without leaving a million deprecated methods lying around on Session. The remaining question (if other people agree to this approach) is how the user obtains Transactions and how they associate the Session with the Transaction. I can think of some alternatives: EITHER (1): Session s = factory.openSession(); Transaction tx = new JDBCTransaction(s); tx.begin(); try { s.update(object); //new method I just wrote ;) s.flush(); tx.commit(); } catch (Exception e) { tx.rollback(); throw e; } finally { s.close(); } OR (2): Transaction tx = new JTATransaction(); Session s = factory.openSession(); tx.begin(s); try { s.update(object); s.flush(); tx.commit(s); } catch (Exception e) { tx.rollback(s); throw e; } finally { s.close(); } OR (3): Properties props = new Properties(); props.setProperty("hibernate.transaction_strategy", "JDBC"); Session s = factory.openSession(props); Transaction tx = s.beginTransaction(); try { s.update(object); s.flush(); tx.commit(); } catch (Exception e) { tx.rollback(); throw e; } finally { s.close(); } I like both (1) and (2) for not requiring modifications to the current API (which is an enormous plus to me). All three leave the existing API meaningful ( flush() + close() + connection() are all still useful ) so no more deprecations (this makes me very comfortable). (2) has the advantage that a single Transaction object could be used for multiple Sessions (if, for example, there were multiple databases). I'm not sure if thats particularly useful ... the other approaches still allow multiple Sessions per transaction, but with multiple Transaction objects... To fully benefit from the abstraction that Anton is after, (1) and (2) would probably require a TransactionFactory interface (to let us swap JDBCTransaction for JTATransaction somewhat transparently). Properties props = new Properties(); props.setProperty("hibernate.transaction_strategy", "JTA"); TransactionFactory factory = Hibernate.createTransactionFactory(props); Then, for (1): Transaction tx = TransactionFactory.createTransaction(session); Or, for (2): Transaction tx = TransactionFactory.createTransaction(); So, in defence of approach (3) above, you end up with a simpler API. Other questions in my mind: (1) I had kind of hoped to roll the stuff thats done by ConnectionProvider into the TransactionStrategy (ie opening, closing a JDBC connection) but it now seems to make more sense to orthogonalize these things. Does everyone else concur with that? (2a) For swappable Transaction strategies to work, JTATransaction would need to look up the surrent transaction in JNDI. Is this always okay? The usual way to get the current transaction in an EJB is from the EJBContext. (2b) What about in a CMT bean? I guess you would just need to revert to Transaction tx = new ContainerTransaction(session, ejbContext); (3) Is the call to tx.begin() really necessary in approach (1)?? Surely the work could be done in the constructor.... Okay, cut me down if all this still aint enough. thanks Gavin |