Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This article is... Questionable at best. I don't think any of this is an argument against JPA, except that the author doesn't like how it works? I also suspect the author doesn't know hibernate that well.

For instance selecting just the fields you need is relatively simple with JPQL:

    SELECT i.url FROM Image i WHERE i.id = ...


JPA and Hibernate make it very easy to use it incorrectly, its almost like they promote bad SQL queries and ideas. They let users of database connection to write Java-first database queries, when database query should be database first, it's just way too easy to abuse it and get too much data, too many columns and JOINs.

Developers look like JSON looks like, what we send to browser, what formatting it has, validation and size of JSON data, as it's easy to monitor and trim.

Can't say the same about Hibernate. How the hell even hibernate caching works? Why even are there 2 levels of Hibernate cache? It's too easy to create and abuse transactions. Dirty-checking is JUST WAYYYY TOOO EAZY TO ABUSE. not calling, using setter of an instance shouldn't update in database by default omg, It shouldn't be possible for transactions to leak outside some easily specified scope - I've seen one project where transaction leaked to Jackson!! Jackson was calling getters on fields and executing DB queries. JSON ended up as 2.6Mb instead list of 10 fields.

Hibernate is popular because we don't need to learn SQL to get needed data, but it's also super hard to get it right and don't do something stupid by accident.

If in any doubt, refer to JOOQ - it's the SQL-oriented ORM for Java.


> How the hell even hibernate caching works? Why even are there 2 levels of Hibernate cache?

https://docs.jboss.org/hibernate/stable/orm/userguide/html_s...

> using setter of an instance shouldn't update in database by default omg

This doesn't happen.. the database won't update until you ask the entity manager to persist the entity.

> I've seen one project where transaction leaked to Jackson!! Jackson was calling getters on fields and executing DB queries. JSON ended up as 2.6Mb instead list of 10 fields.

I suspect you might not agree, but JPA lazy loading is one of the easiest concepts to understand. However, I'd argue that leaking your database models to the view is a mistake to begin with and said application is already incorrect.

> If in any doubt, refer to JOOQ - it's the SQL-oriented ORM for Java.

Both the author/maintainer of jOOq and Hibernate agree that each has their place.

I really am amazed at developers that don't take the time to learn about the tools they use.


> This doesn't happen.. the database won't update until you ask the entity manager to persist the entity.

Doesn't this happen through automatic dirty checking?


No calling a setter on an Entity doesn't automatically issue an sql UPDATE query. You need to ask the EntityManager to merge or persist the entity and it's changes.

Obviously JPA knows what fields were updated via dirty checking.. that's almost half the point of an ORM.


If you have a managed instance of an entity, like something returned by a find or a query, calling a setter will modify its state and the state change _will_ be detected and persisted automatically on the next flush, without explicit persist or merge.


I'm not talking about "dirty checking". I'm talking about "automatic dirty checking". Take for example this code I got from this article[1]:

    SessionFactory  sessionFactory = HibernateUtil.getSessionFactory();
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    Person person  = session.load(Person.class, 2); //loads Person object for id 2
    person.setAge(32);
    tx.commit();
    session.close();
    HibernateUtil.closeSessionFactory();
It results in an updated age for the person in the DB. However, EntityManager was never directly notified about the change in the person object.

[1] - https://learnjava.co.in/automatic-dirty-checking-in-hibernat...


That's because JPA isn't involved here. It's directly using hibernate api's and not sticking to the standard which is what I was talking about.


I'm almost certain this occurs with Hibernate as the JPA provider. I haven't tried this with other JPA providers but as far as I can tell from tutorials[1], stack overflow posts[2], and the JPA documentation[3], this is the default for JPA as well.

[1] - https://www.objectdb.com/java/jpa/persistence/update

[2] - https://stackoverflow.com/a/8307991

[3] - https://docs.oracle.com/javaee/6/tutorial/doc/bnbqw.html#bnb...

EDIT: Oops I accidentally replied to this twice


Have you verified that? I'm pretty sure that occurs using the JPA API and Hibernate. I'm not sure if other JPA providers do this as well.


That is because "session.load(Person.class, 2)" line literally says "and track changes" - as article says.

That is not how Hibernate or JPA is used normally. It is going out of standard way to achieve the thing you complain about.


> That is because "session.load(Person.class, 2)" line literally says "and track changes" - as article says.

I'm aware that that what occurs. That is my point. I'm responding to the previous posts statement "No calling a setter on an Entity doesn't automatically issue an sql UPDATE query". This is an example where calling a setter causes an update query to be run.

> That is not how Hibernate or JPA is used normally. It is going out of standard way to achieve the thing you complain about.

What about this not not how Hibernate and JPA are used normally? Are you saying that setters are not normally used? Do you mean that people normally call update or merge to persist an Entity? If so, I agree that is what people normally do. However, when people do that they tend to accidentally introduce bugs. Usually this occurs when they update an entity and then do some validation on it. When the validation fails they think they can avoid sending he changes to the DB by doing nothing. However, that isn't true. They have to manually evict the entity from the session to prevent that from happening.


The "session.load(Person.class, 2)" thing is not done normally. It is not even part of JPA. It is hibernate only feature.

So in all project I have seen, calling setter did not changed database.

> Do you mean that people normally call update or merge to persist an Entity?

Yes, people normally call update and merge to persist an entity.


People normally do that when they do not have to do that.

  Dog rex = em.find(Dog.class,"rex"); // 1
  rex.setAge(2); // 2
  // other query // 3
At 3 the update is flushed on the underlying db. This is pure JPA. Calling merge is forcing an useless query before the update. Also, merge returns the managed entity.


> Hibernate is popular because we don't need to learn SQL to get needed data, but it's also super hard to get it right and don't do something stupid by accident.

I think this is plain wrong, or I might have been very lucky with who I work with: if anything I think most people I work with learned JPA or other ORMs long after learning SQL.


You have been lucky. Part of our hiring test (intentionally) does something which is trivial to get correct if you know SQL but also easy to get racey with Hibernate. About 4/5 of applicants get it wrong and maybe 2/5 don't know how to fix it when we show them they problem. (Spring devs with 1-5 years experience in web APIs and reporting.)


Yeah, I really dont know anyone in real life who would claim or expect developers to not know SQL just because hibernate is used.

Hibernate is how to get data into Java. And we still have database scripts, migrations to new versions and what not.


> not calling, using setter of an instance shouldn't update in database by default omg, It shouldn't be possible for transactions to leak outside some easily specified scope - I've seen one project where transaction leaked to Jackson!! Jackson was calling getters on fields and executing DB queries. JSON ended up as 2.6Mb instead list of 10 fields.

I saw a similar problem with some old codebase where I work. There is some Velocity templates that shows information stored on database entities (yeah... bad idea). And sometimes, we got some mysterious errors about transaction closed. Well... Results that Velocity calling the getters of these beans, can trigger a JPA/Hibernate query to get some additional data that has been loaded before. And this could happens after we close the database transaction.


Giving up basic OO niceties like invariants in your whole domain just to get automatic persistence from some library I agree with the author: it’s insane and no one should accept that tradeoff.

There has to be ways around that though, perhaps using a duplicated domain of DTOs or coercing the ORM to use constructors or private setters to keep encapsulation and invariants.


IMO invariants are better handled by a class who's sole responsibility is to enforce and validate said invariants, especially when you have dependencies involved to enforce them (like making sure the Item actually exists in the db).

Value classes like @Entity shouldn't have the responsibility to enforce those business rules.

We can disagree on which way is more object oriented though.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: