Monday, December 7, 2015

JPA EntityManager Merge vs Persist

Here's a quick short post. Putting it here, since it has been tremendously useful for me. I hope this will help others as well.

There have been several questions on SO about merge() and persist() operations. But I find that it is not just about one resulting to an UPDATE SQL command, and the other resulting to an INSERT SQL command.

Results of merge() and persist()

Instead of pasting relevant sections from the JPA 2.1 specification in this post, I've created a summary table of the results of the said operations. This is based on sections 3.2.2 (Persisting an Entity Instance) and 3.2.7.1 (Merging Detached Entity State) of the JPA 2.1 specification.

Operation State Result
persist new becomes managed
persist managed ignored (but cascaded)
persist removed becomes managed
persist detached throws exception or commit fails
Operation State Result
merge new becomes managed
merge managed ignored (but cascaded)
merge removed throws exception or commit fails
merge detached becomes managed

As you can see, both merge() and persist() operations treat new and managed entities the same way. But they only differ in the way they treat removed and detached entities.

Closing Thoughts

So, the next time you think that persist() results to an INSERT, and merge() results to an UPDATE, think again!

Here's my take. I personally prefer to use merge() operation to handle new, managed, and detached entities.

But for removed entities (which can only happen when you programmatically remove it), I use persist(). But then again, it's rare (in my experience) to remove an entity, and then reverse its removal in the same persistence context.

Friday, December 4, 2015

Spring-managed Transactions Explained - Part 2 (JPA)

In the first part of the series, I showed how transactions work in plain-vanilla JDBC. And then I showed how Spring manages JDBC-based transactions. In this second part of the series, I'll show how transactions work in plain-vanilla JPA first. And then show how Spring manages JPA-based transactions.

Funds Transfer

To help illustrate transactions, I'll be using the same case study of transferring funds from one bank account to another. Here, we show code snippets of debit, credit, and transfer methods.

... class BankAccountService {
  public void transfer(MonetaryAmount amount, ...) {
    debit(amount, ...);
    credit(amount, ...);
    ...
  }
  public void credit(MonetaryAmount amount, AccountId accountId) {
    ...
  }
  public void debit(MonetaryAmount amount, AccountId accountId) {
    ...
  }
  ...
}

JPA Transactions

In plain-vanilla JPA, transactions are started by calling getTransaction().begin() on the EntityManager. The code snippet below illustrates this.

import javax.persistence.*;
...
EntityManagerFactory emf = ...;
EntityManager em = emf.createEntityManager();
try {
  em.getTransaction().begin();
  // make changes through entities
  em.getTransaction().commit();
  ...
} catch(Exception e) {
  em.getTransaction().rollback();
  throw e;
} finally {
  em.close();
}

Technically, the EntityManager is in a transaction from the point it is created. So calling begin() is somewhat redundant. Until begin() is called, certain operations such as persist, merge, remove cannot be called. Queries can still be performed (e.g. find()).

Objects that were returned from queries can be changed. Although the JPA specification is somewhat unclear on what will happen to these changes when no transaction has been started.

Now, let's apply JPA to the funds transfer case study.

We defined a BankAccount entity to handle debit() and credit() behavior.

import javax.persistence.*;

@Entity
... class BankAccount {
  @Id ...;
  ...
  public void debit(MonetaryAmount amount) {...}
  public void credit(MonetaryAmount amount) {...}
  ...
}

We add an EntityManagerFactory to BankAccountService to enable the creation of EntityManagers when needed.

import javax.persistence.*;

... class BankAccountService {
  private EntityManagerFactory emf; // injected via constructor
  ...
  public void transfer(MonetaryAmount amount, ...) ... {
    EntityManager em = emf.createEntityManager();
    try {
      em.getTransaction().begin();
      BankAccount fromAccount = em.find(BankAccount.class, ...);
      BankAccount toAccount = em.find(BankAccount.class, ...);
      fromAccount.debit(amount);
      toAccount.credit(amount);
      em.getTransaction().commit();
      ...
    } catch(Exception e) {
      em.getTransaction().rollback();
      // handle exception (possibly rethrowing it)
    } finally {
      em.close();
    }
  }
  public void credit(MonetaryAmount amount, AccountId ...) ... {
    EntityManager em = emf.createEntityManager();
    try {
      em.getTransaction().begin();
      BankAccount theAccount = em.find(BankAccount.class, ...);
      theAccount.credit(amount);
      em.getTransaction().commit();
      ...
    } catch(Exception e) {
      em.getTransaction().rollback();
      // handle exception (possibly rethrowing it)
    } finally {
      em.close();
    }
  }
  public void debit(MonetaryAmount amount, AccountId ...) ... {
    EntityManager em = emf.createEntityManager();
    try {
      em.getTransaction().begin();
      BankAccount theAccount = em.find(BankAccount.class, ...);
      theAccount.debit(amount);
      em.getTransaction().commit();
      ...
    } catch(Exception e) {
      em.getTransaction().rollback();
      // handle exception (possibly rethrowing it)
    } finally {
      em.close();
    }
  }
}

Spring-managed JPA Transactions

The transfer, credit, and debit methods could sure use a template class (something like a JdbcTemplate) to remove all the boilerplate code. Spring previously provided a JpaTemplate class, but was deprecated as of Spring 3.1, in favor of native EntityManager usage (typically obtained through @PersistenceContext).

So, let's do just that — use EntityManager obtained through @PersistenceContext.

import javax.persistence.*;

... class BankAccountService {
  @PersistenceContext
  private EntityManager em;
  ...
  public void transfer(MonetaryAmount amount, ...) ... {
    try {
      em.getTransaction().begin();
      BankAccount fromAccount = em.find(BankAccount.class, ...);
      BankAccount toAccount = em.find(BankAccount.class, ...);
      fromAccount.debit(amount);
      toAccount.credit(amount);
      em.getTransaction().commit();
      ...
    } catch(Exception e) {
      em.getTransaction().rollback();
      // handle exception (possibly rethrowing it)
    }
  }
  public void credit(MonetaryAmount amount, AccountId ...) ... {
    try {
      em.getTransaction().begin();
      BankAccount theAccount = em.find(BankAccount.class, ...);
      theAccount.credit(amount);
      em.getTransaction().commit();
      ...
    } catch(Exception e) {
      em.getTransaction().rollback();
      // handle exception (possibly rethrowing it)
    }
  }
  public void debit(MonetaryAmount amount, AccountId ...) ... {
    try {
      em.getTransaction().begin();
      BankAccount theAccount = em.find(BankAccount.class, ...);
      theAccount.debit(amount);
      em.getTransaction().commit();
      ...
    } catch(Exception e) {
      em.getTransaction().rollback();
      // handle exception (possibly rethrowing it)
    }
  }
}

Our code is a little bit simpler. Since we didn't create an EntityManager, we don't have to close it. But we are still calling getTransaction().begin(). Is there a better way? And how does an EntityManager get injected into the object in the first place?

From my previous post in this series, the astute reader is probably already thinking of having Spring do the work for us. And rightfully so!

EntityManager and @PersistenceContext

We tell Spring to inject an EntityManager from the EntityManagerFactory by adding a PersistenceAnnotationBeanPostProcessor (either through XML <bean>, or simply using a Java-based configuration via @Configuration classes loaded via AnnotationConfigApplicationContext).

  • When using XML-based configuration, a PersistenceAnnotationBeanPostProcessor is transparently activated by the <context:annotation-config /> element. And this element also gets transparently activated by <context:component-scan />.
  • When using Java-based @Configuration, the AnnotationConfigApplicationContext is used. And with it, annotation config processors are always registered (one of which is the aforementioned PersistenceAnnotationBeanPostProcessor).

By adding a single bean definition, the Spring container will act as a JPA container and inject an EnitityManager from your EntityManagerFactory.

JPA and @Transactional

Now that we have an EntityManager, how can we tell Spring to begin transactions for us?

We tell Spring to start transactions by marking methods as @Transactional (or mark the class as @Transactional which makes all public methods transactional). This is consistent with the way Spring enables transactions with JDBC.

import javax.persistence.*;
import org.springframework.transaction.annotation.Transactional;

@Transactional
... class BankAccountService {
  @PersistenceContext
  private EntityManager em;
  ...
  public void transfer(MonetaryAmount amount, ...) ... {
      BankAccount fromAccount = em.find(BankAccount.class, ...);
      BankAccount toAccount = em.find(BankAccount.class, ...);
      fromAccount.debit(amount);
      toAccount.credit(amount);
  }
  public void credit(MonetaryAmount amount, AccountId ...) ... {
      BankAccount theAccount = em.find(BankAccount.class, ...);
      theAccount.credit(amount);
  }
  public void debit(MonetaryAmount amount, AccountId ...) ... {
      BankAccount theAccount = em.find(BankAccount.class, ...);
      theAccount.debit(amount);
  }
}

Wow, that was nice! Our code just got a lot shorter.

And just as explained in the first part of this series, when Spring encounters this annotation, it proxies the object (usually referred to as a Spring-managed bean). The proxy starts a transaction (if there is no on-going transaction) for methods that are marked as @Transactional, and ends the transaction when the method returns successfully.

Proxy adds transaction behavior

A call to debit() will use a transaction. A separate call to credit() will use a transaction. But what happens when a call to transfer() is made?

Since the transfer() method is marked as @Transactional, Spring will start a transaction. This same transaction will be used for calls to debit() and credit(). In other words, debit(amount) and credit(amount) will not start a new transaction. It will use the on-going transaction (since there is one).

But wait! How does Spring know when to inject a proper entity manager? Is it only injected when a transactional method is invoked?

Shared EntityManager

In one of my training classes, I tried the following to better understand how Spring injects an EntityManager via @PersistenceContext. And I believe it will help others too. So, here's what I tried:

import javax.persistence.*;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.InitializingBean;

@Transactional
... class BankAccountService implements InitializingBean {
  @PersistenceContext
  private EntityManager em;
  ...
  @Override
  public void afterPropertiesSet() {
    System.out.println(em.toString());
  }
  ...
}

An output of something like this was displayed on the console after the application context started.

Shared EntityManager proxy for target factory [...]

So what is this shared entity manager?

When the application context starts, Spring injects a shared entity manager. The shared EntityManager will behave just like an EntityManager fetched from an application server's JNDI environment, as defined by the JPA specification. It will delegate all calls to the current transactional EntityManager, if any; otherwise, it will fall back to a newly created EntityManager per operation.

Going back to our question. Spring doesn't inject the right entity manager at the right time. It always injects a shared entity manager. But this shared entity manager is transaction-aware. It delegates to the current transactional EntityManager, if there is an on-going transaction.

Conclusion

This concludes the two-part series. I hope that by starting off with the plain-vanilla versions of JDBC and JPA (sans DAOs and repositories), I was able to make it clearer as to how Spring is able to manage transactions behind the scenes. And that by having a clearer idea as to what Spring is doing behind the scenes, you can troubleshoot better, understand why you get an TransactionRequiredException saying "No transactional EntityManager available", and add better fixes to your applications.

Now, it's time for a cold one.

Thursday, December 3, 2015

Spring-managed Transactions Explained - Part 1 (JDBC)

I've been meaning to write about this for quite some time now. In the training courses I've been privileged to conduct, I've noticed that course participants have had the most difficulty trying to understand how Spring manages transactions. In the first part of this series, I'll start by showing how transactions work in plain-vanilla JDBC. And then show how Spring manages JDBC-based transactions.

In the second part of this series, I'll show how transactions work in plain-vanilla JPA. And then show how Spring manages JPA-based transactions.

Funds Transfer

To help illustrate transactions, I'll be using the often used case study of transferring funds from one bank account to another. Here, we show code snippets of debit, credit, and transfer methods.

... class BankAccountService {
  public void transfer(MonetaryAmount amount, ...) {
    debit(amount, ...);
    credit(amount, ...);
    ...
  }
  public void credit(MonetaryAmount amount, AccountId accountId) {
    ...
  }
  public void debit(MonetaryAmount amount, AccountId accountId) {
    ...
  }
  ...
}

JDBC Transactions

In plain-vanilla JDBC, transactions are started by setting the Connection's auto-commit mode to false (or to manual commit mode). Once the Connection's auto-commit is set to false, subsequent database changes are not committed until a call to commit() is made. The changes brought about by the SQL operations will not be seen by other connections until the changes are committed. The code snippet below illustrates this.

import java.sql.*;
...
try (Connection conn = dataSource.getConnection()) {
  conn.setAutoCommit(false);
  ... // SQL operations here (inserts, updates, deletes, etc)
  // database changes will not be saved until commit
  conn.commit(); // save changes (all-or-nothing)
} catch (SQLException e) {
  // handle exception
  conn.rollback(); // rollback changes
}

Now, let's apply this to the funds transfer case study.

The transfer() method is now overloaded with an additional connection parameter.

import java.sql.*;
...
... class BankAccountService {
  public void transfer(MonetaryAmount amount, ...)
      throws SQLException {...}
  public void transfer(
        MonetaryAmount amount, ..., Connection conn)
      throws SQLException {...}
  ...
}

The method that does not accept a connection, creates a new connection, and calls the same method that accepts a connection parameter. The method that accepts a connection, uses it to carry out debit and credit operations.

import java.sql.*;

... class BankAccountService {
  public void transfer(MonetaryAmount amount, ...)
      throws SQLException {
    try (Connection conn = dataSource.getConnection()) {
      conn.setAutoCommit(false);
      transfer(amount, ..., conn);
      conn.commit(); // save changes (all-or-nothing)
    } catch (SQLException e) {
      // handle exception
      conn.rollback(); // rollback changes
    }
  }
  public void transfer(
        MonetaryAmount amount, ..., Connection conn)
      throws SQLException {
    debit(amount, ..., conn);
    credit(amount, ..., conn);
    ...
  }
  public void credit(MonetaryAmount amount, AccountId accountId)
      throws SQLException {...}
  public void credit(MonetaryAmount amount, AccountId accountId,
      Connection conn) throws SQLException {...}
  public void debit(MonetaryAmount amount, AccountId accountId)
      throws SQLException {...}
  public void debit(MonetaryAmount amount, AccountId accountId,
      Connection conn) throws SQLException {...}
  ...
}

The debit() and credit() methods are also overloaded. Just like the transfer() methods, the one that does not accept a connection parameter, creates a new connection, and calls the one that accepts a connection object. The method that accepts a connection, uses it to carry out SQL operations.

import java.sql.*;

... class BankAccountService {
  public void transfer(MonetaryAmount amount, ...)
      throws SQLException {
    ... transfer(amount, ..., conn); ...
  }
  public void transfer(
        MonetaryAmount amount, ..., Connection conn)
      throws SQLException {
    debit(amount, ..., conn);
    credit(amount, ..., conn);
    ...
  }
  public void credit(MonetaryAmount amount, AccountId accountId)
      throws SQLException {
    try (Connection conn = dataSource.getConnection()) {
      conn.setAutoCommit(false);
      credit(amount, accountId, conn);
      conn.commit(); // save changes (all-or-nothing)
    } catch (SQLException e) {
      // handle exception
      conn.rollback(); // rollback changes
    }
  }
  public void credit(MonetaryAmount amount, AccountId accountId,
      Connection conn) throws SQLException {
    ... = conn.prepareStatement(...);
    ... // SQL operations for credit
  }
  public void debit(MonetaryAmount amount, AccountId accountId)
      throws SQLException {
    try (Connection conn = dataSource.getConnection()) {
      conn.setAutoCommit(false);
      debit(amount, accountId, conn);
      conn.commit(); // save changes (all-or-nothing)
    } catch (SQLException e) {
      // handle exception
      conn.rollback(); // rollback changes
    }
  }
  public void debit(MonetaryAmount amount, AccountId accountId,
      Connection conn) throws SQLException {
    ... = conn.prepareStatement(...);
    ... // SQL operations for debit
  }
  ...
}

Notice that we'll need to pass connection objects all over the place. Yes, this looks ugly. But stay with me for a few more minutes and read on.

A pattern emerges from these methods. Whenever a database transaction needs to be made, a connection is either provided or established, then used to carry out SQL operations (or database changes), and the changes are committed (or rolled back) by the method that established the connection.

The method accepting a connection object gives up control of the transaction to its caller (as in the case of credit(amount) calling credit(amount, connection)). The scope of transactions can span one method call, or several methods calls (as in the case of transfer(amount) calling debit(amount, connection) and credit(amount, connection)).

As already mentioned, this looks ugly and error-prone. The connection object is passed all over the place. So, how can we improve on this?

Spring-managed JDBC Transactions

First, we'll use Spring's JdbcTemplate to help us deal with JDBC boilerplate code and SQLExceptions. Second, we'll use Spring's declarative transaction management.

When we start using a JdbcTemplate inside BankAccountService, we no longer need to handle connections explicitly, and we can remove those overloaded methods. The connection object actually gets hidden in some thread local object.

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;

@Transactional
... class BankAccountService {
  private JdbcTemplate jdbcTemplate; // injected via constructor
  ...
  public void transfer(MonetaryAmount amount, ...) {
    ...
  }
  public void credit(MonetaryAmount amount, AccountId accountId) {
    jdbcTemplate.update(...); // SQL operations for credit
    ...
  }
  public void debit(MonetaryAmount amount, AccountId accountId) {
    jdbcTemplate.update(...); // SQL operations for debit
    ...
  }
  ...
}

How does JdbcTemplate get a Connection?

For each JdbcTemplate method, it retrieves a connection from the given DataSource that is provided (either as constructor argument, or as property setDataSource(DataSource)). After the JdbcTemplate method returns, the connection is closed. Without transactions, the connection's auto-commit mode remains true. The good thing is, JdbcTemplate is transaction-aware. That means, it will participate in the on-going transaction, if there is one (i.e. use the on-going transaction's connection).

So, how do we set the connection's auto-commit mode to false, so that a transaction can be started and span more than one method call to JdbcTemplate?

To use transactions, we do not set the connection's auto-commit mode to false. Instead, we tell Spring to start transactions. In turn, Spring will retrieve a connection, set its auto-commit mode to false, and keep using this same connection until the transaction is completed (either with all changes saved/committed, or all changes rolled back).

So, how do we tell Spring to start transactions, and what does @Transactional do?

As you might have guessed, the @Transactional annotation tells Spring when to start a transaction (by setting the connection's auto-commit mode to false).

We tell Spring to start transactions by marking methods as @Transactional (or mark the class as @Transactional which makes all public methods transactional). And for Spring to start noticing @Transactional annotations, we'll need to add <tx:annotation-driven /> in our XML-based configuration, or add @EnableTransactionManagement in our Java-based @Configuration.

When Spring encounters this annotation, it proxies the object (usually referred to as a Spring-managed bean). The proxy starts a transaction (if there is no on-going transaction) for methods that are marked as @Transactional, and ends the transaction when the method returns successfully.

Proxy adds transaction behavior

Since JdbcTemplate is transaction-aware, it knows how to get the on-going transaction's connection (if one exists), and not create a new one.

...
import org.springframework.transaction.annotation.Transactional;

@Transactional
... class BankAccountService {
  ...
  public void transfer(MonetaryAmount amount, ...) {
    ...
    debit(amount, ...);
    credit(amount, ...);
    ...
  }
  public void credit(MonetaryAmount amount, AccountId accountId) {...}
  public void debit(MonetaryAmount amount, AccountId accountId) {...}
  ...
}

So, a call to debit() will use a transaction. A separate call to credit() will use a transaction. But what happens when a call to transfer() is made?

Since the transfer() method is marked as @Transactional, Spring will start a transaction. This same transaction will be used for calls to debit() and credit(). In other words, debit(amount) and credit(amount) will not start a new transaction. It will use the on-going transaction (since there is one).

Here's another good blog post to better understand Transactions, Caching and AOP in Spring.