SharedEntityManagerCreator immediately throws TransactionRequiredException on persist, merge, remove etc (as required by JPA spec)
Issue: SPR-11923
This commit is contained in:
parent
cab0b97a83
commit
045d7357d5
|
|
@ -23,10 +23,13 @@ import java.lang.reflect.InvocationHandler;
|
|||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.TransactionRequiredException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
|
@ -61,6 +64,23 @@ public abstract class SharedEntityManagerCreator {
|
|||
|
||||
private static final Class<?>[] NO_ENTITY_MANAGER_INTERFACES = new Class<?>[0];
|
||||
|
||||
private static final Set<String> transactionRequiringMethods = new HashSet<String>(6);
|
||||
|
||||
private static final Set<String> queryTerminationMethods = new HashSet<String>(3);
|
||||
|
||||
static {
|
||||
transactionRequiringMethods.add("joinTransaction");
|
||||
transactionRequiringMethods.add("flush");
|
||||
transactionRequiringMethods.add("persist");
|
||||
transactionRequiringMethods.add("merge");
|
||||
transactionRequiringMethods.add("remove");
|
||||
transactionRequiringMethods.add("refresh");
|
||||
|
||||
queryTerminationMethods.add("getResultList");
|
||||
queryTerminationMethods.add("getSingleResult");
|
||||
queryTerminationMethods.add("executeUpdate");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a transactional EntityManager proxy for the given EntityManagerFactory.
|
||||
|
|
@ -246,6 +266,13 @@ public abstract class SharedEntityManagerCreator {
|
|||
}
|
||||
// Still perform unwrap call on target EntityManager.
|
||||
}
|
||||
else if (transactionRequiringMethods.contains(method.getName())) {
|
||||
// We need a transactional target now, according to the JPA spec.
|
||||
// Otherwise, the operation would get accepted but remain unflushed...
|
||||
if (target == null) {
|
||||
throw new TransactionRequiredException("No transactional EntityManager available");
|
||||
}
|
||||
}
|
||||
|
||||
// Regular EntityManager operations.
|
||||
boolean isNewEm = false;
|
||||
|
|
@ -337,8 +364,7 @@ public abstract class SharedEntityManagerCreator {
|
|||
throw ex.getTargetException();
|
||||
}
|
||||
finally {
|
||||
if (method.getName().equals("getResultList") || method.getName().equals("getSingleResult") ||
|
||||
method.getName().equals("executeUpdate")) {
|
||||
if (queryTerminationMethods.contains(method.getName())) {
|
||||
// Actual execution of the query: close the EntityManager right
|
||||
// afterwards, since that was the only reason we kept it open.
|
||||
EntityManagerFactoryUtils.closeEntityManager(this.em);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
package org.springframework.orm.jpa;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.TransactionRequiredException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
|
@ -40,4 +42,46 @@ public class SharedEntityManagerCreatorTests {
|
|||
is(notNullValue()));
|
||||
}
|
||||
|
||||
@Test(expected = TransactionRequiredException.class)
|
||||
public void transactionRequiredExceptionOnJoinTransaction() {
|
||||
EntityManagerFactory emf = mock(EntityManagerFactory.class);
|
||||
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
|
||||
em.joinTransaction();
|
||||
}
|
||||
|
||||
@Test(expected = TransactionRequiredException.class)
|
||||
public void transactionRequiredExceptionOnFlush() {
|
||||
EntityManagerFactory emf = mock(EntityManagerFactory.class);
|
||||
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
|
||||
em.flush();
|
||||
}
|
||||
|
||||
@Test(expected = TransactionRequiredException.class)
|
||||
public void transactionRequiredExceptionOnPersist() {
|
||||
EntityManagerFactory emf = mock(EntityManagerFactory.class);
|
||||
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
|
||||
em.persist(new Object());
|
||||
}
|
||||
|
||||
@Test(expected = TransactionRequiredException.class)
|
||||
public void transactionRequiredExceptionOnMerge() {
|
||||
EntityManagerFactory emf = mock(EntityManagerFactory.class);
|
||||
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
|
||||
em.merge(new Object());
|
||||
}
|
||||
|
||||
@Test(expected = TransactionRequiredException.class)
|
||||
public void transactionRequiredExceptionOnRemove() {
|
||||
EntityManagerFactory emf = mock(EntityManagerFactory.class);
|
||||
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
|
||||
em.remove(new Object());
|
||||
}
|
||||
|
||||
@Test(expected = TransactionRequiredException.class)
|
||||
public void transactionRequiredExceptionOnRefresh() {
|
||||
EntityManagerFactory emf = mock(EntityManagerFactory.class);
|
||||
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
|
||||
em.refresh(new Object());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue