5 ms·
I've been using Hibernate sans Java EE for about four years. I started using it under JPA (again, without Java EE) about two years ago. Only in the last few mon
by fusiongyro 13y ago
I've been using Hibernate sans Java EE for about four years. I started using it under JPA (again, without Java EE) about two years ago. Only in the last few months have I been able to deploy a Java EE environment, and there, only for a very small project, and the Java EE aspect was pretty minor, although desirable and cool.
Hibernate does not require Java EE stuff. The "dynamic weaving" is provided by Javassist (formerly provided by cglib, but cglib is apparently deprecated). No complex setup here. Put the appropriate dependency in your pom and it "magically" works.
Indeed, my biggest objection to Hibernate is the degree to which it relies on magic. A lot of that magic is truly magic, in the sense that you are not supposed to worry to hard about how it all works. If it did always just work, it wouldn't be maddening when you try to figure out why it is going wrong only to get slapped in the face by a fistful of hard magic.
For instance, the batch annotation, in pure, non-JPA Hibernate, is the fetch "mode." There are several options like "join" and "subselect." Hibernate defaults to an N+1 queries situation, but supplying "join" or "subselect" instead isn't necessarily good enough to get the behavior you want. We had a situation where no matter what we did in the Hibernate config, the behavior was an N+1 query explosion. The problem turned out to be an innocuous-looking log statement in the object model. Tracing in, it turned out that this log statement was being invoked indirectly from the object's constructor, causing the list to be "forced" before construction was complete. For some reason this bypassed Hibernate's usual configuration. The solution was to delete the log statement and take a lot of care not to touch anything that might be a PersistentList from the constructor.
That kind of lesson, while trite, is very hard to apply in practice. Especially when you have a set of developers working on the database and object-relational mapping layer and another set working on the model. Hibernate brings a lot of "gotchas." Shield's article hits on one of the more onerous database-side ones, that you are informally forced into using artificial keys, but there are enough oddball ramifications and restrictions to go around that plenty of them spill out into the Java code.
I have positive feelings towards myBatis, but I have only used it for a few edge cases in my Hibernate projects. While it is actually pretty easy to trick Hibernate into returning real objects for native queries, the trouble doesn't end there. It's very hard to do a complex SQL query from Hibernate without running into the vague sensation that the Criteria API would be better. A few hours later, you're back to building SQL strings, having read unsettling absurdities in the documentation like "There is no explicit 'group by' necessary in a criteria query."
myBatis's major advantage, in my conjectural opinion, is that it does not pretend to liberate you from worrying about the database. As a database developer, I am free to write the best query I can for a given situation, liberally using the most esoteric features of my database. My peers in the model can write exactly the interfaces they want to use. But they are not free to imagine that they have the entire object graph available to them to manage to the minutia at all times, and the ramifications of this loss on a group working solely in the model must be great, and I haven't seen them yet. I see storm clouds looming on that side of this tradeoff. It's annoying when I go to a peer and say what they can and cannot do in a constructor or a bean property getter/setter, but from then on they can still pretend that they have everything, and the worst thing that happens is really untenable performance. But everything works. myBatis, in contrast, is only too happy to give you back an incomplete object tree. There is no "weaving" or "instrumentation" in what comes back to support on-the-fly querying just because you accessed some property. Again, it is a great strength (much, much less magic) but it's also a great weakness. Your model guys aren't going to be able to ignore the database with impunity.
I'd like to hear from a group that switched from Hibernate or JPA to myBatis and how it worked out.
- brianmcc 13y agoVery interesting; as someone's who been very happily using Ibatis with Java and Spring for many years I've always been wary of Hibernate for just the reasons you mention. The thought of ceding control over SQL to a framework so extensively would give me sleepless nights, and my hunch has always been that there will be a bunch of non-performant parent/child relation anti-patterns basically baked in and waiting to pounce (if that's not too much of a mixed metaphor...!).
- nobullet 13y agoI understand why people don't like ORMs. But I don't understand people who like iBatis: it is boilerplate like the hell. Imaging you have to separately update mappings for SQL select, insert, update and delete query (and these mappings are very long) for your entities. For example, prepared statement for update looks like this: PreparedStatement ps = ...; ps.setLong(1, author.getUserId()); ps.setLong(2, author.getStreamId()); ps.setString(3, author.getNetwork()); ps.setString(4, author.getIdInNetwork()); ps.setString(5, author.getNote()); ps.setString(6, author.getSocialId()); .... And manually counting questions is a normal practice when you add a field: static final String UPDATE = "UPDATE Table1 SET Domains = ?, TemplateId = ?, InternalJson = ? WHERE StreamID = ?"; static final String INSERT = "INSERT INTO Config1 (UserID, StreamID, Domains, TemplateId, InternalJson) VALUES (?, ?, ?, ?, ?)";
- fusiongyro 13y agoYou have to pick your battles. It's convenient that Hibernate will do these things for you, but I have seen lots of times when the order Hibernate wants to remove something causes an integrity violation. For instance, a not-null foreign key reference in a linking table; sometimes Hibernate seems to try setting the value to null before deleting the referenced entity, leading to an integrity violation. There have been times when I couldn't figure out how to make Hibernate do this the right way (reversing the order of its deletes and skipping the unnecessary set-null step) so I instead just lifted the constraint. I hate when I have to do that, because ideally Hibernate should just live with whatever schema I have given it. Another example is trying to depend on CASCADE in the database. The settings you need to make to get Hibernate to accept this are quite arcane and force you to manually worry about list indexes in the Java code. Yet another example of a place where Hibernate, which ought not be telling me how to make my database or my Java code, instead winds up forcing me to take certain decisions in both.