DBUnit issue with hibernate statelessSession - spring

I'm trying to test my code using Spring and DBunit (http://springtestdbunit.github.io/)
Once inside the unit test:
sessionFactory.getCurrentSession().createCriteria(MyEntity.class).list()
will return the list of entities inserted by DBUnit, so it did insert records in teh database (MYSQL).
But:
sessionFactory.openStatelessSession().createCriteria(MyEntity.class).scroll(FORWARD_ONLY).next()
will return false! It can't find any records using the stateless session.
Beforehand, I use to insert the same records using Liquibase, and this piece of code worked perfectly.
Using HSql it's even worse, it totally freezes when trying to open the stateless session... (on the scroll() instruction...)
Thank you for your help!

OK! So this actually have nothing to do with DBunit, sort of...
This code simple shows the same issue, and no DBUnit involve:
MyEntity myEntity = new MyEntity ();
sessionFactory.getCurrentSession().save(myEntity );
assertEquals(1, sessionFactory.getCurrentSession().createCriteria(MyEntity .class).list()
.size());
assertTrue(sessionFactory.openStatelessSession().createCriteria(MyEntity .class)
.scroll(ScrollMode.FORWARD_ONLY).next());
First assert is ok, second fails.
So I guess it is a simple hibernate problem, and I also guess that liquibase was doing something to prevent it somehow... Probably a transaction issue?

SO! It seems to be a transaction issue in the end as a simple
sessionFactory.getCurrentSession().getTransaction().commit();
make the test go green!
Question now is how to make DBUnit commit the transaction I suppose...
At the beginning of the test, after DBUnit initialization, I run:
sessionFactory.getCurrentSession().getTransaction().wasCommitted()
And it returns false. This think the issue comes from there.

Problem solved!
Thanks to this:
https://tadaya.wordpress.com/2008/04/27/transaction-aware-datasource-use-dbunit-hibernate-in-spring/

Related

Cannot run 'dropIndexes' in a multi-document transaction

I am using Spring Mongo for query from Database. And i try drop index by following code
mongoOperations.indexOps(MY_COLLECTION).dropIndex("rowIndex");
and i get error
Cannot run 'dropIndexes' in a multi-document transaction
How can i fix this error ?
I have fixed this, it happen because i place the code inside method with annotation #Transactional. Example:
#Transactional
void funnyAction(){
mongoOperations.indexOps(MY_COLLECTION).dropIndex("rowIndex");
}
I have fixd by moving the code outside the method

Spring JPA derived delete query

I am using Spring Data rest with Spring JPA. I have one Spring JPA derived delete query that should deletes the list of items but when I am executing it and noticing the console I found that it is executing select query instead that's very strange situation I have ever come across.
#RepositoryRestResource(collectionResourceRel="revision", path="revision")
interface RevisionRepository extends JpaRepository<Revision, Long> {
List<Revision> deleteByContentId(long contentId)
}
I have even tried using Long instead of List<Revision> doesn't work and also have tried removeByContentId it is also doesn't work either and keeps executing the select query instead delete query.
when I am running this method this is what I got on my console
Hibernate: select revision0_.id as id1_2_, revision0_.body as body2_2_, revision0_.content_id as content_3_2_, revision0_.content_type as content_4_2_, revision0_.date_created as date_cre5_2_, revision0_.file_name as file_nam6_2_, revision0_.folder_id as folder_i7_2_, revision0_.force_ssl as force_ss8_2_, revision0_.is_active as is_activ9_2_, revision0_.lookup as lookup10_2_, revision0_.meta_description as meta_de11_2_, revision0_.meta_keywords as meta_ke12_2_, revision0_.meta_title as meta_ti13_2_, revision0_.nav_item as nav_ite14_2_, revision0_.nav_order as nav_ord15_2_, revision0_.regions_objects as regions16_2_, revision0_.summary as summary17_2_, revision0_.title as title18_2_, revision0_.updated_by as updated19_2_, revision0_.user_id as user_id20_2_ from revisions revision0_ where revision0_.content_id=?
does anyone having any idea why it is behaving strangely?
You need to add #Modifying annotation to your delete method. You will also need to make sure it is executed within a transaction, so you might need to add #Transactional annotation too, if you invoke this method not in a transaction.
Please see an example:
#Modifying
#Transactional
int deleteByFieldName( Long fieldValue );
In latest Spring >=5 and Spring Boot >=2.
#Transactional
int deleteByFieldname( Long fieldValue );
Works fine.
Note 1:
#Modifiyng annotation has absolutely no effect in this. It only work for #Query annotation. Without #Query, it is simply ignored.
Note 2:
In naming convention, that depends on the configured NamingStrategy, the CamelCase might be interpreted and nested entity relation or "_" in field name. So "Fieldname" and "FieldName" mean very different things.
Note 3:
Derived delete queries like this have a really nasty n+1 side effect. They ALWAYS first issue select for the rows then isses delete each row/entity one by one with separate delete stement. No way around this, except using #Query() with manual delete statement. And using #Query then requires the #Modifying for delete query.

Spring Data JPA save() throws NPE

I wrote a web service with spring boot using spring data jpa for persistence.
The webservice has some static objects (in Singleton Bean) that regulary needs to be backed up to my database.
Sometimes! (This sucks...I dont' really know what happens) when I call
ObjectType updated = myRepository.save(existingObject)
I get an java.lang.NullPointerException - without usable stacktrace as the method doing this is running via #Scheduled.
I tried debugging and existingObject seems to be absolutely fine. The error only occurs, when existingObject is actually NOT a new object (i.e. when id != 0)
P.S. I am using Spring Boot therefore not really using EntityManager. I only use the #Autowired myRepository.
I'm seeing something similar happening. During save, it seems the object is re-fetched from DB (perhaps to see which fields were altered?) but a ManyToOne relationship is not loaded (even though the FetchType is explicitly set to EAGER).
For some reason, a compareTo is called on the relationship. The related object isn't null, but it only has its ID filled in (presumably because that was available in the object that was fetched from the DB). All other fields are null.
When the compareTo then does its stuff, a NullPointerException follows.
As to the actual solution, I don't know yet, as I would have expected the FetchType EAGER to make sure the relationship is loaded. Hopefully this helps someone to further find the root cause.
(I would have added this as a comment as it doesn't actually answer the question, but StackOverflow won't let me due to insufficient reputation...)
You haven't provided enough information. IF that line is where the NullPointerException is occurring, then the only possibilities are that myRepository is null, or existingObject is null. However, it's possible the NullPointerException is happening as a result of something in the save. Wrap the code in a try catch, and log the exception stacktrace to file.
If needed, checkout the logging customization notes here:
http://projects.spring.io/spring-boot/docs/spring-boot/README.html

Spring Database Integration Test, when to flush or?

I am fairly new to spring, and doing some integration tests.
Using Hibernate, MySql and Spring data JPA.
I am using transaction support and everything gets rolled back at the end of each test.
For example:
#Test (expected=DataIntegrityViolationException.class)
public void findAndDelete() {
UUID uuid = UUID.fromString(TESTID);
User user= iUserService.findOne(uuid);
iUserService.delete(cashBox);
iUserService.flush();
assertNull(iUserService.findOne(uuid));
}
In the above code, I call the iUserService.flush(), so that the sql gets sent to the DB, and an expected DataIntegrityViolationException occurs because there is a foreign key from User to another table (Cascade is not allowed, None). All good so far.
Now, if I remove the iUserService.flush()
then the expected exception does not occur because the sql does not get sent to the DB.
I tried adding the flush() into a teardown #After method, but that didn't work as the test does not see the exception outside of the test method.
Is there any way to avoid calling the flush within the test methods?
It would be preferable if the developers on my team did not have to use the flush method at all in their testing code
Edit:
I tried adding the following
#Before
public void before() {
Session session = entityManagerFactory.createEntityManager().unwrap(Session.class);
session.setFlushMode(FlushMode.ALWAYS);
}
but it does seem to flush the sqls, before each query.
In my humble opinion, it's better than the developers of your team know what they are doing.
It includes the things that are configured by default and the consequences of that.
Please, take a look to why you need avoid false positives when testing ORM code

Spring transaction propagation_required issue

In our java project we are using ORM with hibernate and spring.
I had problems in deleting persistent objects. For example this sample method gets entities by ids and then delete them:
#Transactional
public void remove(List<Long> ids) {
SearchTemplate template = new SearchTemplate();
template.addParameter("milestoneId",ids);
List <InvoiceQueue> items = this.findByCriteria(template);
...
this.delete(items);
}
Method executes Ok without any exception but doesn't actually delete the items from the DB.
Adding the following annotation to the method definition #Transactional(propagation = Propagation.REQUIRES_NEW) solves the problem.
Can anyone explain why it doesn't work with the default propagation type PROPAGATION_REQUIRED.
Thanks in advance.
Environment details :
hibernate.version 3.5.5-Final, spring.version 3.0.5.RELEASE
Really just repeating what #PeterBagyinszki said in his comment, but the reason quite probably is that the transaction within which your delete occurs gets rolled back due to some other part throwing an exception, and all the changes made during the transaction get canceled. With Propagation.REQUIRES_NEW, the delete is done within it's own separate nested transaction. The outcome of the nested transaction (committed or rolled back) won't affect the "outer" transaction and vice versa.
Check your logs to see what is causing the transaction to be rolled back, note that even something like a simple SELECT -query failing with something like NoResultException will cause the transaction to roll back, unless you explicitly state in the #Transactional-annotation it not to roll back on certain exceptions.

Resources