Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shared EntityManager should immediately throw TransactionRequiredException if no transaction in progress [SPR-11923] #16541

Closed
spring-projects-issues opened this issue Jun 27, 2014 · 8 comments
Assignees
Labels
in: data Issues in data modules (jdbc, orm, oxm, tx) type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Jun 27, 2014

Oliver Drotbohm opened SPR-11923 and commented

Section 7.9.1 of the JPA spec states that in a container managed persistence context (that's what you get with LocalContainerEntityManagerFactoryBean), calls to persist(…), merge(…), etc. need to throw a TransactionRequiredException if there's no transaction in progress. However, we currently don't consider this at all which leads to the effect that code like this will not create an exception but also don't persist the entity:

@Repository
public class UserDao {

    @PersistenceContext
    private EntityManager em;

    public void save(User user) {
        em.persist(user);
    }
}

Additionally calling em.flush() will trigger the exception being thrown by the persistence provider but you might run into this scenario as the code relies on a transaction being started on a layer above. If that's forgotten, you get running (invalid) code, that's not barking at you in any way.

Of course this can be worked around by e.g. using Spring Data JPA (which has defaulting of transactions on the repository level) but I think we should adhere to the spec here.


Affects: 3.2.9, 4.0.5

Issue Links:

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jul 14, 2014

Franz Neumann commented

After upgrade on 4.0.6 I become a lot of such TransactionRequiredException's. Do you mead since the version, that I should add @Trasactional to every method, which calls EntityManager? I've tried out it, but my EntityManager seems not to be a transactional one. I've got now:

javax.persistence.TransactionRequiredException: No transactional EntityManager available
	at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:273)
	at com.sun.proxy.$Proxy30.merge(Unknown Source)
	at com.euroit.militaryshop.persistence.dao.impl.CategoryDaoImpl.createOrSave(CategoryDaoImpl.java:51)
	at com.euroit.militaryshop.service.impl.CategoryServiceImpl.createCategory(CategoryServiceImpl.java:48)
	at com.euroit.militaryshop.service.CategoryServiceIT.testFindCategoryByCode2(CategoryServiceIT.java:116)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:233)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jul 14, 2014

Franz Neumann commented

Sorry, I tried out wrong @Transactional (from JDO and not from Spring).

I leave only the first part of my question open:
Do you mead since the version, that I should add @Trasactional (Spring) to every method, which calls EntityManager?

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jul 14, 2014

Oliver Drotbohm commented

Calling EntityManager.merge(…) without a transaction in progress is invalid by definition (see the section of the spec referenced in the original ticket description). Looking at the stack trace I wonder where you currently define transaction boundaries.

Defining none at all is probably not a good idea for production code anyway. Usually transaction boundaries are defined at the service layer level.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jul 15, 2014

Franz Neumann commented

Yeah, it's not so simple. Actually I used Spring Entity Manager in conjuction with GAE Datastore and Datanucleus, where transactions are a little bit different. Probably it's a time to delete Spring and Datanucleus stuff there and start to use just Datastore API. That has not to do with JPA.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jul 15, 2014

Oliver Drotbohm commented

To be honest, I'd be highly alarmed if I was using JPA and then realize that "things are a bit different". If a platform claims to support JPA but then does not behave accordingly - what benefits do you gain from using JPA in the first place?

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jul 15, 2014

Franz Neumann commented

-ist historisch aufgewachsen-

As I said, there is no benefits, such aproach was desribed in one of tutorials and it used to work. But no more.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Dec 5, 2014

Fergus Nelson commented

The activity on this bug says that it was in version 3.2.10 but then removed? Is it possible to get the fix applied to the 3.2.X branch?

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Dec 5, 2014

Juergen Hoeller commented

We don't plan a backport to the 3.2.x line primarily for compatibility with "unusual" JPA providers which may behave correctly for such operations without a transaction as well. We don't want to cause any disruption there.

3.2.x is in strict maintenance mode now, so we try to avoid potential breakages even for questionable behavior. I strongly recommend an upgrade to 4.x for many such improvements in developer guidance and error reporting.

Juergen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: data Issues in data modules (jdbc, orm, oxm, tx) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants