I've been looking at the code generated by Spring Roo and I noticed that the persist() method it creates is given Propagation.REQUIRES_NEW. Wouldn't the default propagation be sufficient?
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void Entity.persist() {
if (this.entityManager == null) this.entityManager = entityManager();
this.entityManager.persist(this);
}
Some additional information. Here is the roo log that produced this code:
// Spring Roo 1.1.0.RELEASE [rev 793f2b0] log opened at 2011-02-04 10:01:02
project --topLevelPackage org.sotest.sscce --projectName Test --java 6
// Spring Roo 1.1.0.RELEASE [rev 793f2b0] log closed at 2011-02-04 10:01:04
// Spring Roo 1.1.0.RELEASE [rev 793f2b0] log opened at 2011-02-04 10:01:06
persistence setup --database GOOGLE_APP_ENGINE --provider DATANUCLEUS
entity --class ~.entities.Entity
exit
// Spring Roo 1.1.0.RELEASE [rev 793f2b0] log closed at 2011-02-04 10:02:55
I am using the GAE database with the DN provider. I simply created an entity, I did not touch any files other than issuing the above roo commands. When I open Entity_Roo_Entity.aj I get the above code.
I will try this again on the latest version of Roo and verify the same output. I will also post this issue on a Roo-related forum.
Update: The same code is generated with Roo 1.1.1 (latest version)
SECOND ANSWER (after additional info was added to question)
It's likely due to the use of GAE. The GAE datastore doesn't use traditional transaction semantics. See description of GAE's transaction isolation here. Specifically:
Queries and gets inside a transaction
are guaranteed to see a single,
consistent snapshot of the datastore
as of the beginning of the
transaction. ... This consistent
snapshot view also extends to reads
after writes inside transactions.
Unlike with most databases, queries
and gets inside a datastore
transaction do not see the results of
previous writes inside that
transaction. Specifically, if an
entity is modified or deleted within a
transaction, a query or get returns
the original version of the entity as
of the beginning of the transaction,
or nothing if the entity did not exist
then.
There are also restrictions on querying within a transaction. With this in mind, the REQUIRES_NEW is probably added so that any subsequent reads of the entity within the "first" transaction work as expected. Seems confusing and non-standard, but perhaps this is the best option when working in the constraints of GAE.
FIRST ANSWER
There must be a misunderstanding or something else at
play. I just checked with Roo v1.1.1
generating a simple entity with
Hibernate provider, and the default
transaction propagation is used. This
is also somewhat verified in the
documentation:
All persistence methods are configured
with Spring's Transaction support
(Propagation.REQUIRED,
Isolation.DEFAULT).
Using Propagation.REQUIRES_NEW would
not make sense for the default persist
methods.
I'm not an expert in Roo, so can't
even think of anything that might do
this. Perhaps you should post more of
your code, particularly any
non-standard configurations. Random
questions/ideas:
Are you using Hibernate provider or ?
Any custom configuration of the persisence-unit?
Do see the Propagation.REQUIRES_NEW on all of
your entity persist methods?
Where are you seeing the propagation annotation. (e.g. In the
*_Entity.aj file?)
Is there any chance that your entity class (or one of it's parents)
has it's own .persist method (thus
overriding Roo's generated method).
1:
http://static.springsource.org/spring-roo/reference/html/base-persistence.html
1: ah. I think it's highly likely to be due to use of the GAE/DN provider. I'll modify my answer accordingly. In the meantime, check out the notes around GAE's transaction isolation here: http://code.google.com/appengine/docs/java/datastore/transactions.html .
Related
We have a Spring-Boot application exposing some REST endpoints. We allow for this application to be operated standalone (as executable jar) or as a war to be deployed in a wildfly-11 application-server.
The class defining the REST-endpoints is marked #RestController #Transactional(REQUIRES_NEW) (both on class level, obviously). When running standalone, everything works as expected but when deployed in wildfly, the rollback on exceptions does not work. We established this by sending the exact same REST-message while operating on the exact same database.
We have confirmed via debugging that the final frames of the stacktrace is identical in both cases and especially in both cases we see a transactional-proxy around our REST-controller bean.
One difference would be, that within wildfly the application will use a jndi-datasource, prepared by wildfly while standalone the spring-boot will manage the database-connections.
Any idea what is wrong here?
Edit
I just tried explicitly invoking setRollbackOnly on the JtaTransactionmanager from within my code. The transaction will still commit. This sort of looks like a bug in Spring Boot to me.
Edit 2
Debugging further reveals that the transaction seems to be set to autocommit - every statement is immediately written to the database. This seems to be in violation to the annotation #Transactional and also to the fact that Spring creates a transactional proxy around my bean.
It's not a full answer - just a reasoning. JNDI is usally used at the app server layer whereas JDBC - at the application layer. At the App server layer are used global transaction settins that are overriding app settings. Follow the spring doc to get more
For reasons beyond my understanding the default transactional behaviour when deploying a spring-boot webapp to an application-server is auto-commit.
The solution to this problem is to enrich your application-configuration with the property spring.datasource.tomcat.default-auto-commit=false
I see with the Spring Boot you don't need to open and close the hibernate session.
But for the understanding purpose how it is working internally, On which layer it is opening the hibernate session and when it is closing.
I created one POC.
I have one Spring boot application it has two Entity One is Customer and other is Address and there is one to Many relation between Customer and Address.
And I have one two Apis one is adding record and other is fetching all the records.
These APis are there in the CustomerEndpoint and it is annotated with
#RestController
#RequestMapping(value="/customer").
And also created CustomerRepository which extends CrudRepository for saving and fetching the Customer records.
So as per my understanding while fetching the Customer using CustomerRepository inside CustomerEndpointclass should throw LazyInitialization error when we will say customer.getAddress(as its fetchtype is LAZY).
But it is not throwing any error, it is working properly.
I was thinking the hibernate session not be there in the CustomerEndpoint class.
Can anyone help me how this Hibernate session is maintained by Spring boot?
As everybody is thinking it as a duplicate of another question but my question is not top of their explanation as according to them session is valid till the Repository so according to that i should get LazyInitialization exception while saying customer.getAddress inside CustomerEndpoint as it is not a Repository but i am not getting any Exception
First of all it is not a good practice to use Repository layer in your Presentation layer.
OSIV (Open Session in View) is enabled by default in Spring Boot, and OSIV is really a bad idea from a performance and scalability perspective.
Because of this you are not getting the exception and able to work in your presentation layer.
Check by putting the follwoings in your application.properties file
spring.jpa.open-in-view=false
You can refer OSIV AntiPattern for more details
I think, It still works If your customer.getAddress is inside the transaction
I have a Spring Boot application and tests with #SpringBootTest.
I'm trying to have my database in the same state for each test.
My test class is annotated with #Transactional and #Rollback.
And the services I'm testing are also annotated with #Transactional.
From what I understand while activating TransactionManager TRACE logs, the Spring Boot app transactions are committed and the test transaction is rolled back as expected.
The issue comes from the fact that there are 2 different transactions created with my setup: one for test and one for the app.
Do you know what I could do to have the transaction created in the test be the same in the app?
Example code:
https://github.com/sey/transactional
You will see that GreetingsResourceTest fails because I think there are 2 different contexts not sharing transaction.
However GreetingsServiceTest works as expected as there is not a specific application context created during the test.
Spring has a propagation level e that represents transaction propagation behaviors for use with the Transactional annotation. Is the only way that you can overwrite how Spring will create Transactions using #Transactional:
MANDATORY
Support a current transaction, throw an exception if none exists.
NESTED
Execute within a nested transaction if a current transaction exists, behave like PROPAGATION_REQUIRED else.
NEVER
Execute non-transactionally, throw an exception if a transaction exists.
NOT_SUPPORTED
Execute non-transactionally, suspend the current transaction if one exists.
REQUIRED
Support a current transaction, create a new one if none exists.
REQUIRES_NEW
Create a new transaction, and suspend the current transaction if one exists.
SUPPORTS
Support a current transaction, execute non-transactionally if none exists.
I am using hibernate for the REST API. Right now all the transactions are handled by explicitly calling beginTransaction and transaction.commit. The transaction is rolled back in case of a failure. I am looking to use #Transactional instead of all the beginTransactions and commit transactions. Could someone tell me how can I integrate #Transactional in my hibernate. I am using mysql for querying the database.
You can annotate your query method with #Transactional so you get your transaction opened, commited and closed when your method ends.
Be careful about isolation levels (https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Transactional.html#isolation--) because it indicates when Spring will create a new session for your transaction, or simply use already opened one.
When you thrown an exception on your method, transaction gets an automatic rollback and you're good :)
You can use Spring Framework with Hibernate Integration. The advantage is spring manages the Hibernate session's and all the low level things that we have to manage manually in hibernate like granular commit etc. Here is the example of this. this is older repository so uses older version of Spring and Hibernate but you can upgrade it here
Am facing an issue while upgrading spring from 1.2.5 to 4.1.1. With the spring1.2.5 spring was committing all my changes to the dao objects in the table without an explicit update query call. But after the upgrade changes is not getting persisted automatically.
Below is my value for my hibernate.transaction.jta.platform configuration
<prop key="hibernate.transaction.jta.platform">org.hibernate.service.jta.platform.internal.WeblogicJtaPlatform</prop>
After debugging i found in the transaction interceptor class of spring transaction jar, commitTransactionAfterReturning method is being invoked which is committing all changes in the transaction. But am not able to find a equivalent method in the transaction interceptor class of spring transaction 4.1.1 jar. I do not want do explicit updates for all the changes & I want spring to handle them as it was performing in 1.2.5 version.
Please let me know how to handle the above scenario.