From: Gavin_King/Cirrus%<CI...@ci...> - 2002-05-21 06:52:46
|
> I think that separating the Transaction and the Session makes perfect > sense at a certain level, but I'm personally interested in something > even more high-level (you can call it "brain-dead", if you like). I > have two specific issues: > > 1. I'm not completely comfortable with requiring that every > transaction include the sequence: > > s.flush(); > tx.commit(); If it helps, I'm perfectly happy if Transaction.commit() calls Session.flush(). I don't see anything wrong with that at all. If it saves a line of code, its all good. ( find() methods also call flush() transparently ) > With your clean separation of Transaction & Session, though, I don't > think that hybrid flush/commit method belongs in either of those > classes, so this is where the wrapper described below would come in. No, it doesn't and thats why the old commit()/cancel() methods were problematic. There is not necessarily a 1-1 relationship between transactions and sessions, so modelling them as a single object just doesn't fit (to me anyway). > 2. More generally, I think there's a case for combining the > Session and Transaction functionality on a single interface, just to > keep the final API as simple as possible. I think we may disagree > on this, but I'd like to know whether you see the problem with a > combined interface as having mainly to do with backwards > compatibility, or whether you see other disadvantages to it. Yeah, we disagree. I see your POV and I know why it would be nice and, in fact, I originally designed things that way ( with Session.commit() and Session.cancel() ). However, while its a more convenient API for most applications, I don't feel its a correct model of the underlying concepts. I think it will be a hassle later on. > 1. Since it's only intended for use in cases where an overall > transaction is required, the transaction can be begun upon creation, > so there's no need for a separate "begin" method. Quite happy with that. But as I pointed out begin() isnt really needed with seperate transaction objects either. You can do that stuff in the constructor. Of course, instantiating the Transaction is an extra operation thats not needed in your design. > 2. Since it incorporates Session functionality, there's no need for > the developer to manage two objects, a session and a transaction. As I see it, this is the main advantage to your model. maintaining pointers to both objects _does_ make application code messier. > 3. It's not necessary to call both flush() and commit() on a > TransactionalSession. As above, I'm happy if Transactions flush the Session. > One possible downside is that this can be seen as introducing a > kind of dual API, which would have to be carefully dealt with in > documentation. I am soooo not keen on this. The main reasons we wanted to do all this in the first place were: 1. Abstract application code from the actual transaction mechanism ( and away from JDBC.setAutocommit() ). 2. Be easier to learn. It seems to me that (1) is fully satisfied by the approach of having seperate transaction objects. (2) is somewhat satisfied though I will give you that your proposed API is simpler yet. What I am quite certain of is this: documenting 2 different APIs and giving new users a choice will unsatisfy (2). Its like "well, we cant make up our mind on the right way to model it so we will add a whole bunch of extra unnecessary complexity to allow _both_ models". :) > The general way I'm looking at it, though, is that Sessions and > Transactions are building blocks used to create a higher level > layer (the "hibernate.4dummies" layer? Count me as dummy #1 :) Heh, in my comment about dummies I certainly meant no disrespect to sensible people who prefer simpler APIs over complicated ones :-) > In a sense, TransactionalSession isn't that different from the > deprecated Session API, with its commit and cancel methods. Exactly. And people found the old API confusing. > > Properties props = new Properties(); > > props.setProperty("hibernate.transaction_strategy", "JTA"); > > TransactionFactory txFactory = Hibernate.createTransactionFactory(props); > The question would arise of whether a beginTransaction() method (or > createTransaction() or whatever) I get the impression we will all agree on beginTransaction() :) > > (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? > It sounds right to me. The hand-waving summary of my imagined > design involves discrete, single-purpose components under the hood, > being combined at a high level in interfaces like Session and > TransactionalSession. quite. > > (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); > My thought was that if Hibernate provides a few basic transaction > strategy implementations initially, they should be fairly small, > simple and take the most obvious approach, as you suggest. Users with > different requirements can tweak them, improve them, write their own, > or just complain. The docs could ask for feedback about this. quite. > Sorry to be dragging this out. We've definitely made great progress > - I'm just being very demanding. In my defense, I think the more > effort that goes into coming up with good designs at this level, the > more widely useful and long-lived the result is likely to be. But if > I'm taking things too far or sucking up too much bandwidth at this > 1.0-is-imminent stage, feel free to apply brakes. Your suggestions are _very_ welcome Anton. And I strongly believe that ideas should always be put forward as strongly-as-possible to get the most out of them. Clearly we have already agreed on a bunch of stuff that makes us all happier than before. I'm not yet 100% sure if TransactionalSession should be left as an exercise for the user or should eventually be integrated into the core API. I am 100% sure I don't want to make the decision now, cos I might regret it. Unless other people start shouting at me, I'm ready to either implement, or let Anton implement: package cirrus.hibernate; interface TransactionFactory { public static TransactionFactory buildTransactionFactory(Properties props); public static Transaction beginTransaction(Session session); public Transaction beginTransaction(Session session); } interface Transaction { public void commit() throws HibernateException; //flushes session public void rollback() throws HibernateException; } package cirrus.hibernate.transaction; public class JTATransaction implements Transaction public class JDBCTransaction implements Transaction public class CMTTransaction implements Transaction Then our idiom becomes: Session s = sf.openSession(); Transaction t = tf.beginTransaction(s); try { Foo foo = s.load(fooid); foo.setName("FOO"); t.commit(); } catch (Exception e) { t.rollback(); } finally { s.close(); } Thats pretty nice, surely? |