Make #Transactional and #Rollback work with Spring Boot Test - java

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.

Related

Using #Transactional with hibernate

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

Exception thrown when using non-XA datasource in two-phase commit transaction

My Websphere application has 3 datsources. Two of them are XA and the other is non-XA.
I have made a Java method transactional by annotating the method with #transactional annotation.
Within the method, 3 tasks are performed. The first one is using one XA datasource to do some update, then the second one uses the non-XA datasource to select a few records and the final task uses another XA datasource to do some update again.
However, an exception is thrown with the following error:
An illegal attempt to commit a one phase capable resource with existing two phase capable resources
I want to know why the above error occurs even my application just uses the non-XA to select some data and no commit is required and how I can get rid of the problem if I am not allowed to change the non-XA datasource to XA.
The non-XA resource cannot by default participate in a distributed transaction. So you have the following options:
Change datasource to XA - you wrote that you cannot do that
Try to enable Last Participant Support - Last participant support is an extension to the transaction service that enables a single one-phase resource to participate in a two-phase transaction with one or more two-phase resources.
Set this (nonXA) datasource to be non transactional, if you don't need transactions for it. It will not be enlisted in the transaction:
Select Resources > JDBC > Data sources
Select the name of the data source that you want to configure.
Select WebSphere Application Server data source properties from the Additional Properties heading.
Select Non-transactional data source.
Click OK.
wrap that nonXA call in EJB, and mark it as not supporting transactions.
Manually manage transaction - don't use container managed transaction, but handle transaction inside your method manually using Transaction API.
when starting the second task, the previous task which does updates on a XA datasource need to be commit or rolled back while you are using #Transaction annotation the whole tasks automatically go through one transaction so don't use #Transaction annotation and instead of it put each task inside separate transaction

javax.transaction.Transactional vs org.springframework.transaction.annotation.Transactional

I don't understand what is the actual difference between annotations javax.transaction.Transactional and org.springframework.transaction.annotation.Transactional?
Is org.springframework.transaction.annotation.Transactional an extension of javax.transaction.Transactional or they have totally different meaning? When should each of them be used? Spring #Transactinal in service layer and javax in DAO?
Thanks for answering.
Spring has defined its own Transactional annotation to make Spring bean methods transactional, years ago.
Java EE 7 has finally done the same thing and now allows CDI bean methods to be transactional, in addition to EJB methods. So since Java EE 7, it also defines its own Transactional annotation (it obviously can't reuse the Spring one).
In a Java EE 7 application, you'll use the Java EE annotation.
In a Spring application, you'll use the Spring annotation.
Their use is the same: informing the container (Java EE or Spring) that a method is transactional.
Another difference is how Spring handles the #Transactional annotations
org.springframework.transaction.annotation.Transactional is always taken into account
javax.transaction.Transactional is taken into account only when EJB3 transactions are present. EJB3 transactions' presence is done by checking if class javax.ejb.TransactionAttribute is available in the classpath (from version 2.5.3 to 3.2.5).
Thus you can end up with your annotations not being taken into account if only javax.transaction.Transactional is in your classpath and not javax.ejb.TransactionAttribute.
This can be the case if you're working with Hibernate: hibernate-core (4.3.7.Final) depends on jboss-transaction-api_1.2_spec (1.0.0.Final), which doesn't provide javax.ejb.TransactionAttribute.
Declarative transaction scope
Both the Spring and JPA #Transaction annotation allow you to define the scope of a given application transaction.
So, if a service method is annotated with the #Transactional annotation, it will run in a transactional context. If the service method uses multiple DAO or Repositories, all read and write operations will be executed in the same database transaction.
Spring #Transactional
The org.springframework.transaction.annotation.Transactional annotation has been available since the 1.2 version of the Spring framework (circa 2005), and it allows you to set the following transactional properties:
isolation: the underlying database isolation level
noRollbackFor and noRollbackForClassName: the list of Java Exception classes that can be triggered without triggering a transaction rollback
rollbackFor and rollbackForClassName: the list of Java Exception classes that trigger a transaction rollback when being thrown
propagation: the transaction propagation type given by the Propagation Enum. For instance, if the transaction context can be inherited (e.g., REQUIRED) or a new transaction context should be created (e.g., REQUIRES_NEW) or if an exception should be thrown if no transaction context is present (e.g., MANDATORY) or if an exception should be thrown if a current transaction context is found (e.g., NOT_SUPPORTED).
readOnly: whether the current transaction should only read data without applying any changes.
timeout: how many seconds should the transaction context be allowed to run until a timeout exception is thrown.
value or transactionManager: the name of the Spring TransactionManager bean to be used when binding the transaction context.
Java EE #Transactional
The javax.transaction.Transactional annotation was added by the Java EE 7 specification (circa 2013). So, the Java EE annotation was added 8 years later than its Spring counterpart.
The Java EE #Transactional defines just 3 attributes:
dontRollbackOn: the list of Java Exception classes that can be triggered without triggering a transaction rollback
rollbackOn: the list of Java Exception classes that trigger a transaction rollback when being thrown
value: the propagation strategy, given by the TxType Enum. For instance, if the transaction context can be inherited (e.g., REQUIRED) or a new transaction context should be created (e.g., REQUIRES_NEW) or if an exception should be thrown if no transaction context is present (e.g., MANDATORY) or if an exception should be thrown if a current transaction context is found (e.g., NOT_SUPPORTED).
Which one to choose?
If you're using Spring or Spring Boot, then use the Spring #Transactional annotation, as it allows you to configure more attributes than the Java EE #Transactional annotation.
If you are using Java EE alone, and you deploy your application on a Java EE application server, then use the Java EE #Transactional annotation.
Please be careful, (this issue happened in tomcat),
If your application is SPRING web application and you are using Spring's transaction handling mechanism that is #org.springframework.transaction.annotation.Transactional, then don't mix it with javax.transaction.Transactional.
That is Always use, #org.springframework.transaction.annotation.Transactional in a spring application consistently.
Otherwise we may end up with this error,
org.springframework.orm.jpa.JpaSystemException: commit failed; nested exception is org.hibernate.TransactionException: commit failed
........
Caused by: java.sql.SQLException: Protocol violation: [0]

can you create your own JTA transaction?

I am loading a large set of data into a database from a webservice. I am using eclipslink for persistence and running the application on glassfish 3.0. I run into problems on my test data set in that there are a few foreign key constraint violations. I am fine with the violation, I do not want that data if it is not complete. My problem however comes in that the exception is thrown in the container. That then marks my transaction for a rollback, and I get no data at all then.
I would like to continue using JTA but am not sure if I can do what I want to achieve, and that is create my own JTA transaction so I can control when it commits,etc. I am not sure if that is a good idea though as I feel by doing so I may be destroying some of the benefits of using JTA.
So is it possible to get a JTA transaction?
Do the database work in a method of a session bean. Annotate that method with:
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
It will be given its own transaction. The outer transaction will be suspended while it does its stuff.
http://wiki.eclipse.org/Using_Advanced_Unit_of_Work_API_%28ELUG%29#Integrating_the_Unit_of_Work_with_an_External_Transaction_Servicestrong text**
Read How to Acquire a Unit of Work with an External Transaction Service. Apparently you can snatch the UserTransaction and/or start your own by querying the container JNDI for UserTransaction

Why does Spring Roo give persist() Propogation.REQUIRES_NEW

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 .

Categories

Resources