I’ve never used Spring until now, but it seems to be a beautiful thing! I mean, I had picked up a love for Dependency Injection at my last job, because it made things so much easier to test, but I never took the time to learn about Spring itself because I was elbow deep in learning raw Hibernate and Struts 1.X.
Now that I am picking it up for our current project at work, I really like it! I could see how someone could make a ‘Big Brother’ analogy with Spring, but that would give the completely wrong impression. Spring is more like a ‘Fairy Godmother’ who is of course helpful, but stays invisible when you don’t need her. Spring even smooths out some of the rough edges of Struts for you! (Yay!)
The Rabbit Hole
In our model, we have a fairly big object that is pretty central to most of the site. Many of the fields and collections are set up to be @Transient. Also, even though all the objects will be running in a single JVM (i.e. non-EJB), we’ve defined our @Transactional boundaries to be at the "services layer", e.g. underneath but not including the Action classes.
So, I infer the following behavior from this setup. (And please, correct me if I am wrong…): Let’s say this BigObject (BO for short) is pulled from the DB in the services layer. As soon as it crosses the transactional boundary, it is now considered to be ‘detatched’. The Action class can then muck about adding/deleting/updating data in the BO. Then, the BO gets passed back to the service layer, back into a transaction. Then, you call some kind of saveBO(BO) method in the corresponding DAO, it becomes "re-attached" and Hibernate "does some magic" to the data, and it all just goes into the database likety_splitly…
Since some of the fields are labeled @Transient, doesn’t this give the BO statefulness? Let’s say there’s a transient Collection of relationships to other objects, and it is needed in the service layer where the BO is initially ‘hydrated’. By the time the BO crosses the transactional boundary it would have the whole Collection populated. Then, as the BO descends back into a new transactional context, it might, or might not, have been populated, right? It just strikes me as wrong that a supposedly POJO data object is carrying around some indication of state.
What I Wanted to Do Otherwise, and What I Was Told
I am uncomfortable the thought of trusting (that much) Hibernate "magic". I wanted to poll the BO’s Collection to see if the relationship I was creating already existed, so I could opt not to create a new one. But, I can’t be sure if the Collection is even there, since the BO is being handed to me from above, which means it might be a detached object. Our data-tier guy says to just insert the new relationship (into a Collection that might be empty in the local version, but might not be in the database), and Hibernate (using optimistic locking) can sort it all out. (It was at this point that I started to doubt myself… Am I down a rabbit hole because I’m being pessimistic, and that is conflicting the codified ‘optimism’?)
My First Option
Let’s assume I’m not completely off the mark above… What I’ve done before is to try and do all the pulling, manipulation, and saving of information within a single transactional context. I’ve defined the services layer API to take identifiers and smaller chunks of data… (Something like addRelationship(bigObjectId, relationship)…) I didn’t get too far down this path before I changed jobs, so I wasn’t around for the full conclusion of that pattern… (So, if you have followed this pattern through, please let me know how it went!)
My Second Option
The other thing that occurred to me was to move the transactional boundary. Why define it at the services layer, especially since everything is within the same JVM? Why not put the transactional boundary all the way around the Request/Response cycle via a ServletFilter, or by putting the @Transactional on the Action class managed by Spring (as mentioned in this IBM DeveloperWorks article), or even via AOP? This way, everything is attached, and you can lazy-load everything! No more cross-boundary state holding, no more stale data.
Suffice it to say, I am kinda confused. It’d be really awesome to test all these options out on my own, so I could get them down in my head… But, I just don’t have the time to play all the scenarios out.