Showing posts with label jpa. Show all posts
Showing posts with label jpa. Show all posts

Wednesday, September 24, 2014

JPA EntityManager: Why use persist() over merge()?

Either way will add an entity to a PersistenceContext, the difference is in what you do with the entity afterwards.
Persist takes an entity instance, adds it to the context and makes that instance managed (ie future updates to the entity will be tracked).
Merge creates a new instance of your entity, copies the state from the supplied entity, and makes the new copy managed. The instance you pass in will not be managed (any changes you make will not be part of the transaction - unless you call merge again).
Maybe a code example will help.
MyEntity e = new MyEntity();

// scenario 1
// tran starts
em.persist(e); 
e.setSomeField(someValue); 
// tran ends, and the row for someField is updated in the database

// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue); 
// tran ends but the row for someField is not updated in the database
// (you made the changes *after* merging)

// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue); 
// tran ends and the row for someField is updated
// (the changes were made to e2, not e)
Scenario 1 and 3 are roughly equivalent, but there are some situations where you'd want to use Scenario 2.

Friday, May 16, 2014

Hibernate, iBatis, Java EE or other Java ORM tool

Let me take a crack at this. First of, I've written some on this subject in Using an ORM or plain SQL?. Specifically to address your points:
Learning Curve/Ease of Use
Ibatis is about SQL. If you know SQL the learning curve for ibatis is trivial. Ibatis does some things on top of SQL such as:
  • group by;
  • discriminated types; and
  • dynamic SQL.
that you'll still need to learn but the biggest hurdle is SQL.
JPA (which includes Hibernate) on the other hand tries to distance itself from SQL and present things in an object rather than a relational way. As Joel points out however, abstractions are leaky and JPA is no exception. To do JPA you'll still need to know about relational models, SQL, performance tuning of queries and so forth.
Whereas Ibatis will simply having you apply the SQL you know or are learning, JPA will require you to know something else: how to configure it (either XML or annotations). By this I mean figuring out that foreign key relationships are a relationship (one-to-one, one-to-many or many-to-many) of some kind, the type mapping, etc.
If you know SQL I would say the barrier to learning JPA is actually higher. If you don't, it's more of a mixed result with JPA allowing you to effectively defer learning SQL for a time (but it doesn't put it off indefinitely).
With JPA once you setup your entities and their relationships then other developers can simply use them and don't need to learn everything about configuring JPA. This could be an advantage but a developer will still need to know about entity managers, transaction management, managed vs unmanaged objects and so on.
It's worth noting that JPA also has its own query language (JPA-SQL), which you will need to learn whether or not you know SQL. You will find situations where JPA-SQL just can't do things that SQL can.
Productivity
This is a hard one to judge. Personally I think I'm more productive in ibatis but I'm also really comfortable with SQL. Some will argue they're way more productive with Hibernate but this is possibly due--at least in part--to unfamiliarity with SQL.
Also the productivity with JPA is deceptive because you will occasionally come across a problem with your data model or queries that takes you a half a day to a day to solve as you turn up logging and watch what SQL your JPA provider is producing and then working out the combination of settings and calls to get it to produce something that's both correct and performant.
You just don't have this kind of problem with Ibatis because you've written the SQL yourself. You test it by running the SQL inside PL/SQL Developer, SQL Server Management Studio, Navicat for MySQL or whatever. After the query is right, all you're doing is mapping inputs and outputs.
Also I found JPA-QL to be more awkward than pure SQL. You need separate tools to just run a JPA-QL query to see the results and it's something more you have to learn. I actually found this whole part of JPA rather awkward and unwieldy although some people love it.
Maintainability/Stability
The danger with Ibatis here is proliferation meaning your dev team may just keep adding value objects and queries as they need them rather than looking for reuse whereas JPA has one entitty per table and once you have that entity, that's it. Named queries tend to go on that entity so are hard to miss. Ad-hoc queries can still be repeated but I think it's less of a potential problem.
That comes at the cost of rigidity however. Often in an application you will need bits and pieces of data from different tables. With SQL it's easy because you can write a single query (or a small number of queries) to get all that data in one hit and put it in a custom value object just for that purpose.
With JPA you are moving up that logic into your business layer. Entities are basically all or nothing. Now that's not strictly true. Various JPA providers will allow you to partially load entities and so forth but even there you're talking about the same discrete entitites. If you need data from 4 tables you either need 4 entities or you need to combine the data you want into some kind of custom value object in the business or presentation layer.
One other thing I like about ibatis is that all your SQL is external (in XML files). Some will cite this is as a disadvantage but not me. You can then find uses of a table and/or column relatively easy by searching your XML files. With SQL embedded in code (or where there is no SQL at all) it can be a lot harder to find. You can also cut and paste SQL into a database tool and run it. I can't overstate enough how many times this has been useful to me over the years.
Performance/Scalability
Here I think ibatis wins hands down. It's straight SQL and low cost. By its nature JPA simply won't be able to manage the same level of latency or throughput. Now what JPA has going for it is that latency and throughput are only rarely problems. High performance systems however do exist and will tend to disfavour more heavyweight solutions like JPA.
Plus with ibatis you can write a query that returns exactly the data you want with the exact columns that you need. Fundamentally there's no way JPA can beat (or even match) that when it's returning discrete entities.
Ease of Troubleshooting
I think this one is a win for Ibatis too. Like I mentioned above, with JPA you will sometimes spend half a day getting a query or entity produce the SQL you want or diagnosing a problem where a transaction fails because the entity manager tried to persist an unmanaged object (which could be part of a batch job where you've committed a lot of work so it might be nontrivial to find).
Both of them will fail if you try to use a table or column that doesn't exist, which is good.
Other criteria
Now you didn't mention portability as one of your requirements (meaning moving between database vendors). It's worth noting that here JPA has the advantage. The annotations are less portable than, say, Hibernate XML (eg standard JPA annotations don't have an equivalent for Hibernate's "native" ID type) but both of them are more portable than ibatis / SQL.
Also I've seen JPA / Hibernate used as a form of portable DDL, meaning you run a small Java program that creates the database schema from JPA configuration. With ibatis you'll need a script for each supported database.
The downside of portability is that JPA is, in some ways, lowest common denominator, meaning the supported behaviour is largely the common supported behaviour across a wide range of database vendors. If you want to use Oracle Analytics in ibatis, no problem. In JPA? Well, that's a problem.

Friday, March 28, 2014

JPA: persisting vs. merging entites

JPA is indisputably a great simplification in the domain of enterprise applications built on the Java platform. As a developer who had to cope up with the intricacies of the old entity beans in J2EE I see the inclusion of JPA among the Java EE specifications as a big leap forward. However, while delving deeper into the JPA details I find things that are not so easy. In this article I deal with comparison of theEntityManager’s merge and persist methods whose overlapping behavior may cause confusion not only to a newbie. Furthermore I propose a generalization that sees both methods as special cases of a more general method combine.

Persisting entities

In contrast to the merge method the persist method is pretty straightforward and intuitive. The most common scenario of thepersist method's usage can be summed up as follows:

"A newly created instance of the entity class is passed to the persist method. After this method returns, the entity is managed and planned for insertion into the database. It may happen at or before the transaction commits or when the flush method is called.
 If the entity references another entity through a relationship marked with the PERSIST cascade strategy this procedure is applied to it also."




The specification goes more into details, however, remembering them is not crucial as these details cover more or less exotic situations only.

Note: If the entity has been removed from the persistence context then it becomes managed again when passed to the persist method. If the entity is detached (i.e. it was already managed) then an exception may be thrown. 

Merging entities

In comparison to persist, the description of the merge's behavior is not so simple. There is no main scenario, as it is in the case ofpersist, and a programmer must remember all scenarios in order to write a correct code. It seems to me that the JPA designers wanted to have some method whose primary concern would be handling detached entities (as the opposite to the persist method that deals with newly created entities primarily.) The merge method's major task is to transfer the state from an unmanaged entity (passed as the argument) to its managed counterpart within the persistence context. This task, however, divides further into several scenarios which worsen the intelligibility of the overall method's behavior.

Instead of repeating paragraphs from the JPA specification I have prepared a flow diagram that schematically depicts the behaviour of the merge method:




Comparison

  • persist deals with new entities (passing a detached entity may end up with an exception.)
  • merge deals with both new and detached entities
  • persist always causes INSERT SQL operation is executed (i.e. an exception may be thrown if the entity has already been inserted and thus the primary key violation happens.)
  • merge causes either INSERT or UPDATE operation according to the sub-scenario (on the one hand it is more robust, on the other hand this robustness needn't be required.)
Note: Both SQL operations are postponed at or before the transaction commits
or flush is called

  • persist makes a previously removed entity managed again
  • merge throws an exception if a previously removed entity is passed
  • persist makes the passed entity managed
  • merge copies the state of the passed entity to the managed entity
  • persist does not return any value
  • merge returns the managed entity - the clone of the passed entity
  • both methods ignore a managed entity and turn their attention to the entities referenced through PERSIST, resp. MERGE, relationships
  • In contrast to merge, passing a detached entity to persist may lead to throwing an exception.

So, when should I use persist and when merge?

persist
  • You want the method always creates a new entity and never updates an entity. Otherwise, the method throws an exception as a consequence of primary key uniqueness violation.
  • Batch processes, handling entities in a stateful manner (see Gateway pattern)
  • Performance optimization
merge
  • You want the method either inserts or updates an entity in the database.
  • You want to handle entities in a stateless manner (data transfer objects in services)
  • You want to insert a new entity that may have a reference to another entity that may but may not be created yet (relationship must be marked MERGE). For example, inserting a new photo with a reference to either a new or a preexisting album.


Design flaws

The persist method implements inserting a new entity. The merge method implements both inserting and updating. There is apparently one method missing, which would implement updating without inserting. I can go on in generalization and think about possibility to define a custom behavior that occurs when an entity is being combined with the persistence context. From this point persisting, merging and updating would be mere three strategies how to combine an incoming entity with the content of the persistence context. The EntityManager interface would contain one general method, let's call it combine(entity, strategy), that would take two arguments: the entity and the strategy used for combining the entity with the persistence context. The strategy would be an interface having two main implementations: PersistStategy and MergeStrategy which would comply with thepersist, resp. merge method. In this design both methods would simply delegate their invocations to the combine method passing the corresponding strategy instance.
The concept of cascade policies could be also generalized: instead of using the values from the CascadeType enumeration a programmer would use the class of the strategy itself as a value for the strategy attribute (or other) of the relationship annotations.
Instead:
   @OneToOne(cascade=CascadeType.PERSIST)
public Address getAddress() {
return address;
}
the code would look like this:
   @OneToOne(cascadeStrategy=PersistStrategy.class)
public Address getAddress() {
return address;
}
If the programmer wanted to declare a relationship through which the update-only entity combination strategy would be propagated to an associated entity, he/she would do it as follows:
   @OneToOne(cascadeStrategy=UpdateOnlyStrategy.class)
public Address getAddress() {
return address;
}
Some generalization should be also done in generating SQL command. Considering that the persist and merge strategies result in generating INSERT or UPDATE SQL command, there should be also some mechanism that would allow a custom strategy to generate its own SQL commands.

Friday, August 23, 2013

What is a JPA implementation?

JPA
JPA is just an API (hence Java Persistence API) that requires an implementation to use.
An analogy would be using JDBC. JDBC is an API for accessing databases, but you need an implementation (a driver jar file) to be able to connect to a database. On its own, without a driver, you cannot do anything with a database.
With JPA, as I said, you need an implementation, a set of classes that lie "below" JPA, and such an implementation will do what you want.
Your application uses the JPA API (this wording is a bit cubersome, but I hope you get the idea), which then communicates with the underlying implementation.
Popular implementations include HibernateEclipseLinkOpenJPA and others.
Every one of them implement the JPA API, so if you use only JPA, every implementation should act the same.
But! The functionality provided by these implementations might go beyond the standard JPA API.
If you want to use this particular functionality, you will have to use vendor specific API that will not be compatible with others.
For example, even though JPA defines the @Id annotation with ID generation options, when using Hibernate, you can use also @org.hibernate.annotations.GenericGenerator for Hibernate specific generation strategies.
Using this annotation will not work unless you're using Hibernate as the underlying implementation.
The bottom line is: JPA is the "least common denominator" which every vendor implements, and every implementation might have some more advanced features that aren't standard.
If you want your application to be portable, use only JPA. If you are sure you won't change your mind later on and switch implementations, use JPA + vendor specific features.

Differences Between Hibernate and JPA

Fans of the Hibernate object-relational mapping (ORM) framework will realize that the Java Persistence API (JPA) is basically a standardization of that framework. And, if you’re like me, you really haven’t given much thought to JPA, because, gee, isn’t it just a watered-down Hibernate? Maybe, maybe not. (I’m not going to get into that here and now.)
It can be useful, though (even if only politically or procedurally), to code to JPA instead of the Hibernate API. If you find yourself in that situation, you may find this compare/contrast between the two API’s to be useful:
HibernateJPA
SessionFactoryEntityManagerFactory
SessionEntityManager
sessionFactory.getCurrentSession().[method]()entityManager.[method]()
saveOrUpdate()persist()
Query.setInteger/String/Entity()Query.setParameter()
list()getResultList()
uniqueResult()getSingleResult()
uniqueResult() returns nullgetSingleResult() throws NoResultException
CriteriaQueries – yesCriteriaQueries – no
Additionally, there are a couple Hibernate-specific JPA-isms to keep in mind:
  • If the underlying JPA implementation is Hibernate, either/both annotations or/and mapping files may be used – at the same time. In such a situation, I believe the mapping files act as an override for the annotations.
  • The best of both worlds (in my mind) is to base the code (at an interface- or API-level) on JPA and its EntityManager, but to have the implementation interact with the Hibernate Session, which can be obtained by calling getDelegate() on the EntityManager.

Saturday, May 18, 2013

What are JPA entities?


An Entity is roughly the same thing as an instance of a class when you are thinking from a code perspective or a row in a table (basically) when you are thinking from a database perspective.
So, it's essentially a persisted / persistable instance of a class. Changing values on it works just like changing values on any other class instance. The difference is that you can persist those changes and, in general, the current state of the class instance (entity) will overwrite the values the row for that instance (entity) had in the database, based on the primary key in the database matching the "id" or similar field in the class instance (entity).
There are exceptions to this behavior, of course, but this is true in general.