Live data from Hacker News

Problems with JPA/Hibernate

stemlaur.com

91–100 of 195 posts

Re: Problems with JPA/Hibernate

#91
post #80

This is a common criticism but still extremely shallow. JPA/Hibernate is still the best way to actually produce working applications if you have to use an SQL database for some reason. To go point by point: Mutable datastructures with default constructors and setters: yes, mutable entities suck. Unfortunately SQL is fundamentally built around mutable entities. Every field of your POJO is writable because every column…

I disagree on most of your points but I am trying to read your entire comment favorably, but my personal experiences do not line up with almost any of this. >>> JPA/Hibernate is still the best way to actually produce working applications if you have to use an SQL database for some reason... This statement makes me think that you either do not prefer to use SQL RDBMS, don’t have to use them very often, believe they ar…

> This statement makes me think that you either do not prefer to use SQL RDBMS, don’t have to use them very often, believe they are some dusty piece of tech, or all of the above when my experience has me believing that RDBMS are absolutely the most common persistence layer I encounter in JVM, .NET, PHP, and Python codebases.

Popular doesn't mean good. I have to use SQL RDBMS a lot, and I respect the amount of low-level engineering work that has gone into them, but yeah I do hate using them.

> I don’t think I’ve ever heard a senior JVM based engineer proclaim that JPA/Hibernate are “the best way... to produce working applications”. It simply isn’t. For basic CRUD applications you will AT BEST barely write fewer lines of code with JPA than with native JDBC queries and ResultSet mapping and have all the lock-in and performance drawbacks of JPA.

I don't think seniority is a good metric, but I've got 10+ years of professional JVM experience for what that's worth. Using JPA means you'll write significantly less code, and the code you get to skip is the most tedious (and therefore rarely read or reviewed) part. Lockin is significantly lower: you can seamlessly migrate between databases in a way that you can't with handwritten SQL, and you can migrate between different JPA implementations with minimal work (not that I think there's actually much value in doing that, but the capability is there). Performance for equivalent effort will be significantly better because you've got a caching layer that actually works already in place (unless you turn it off, but, uh, don't do that).

Of course if your CRUD application is performance-critical enough to justify hand-tuning every query and implementing a correct caching layer by hand then you'll do better without the framework. But realistically that's a vanishingly rare case.

> Lazy loading will inevitably wind up with Session scope problems with any kind of concurrency, forcing nasty internal list enumeration to force a faux eager fetch to work around the problems.

Depends on your application - a lot (not all, but a lot) of systems decompose naturally into a sequence of isolated steps that provide a natural session boundary. E.g. for a REST API or MVC-style webapp just put the session in the view and get on with your life - people have some philosophical objection to this but it works really well. (I actually don't think MVC is a great way to structure a webapp, but that's a separate fight).

> Fetching just the columns you need for a particular projection will have you writing either SQL or Hibernate “SQL” in annotations.

True. But, on the assumption that you've actually structured your entities to follow your domain, how often is that something you actually gain a significant amount of performance (or anything) from?

> If you have a mix of JDBC and JPA in a codebase you will inevitably wind up with enough consistency and visibility issues as to either ditch one of them or ditch the entire codebase.

This I completely agree with (at least for people who don't make any actual effort to address the problem), and I think it's where articles like the OP come from. I see a lot of people follow a pattern something like: their application needs some vaguely tricky query, and rather than spending 5 minutes looking up how to do it in the Hibernate documentation they decide to handwrite the SQL for it instead. Then they realise that this makes the Hibernate cache for the affected entity invalid, and rather than look up how to selectively invalidate the cache for the entities affected by their query they disable the cache globally. Then they complain that Hibernate is slow and decide the solution is to handwrite the SQL for other queries instead. JPA works great, but only if you're willing to actually try to use it.

> I expect every single one of my backend engineers (on any tech stack) to understand the fundamentals of SQL INSERT, UPDATE, and DELETE statements.

Ah, but that isn't actually enough. The people talking about getting better performance from handwriting your SQL are people who understand different types of indices, different join strategies, how the query planner chooses which one to use. And if you put the same amount of time and effort into understanding Hibernate, you can get great things out of it.

Re: Problems with JPA/Hibernate

#92
Sorry for being off-topic, but why is Hibernate called Hibernate?

I can't find an explanation on the Wikipedia or GitHub pages, and whenever I see the name come up on HN my brain does a weird double-take as it goes "Is this an OS hibernation tool--No, it's the Java database thing... does it make objects go to sleep?"

Re: Problems with JPA/Hibernate

#93
post #80

This is a common criticism but still extremely shallow. JPA/Hibernate is still the best way to actually produce working applications if you have to use an SQL database for some reason. To go point by point: Mutable datastructures with default constructors and setters: yes, mutable entities suck. Unfortunately SQL is fundamentally built around mutable entities. Every field of your POJO is writable because every column…

> Mutable datastructures with default constructors and setters: yes, mutable entities suck. Unfortunately SQL is fundamentally built around mutable entities. Every field of your POJO is writable because every column of your database is writable. The impedance mismatch is big enough already without trying to make objects that behave differently from your database. Yes, an object shouldn't just be a datastructure with methods; unfortunately an SQL table row is just a datastructure, and classes are the only mechanism Java offers for representing such a thing. Same for mutable collections.

Every field is not writable in a database. There’s often constraints that restrict how fields can be updated. Requiring setters for all fields breaks that contract.

> Reflection (which is the reason classes must be non-final): again, sucks, again, the only way to do something like this in Java.

It’s the only way if you insist on having the entities track their own state changes via point in time snapshots. If they represent the changes themselves there’s no requirement for reflection.

> Lazy loading is wonderful. Put your session in your view, write a normalised set of entities that actually model your domain, and get on with your life. Don't worry about the details of what loads when unless and until you have to.

In the real world the lazy loaded view get tested with one widget loading five wozzles, then in production it’s one widget loading 5000 wozzles, each performing a separate query to hydrate its state.

> Those who don't understand Hibernate caching are doomed to reinvent it poorly.

Hibernate’s caching model manages to be both incredibly complex and incredibly limiting. Short of careful usage with an external store, it’s nearly impossible to scale across multiple JVMs. And even then it pushes the complexity to the cache.

> Don't use your database as an API. Yes, Hibernate/JPA needs to own your database. That's as it should be. SQL databases are way too complex to be shared between independent applications.

(Emphasis mine)

On the contrary, a well designed database can and will have many separate applications I retracting with it. All the more reason to have the database reflect the true constraints of the system.

> Do you really think people who can't be bothered to learn and understand Hibernate properly are somehow going to take the time to learn and understand "vanilla SQL"? Why?

The complexity of learning SQL is grossly overstated. Plus it translates as skill to all other languages and programming environments. On a purely economic basis it’s a better choice for an individual to learn SQL over Hiberate/JPA.

> None of the problems listed here are problems of JPA/Hibernate. They're problems of SQL databases which are surfaced through JPA/Hibernate, but if you skip out on JPA/Hibernate you still get exactly the same problems (maybe in a slightly less recognisable form). The real solution is to stop using these overrated datastores, but if you must use them then JPA/Hibernate is the least-bad way of doing so.

I think the ultimate example of how bad JPA can be is JPQL. They managed to take the worst aspects of everything, and then not just add them together, but multiply them!

Re: Problems with JPA/Hibernate

#94
post #80

This is a common criticism but still extremely shallow. JPA/Hibernate is still the best way to actually produce working applications if you have to use an SQL database for some reason. To go point by point: Mutable datastructures with default constructors and setters: yes, mutable entities suck. Unfortunately SQL is fundamentally built around mutable entities. Every field of your POJO is writable because every column…

Scala/Kotlin have some SQL abstraction libraries which have immutable data entities, actual constructors, etc. So I don't see why any of this has anything to do with SQL rather than the limitations of Java and Hibernate trying to force Java to do something it's not designed for.

Re: Problems with JPA/Hibernate

#95
post #92

Sorry for being off-topic, but why is Hibernate called Hibernate? I can't find an explanation on the Wikipedia or GitHub pages, and whenever I see the name come up on HN my brain does a weird double-take as it goes "Is this an OS hibernation tool--No, it's the Java database thing... does it make objects go to sleep?"

Probably a reference to how JPA-Hibernate lets you fatten up your creatures (in memory) and then put them to sleep (in the RDBMS) until they're ready to play again.

Re: Problems with JPA/Hibernate

#96
post #80

This is a common criticism but still extremely shallow. JPA/Hibernate is still the best way to actually produce working applications if you have to use an SQL database for some reason. To go point by point: Mutable datastructures with default constructors and setters: yes, mutable entities suck. Unfortunately SQL is fundamentally built around mutable entities. Every field of your POJO is writable because every column…

Scala/Kotlin have some SQL abstraction libraries which have immutable data entities, actual constructors, etc. So I don't see why any of this has anything to do with SQL rather than the limitations of Java and Hibernate trying to force Java to do something it's not designed for.

SQL abstraction libraries yes. ORMs, not really. You can map between an immutable datatype and the state of a row at a given point in time, but the only natural way to work with the native way that SQL databases express writes - in-place updates to rows - is with a model that represents them as in-place updates. In my experience those SQL abstraction libraries tend to be oriented towards either thinking in a purely command-oriented way (i.e. they're the equivalent of an IO monad) or using your database in an append-only log style (which is a much better way of storing data, but not what SQL databases are designed for).

Re: Problems with JPA/Hibernate

#97
post #93
post #80

This is a common criticism but still extremely shallow. JPA/Hibernate is still the best way to actually produce working applications if you have to use an SQL database for some reason. To go point by point: Mutable datastructures with default constructors and setters: yes, mutable entities suck. Unfortunately SQL is fundamentally built around mutable entities. Every field of your POJO is writable because every column…

> Mutable datastructures with default constructors and setters: yes, mutable entities suck. Unfortunately SQL is fundamentally built around mutable entities. Every field of your POJO is writable because every column of your database is writable. The impedance mismatch is big enough already without trying to make objects that behave differently from your database. Yes, an object shouldn't just be a datastructure with…

> Every field is not writable in a database. There’s often constraints that restrict how fields can be updated.

There are, but there's no metamodel that exposes them. All you can do (in a generic/programmatic way) is attempt a write. A particular write may fail because of constraints, but this gives you no information (except in ad-hoc database-specific ways) about what kinds of writes might succeed.

> It’s the only way if you insist on having the entities track their own state changes via point in time snapshots. If they represent the changes themselves there’s no requirement for reflection.

Sure, but that creates a major impedance mismatch. In SQL databases the current state is first-class and changes are very much seccond-class.

> In the real world the lazy loaded view get tested with one widget loading five wozzles, then in production it’s one widget loading 5000 wozzles, each performing a separate query to hydrate its state.

Sure, and then you take 5 minutes and actually profile it, actually read a little bit of the hibernate documentation, and fix it. I find it strange how for most kinds of technology the accepted wisdom is that you should take a bit of time to understand its behaviour (indeed the article says as much regarding SQL), but for ORMs the conventional wisdom is that at the first sign of trouble you should throw the whole thing away.

> On the contrary, a well designed database can and will have many separate applications I retracting with it.

It shouldn't. You are virtually guaranteed to get deadlocks (even in a single application deadlocking is easy - you need to have clear rules about which things can be locked in which order and all queries need to abide by them), updating your schema becomes essentially impossible because you can never know what's using a given column or constraint, you can't make use of temporary tables because it won't be clear what owns or is responsible for them, validation has to be done in the database which makes it very difficult to unit test or deploy (and good luck getting your test environment to look like your prod environment if you have to co-ordinate between n different applications)...

> The complexity of learning SQL is grossly overstated.

The complexity of learning Hibernate/JPA is grossly overstated too. Seriously, it's not that hard if you actually try.

Re: Problems with JPA/Hibernate

#98
post #91

Earlier quoted context omitted.

I disagree on most of your points but I am trying to read your entire comment favorably, but my personal experiences do not line up with almost any of this. >>> JPA/Hibernate is still the best way to actually produce working applications if you have to use an SQL database for some reason... This statement makes me think that you either do not prefer to use SQL RDBMS, don’t have to use them very often, believe they ar…

> This statement makes me think that you either do not prefer to use SQL RDBMS, don’t have to use them very often, believe they are some dusty piece of tech, or all of the above when my experience has me believing that RDBMS are absolutely the most common persistence layer I encounter in JVM, .NET, PHP, and Python codebases. Popular doesn't mean good. I have to use SQL RDBMS a lot, and I respect the amount of low-lev…

And on many of these points I agree...

I was careful to choose popular, and not project opinions about SQL/NoSQL/etc. In my field, most of our data is relational and we use NoSQL for caching, queues, shared work, ETL performance, dashboards, etc. but at the end of the day for persistence, the RDBMS is where the “gold copy” data ends up.

As you mentioned previously, knowing the tool set and the domain is critical to either approach. At a certain point with technology the benefits and costs are weighted by subjective preference and project specific needs. I have weighted SQL higher than JPA by many factors because I can take my SQL knowledge to any backend project, and I’ve been a part of a lot of different tech stacks in my career.

Maybe my travels have lead me to be surrounded by many more engineers that trust the database (and their knowledge of the database) to handle the persistence without a too many layers in between.

I, personally, have never seen a JPA based project that actually worked well with large-ish datasets, high concurrency, or when non-trivial ETL functions are part of the system- and this general domain has been the majority of my career, so I may have blinded myself to THE majority being confused for MY majority.

Thanks for the response and a good look at the topic from a different point of view.

Re: Problems with JPA/Hibernate

#100

I disagree with this bit: A User can be considered unique in one context by its email address, or by its social security number Personally, I'm a fan of giving everything a random UUID, because it's more flexible. It's random and impossible to guess, it scales well because there's no central bottleneck like with an autoincrement, and it's future proof and flexible. What happens when the user changes the email address…

> What if the social security number changes, because it was wrong or because it actually changes? What if the user doesn't have an SSN? What happens if they have one but lawfully refuse to provide it? What happens when you ask for and SSN from a US citizen who is also a European citizen? What happens when your database leaks? In general, relying only on natural keys is a nightmare. Double nightmare if it's PII. Natu…

In my experience from what I've seen there are ways to use natural keys and handle domain changes - I've seen some systems like this work quite successfully. The cost to using synthetic IDs (auto-increment, UUIDs) is a lack of reproducibility and slower importing of data especially across multiple tables/entities limiting scalability. This can be very problematic for certain classes of applications I've seen, but not most. While I agree with your comment for many classes of apps as always there is no general "silver bullet" answer - it depends on your problem space.

Some cases I've seen in previous roles where some natural key is required include reconciling third party data sources, or processing events from a topic or stream and being able to replay the event log, etc knowing that a different ID may break other third parties you don't control since they've already imported the ID. Being able to replay your data sets from scratch and get exactly the same data can have some real advantages for some apps.

Of course you need to be aware of the domain and assume that the key can change over time and have strategies to deal with that (e.g. entity version tables bound by time, data migration to add key attributes, etc etc) and the data structures/processes needs to be designed for this. There's more work in it for sure to get right - it shouldn't be the default. But in some cases I've seen it work really well which frankly surprised me at the time.

Post reply on HN