Cannot run 'dropIndexes' in a multi-document transaction - spring

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

Related

DBUnit issue with hibernate statelessSession

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/

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

session.isOpen() vs session.isConnected()

I am working on sample of Hibernate4 with Spring 3.1.
In my sample , While i print sessionFactory.getCurrentSession().isOpen() on console it prints
true
But I am facing an exception on
sessionFactory.getCurrentSession().isConnected()
Exception is:
org.hibernate.HibernateException: isConnected is not valid without active transaction
EDIT : I googled more and found following solution
sessionFactory.getCurrentSession().beginTransaction();
sessionFactory.getCurrentSession().isConnected()
But i don't want to write begin transaction maually every time i opearte with session methods like isConnected, get,find , save etc.
What are the other possible solutions for above exception?
What if i place #Transactional on my dao class methods?
Regards,
Arun Kumar
isConnected is rarely used and for normal DAO methods it is not needed. Get/Find/Save will open a Connection and Transaction if needed behind the scene, nothing you have to take care of manually.

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.

#Transactional Annotation + for a data insertion in a loop

I am using Spring 3, JPA + Hibernate for a CMS application. In that application I have a service class method which is annotated with #Transactional Annotation with rollBack property. Inside that method I am inserting data (ie entity classes) to a table using a loop. For each iteration of the loop entity classes has to be saved to the database. But it is not happening. The commit only happens when the execution of the loop has completed and exits from the method. Then it commits and saves all at once. But I need to read data once it gets inserted into the database before committing in this case. I tried with the ISOLATION LEVEL to read uncommitted but it didn't supported since I am using the default JPADialect. Also tried to add the hibernate implementation of jpaDialect but still it didn't worked. Please help with a workaround for this problem. One more thing, is there any way using propagation required method.
You are right, this is what I stands for in acid. Because the transactions are working in isolation, other transactions cannot see them before they are committed. But playing with isolation levels is a bad practice. I would rather advice you to run each and every iteration in a separate transaction with start and commit inside.
This is a bit tricky in Spring, but here is an example:
public void batch() {
for(...) {
insert(...)
}
}
//necessarily in a different class!
#Transactional
public void insert() {
}
Note that batch() is not annotated with #Transactional and insert() has to be in a different class (Spring service). Too long to comment, but that's life. If you don't like it, you can use TransactionTemplate manually.
remove the transactional annoation on the the method with loop.
In the loop call a separate method to perform the save, make that method transactional
You either need to go with programmatic transactions (Spring's TransactionTemplate or PlatformTransactionManager are the classes to look at, see Spring Doc for programmatic transactions, or you can call another transactional method from within your loop where the transaction is marked with Propagation.REQUIRES_NEW, meaning each call of that method is executed in its own transaction, see here. I think that the second approach requires you to define the REQUIRES_NEW method on a different Spring bean because of the AOP-Proxy. You can also omit the REQUIRES_NEW if the loop is not executed within a transaction.

Resources