Wait for index to flush with Hibernate Search and JUnit - spring

I'm writing a JUnit test for a Hibernate Search (Lucene) repo. In a #Before method, I persist an entity, and then in a #Test method, I want to search for it. Problem is, the index is apparently not updated by the time the test method is run.
My test class is annotated with #Transactional. I tried annotating just the #Before method with #Transactional, but I must be doing something wrong because Hibernate Search complains about a lack of session while indexing (trying to access lazy loaded properties).
I even tried sleep()ing at the beginning of the test method, to no avail.
I tried calling Search.getFullTextEntityManager(entityManager).createIndexer().startAndWait() in the #Before method, but that appears to run forever.

It's not a good idea to annotate the test as Transactional as you might need to control the transaction.
Hibernate Search is going to flush the changes to the index at transaction commit: you need to commit the transaction before running the query.
As an alternative FullTextSession has a method flushToIndexes() which you could use to force an immediate flush, but then you're not testing the full end to end transactional behavior. Also if you flush the changes to the index, a transaction rollback won't undo them so if you're attempting to have transactional tests to keep them independent that's not going to be good enough.

Related

How to deal with Spring hibernate no lock aquired exception inside a transaction

I have applied #Transactional in my interface, and inside my serviceImpl, the corresponding method is calling some other methods, one method is reading, another method is writing. Although I have anotated as Transactional, when I am giving concurrent request, my insert method is throwing org.hibernate.exception.LockAcquisitionException: error.
Another problem is, this insert method is a shared method and it performs the insert method like Dao.save(obj) . Dao.save() is a generic method So i can not do anything here. I have to apply something on interface to avoid no lock aquired exception.
Is it possible to tell wait untill lock is aquired? Or retry if transaction is failed? Or lock all the tables until the transaction is completed so that another request can not access the relevent resources?
My hibernate version is 3.x, And database is mysql 5.6
The best way to do this is,
Mark your methods transactional
In your mysql database settings set the transaction isolation level as SERIALIZABLE

#Transactional with 1 save statement

Does it make sense mark with spring's #Transactional a method with a single save sentence?
For example:
// does it make sense mark it with #Transactional if it only has 1 save sentence?
#Transactional
public void saveMethod() {
user.save()
}
If you´re using Spring data interface, you dont need use #transactional annotation. Only in case that you want to provide two execution against the database and you want to share the transaction, so then rollback of both actions can be made.
Anyway it is always better use #transactional even as read-only for get queries(setting the FlushMode to MANUAL to let persistence providers potentially skip dirty checks when closing the EntityManager), so I would suggest put the #transactional as Service layer and read-only for get queries.
Yes because any "modifications" on the database requires a transaction (to commit the changes). You might think otherwise because of auto-commit, but in the end, there is still a transaction there somewhere.
But it is always a good thing to explicitly define the boundaries of your transaction (when transaction is started and when it is committed).

Spring and JUnit, the difference of annotating classes and methods with #Transaction?

I would like to understand that if I annotate my junit class with #Transactional, Spring will create only one transaction which will be shared among my #Test methods and rolled back at the end. Whereas if instead I mark each single #Test with #Transactional, a new transaction will be created and rolled back on a #Test basis. I didn't quite find the expected behaviour in the official documentation (link).
Putting #Transactional on a class level is equivalent to putting it on each of the test methods.
I don't think there is an easy way of achieving your first scenario, ie, a single transaction for all the tests. I am not sure it would make much sense anyway since tests will be executed in a random order so you cannot rely on seeing each others modifications. Of course you can always explicitly call your methods from a single uber-test with a single transaction.
#Transactional at JUnit test case class level will start new transaction before each test method and roll it back afterwards.
You cannot easily start new transaction at the beginning of test class and keep it open for the whole class, at least Spring is not supporting this. Your first workaround would be to use #BeforeClass/#AfterClass pair, but they must be static thus you don't have access to transactional manager.
But first ask yourself a question, why do you want to do this? Sounds like one test depends on the output or database side effects of the other. This is a big anti-pattern in testing, not to mention JUnit does not guarantee the order in which test methods are executed. Maybe you just need a database setup before each test case? #Before and #After are executed within the context of Spring transaction, so you can use them there.

Grails service transactional behaviour

In a Grails app, the default behaviour of service methods is that they are transactional and the transaction is automatically rolled-back if an unchecked exception is thrown. However, in Groovy one is not forced to handle (or rethrow) checked exceptions, so there's a risk that if a service method throws a checked exception, the transaction will not be rolled back. On account of this, it seems advisable to annotate every Grails service class
#Transactional(rollbackFor = Throwable.class)
class MyService {
void writeSomething() {
}
}
Assume I have other methods in MyService, one of which only reads the DB, and the other doesn't touch the DB, are the following annotations correct?
#Transactional(readOnly = true)
void readSomething() {}
// Maybe this should be propagation = Propagation.NOT_SUPPORTED instead?
#Transactional(propagation = Propagation.SUPPORTS)
void dontReadOrWrite() {}
In order to answer this question, I guess you'll need to know what my intention is:
If an exception is thrown from any method and there's a transaction in progress, it will be rolled back. For example, if writeSomething() calls dontReadOrWrite(), and an exception is thrown from the latter, the transaction started by the former will be rolled back. I'm assuming that the rollbackFor class-level attribute is inherited by individual methods unless they explicitly override it.
If there's no transaction in progress, one will not be started for methods like dontReadOrWrite
If no transaction is in progress when readSomething() is called, a read-only transaction will be started. If a read-write transaction is in progress, it will participate in this transaction.
Your code is right as far as it goes: you do want to use the Spring #Transactional annotation on individual methods in your service class to get the granularity you're looking for, you're right that you want SUPPORTS for dontReadOrWrite (NOT_SUPPORTED will suspend an existing transaction, which won't buy you anything based on what you've described and will require your software to spend cycles, so there's pain for no gain), and you're right that you want the default propagation behavior (REQUIRED) for readSomething.
But an important thing to keep in mind with Spring transactional behavior is that Spring implements transaction management by wrapping your class in a proxy that does the appropriate transaction setup, invokes your method, and then does the appropriate transaction tear-down when control returns. And (crucially), this transaction-management code is only invoked when you call the method on the proxy, which doesn't happen if writeSomething() directly calls dontReadOrWrite() as in your first bullet.
If you need different transactional behavior on a method that's called by another method, you've got two choices that I know of if you want to keep using Spring's #Transactional annotations for transaction management:
Move the method being called by the other into a different service class, which will be accessed from your original service class via the Spring proxy.
Leave the method where it is. Declare a member variable in your service class to be of the same type as your service class's interface and make it #Autowired, which will give you a reference to your service class's Spring proxy object. Then when you want to invoke your method with the different transactional behavior, do it on that member variable rather than directly, and the Spring transaction code will fire as you want it to.
Approach #1 is great if the two methods really aren't related anyway, because it solves your problem without confusing whoever ends up maintaining your code, and there's no way to accidentally forget to invoke the transaction-enabled method.
Approach #2 is usually the better option, assuming that your methods are all in the same service for a reason and that you wouldn't really want to split them out. But it's confusing to a maintainer who doesn't understand this wrinkle of Spring transactions, and you have to remember to invoke it that way in each place you call it, so there's a price to it. I'm usually willing to pay that price to not splinter my service classes unnaturally, but as always, it'll depend on your situation.
I think that what you're looking for is more granular transaction management, and using the #Transactional annotation is the right direction for that. That said, there is a Grails Transaction Handling Plugin that can give you the behavior that you're looking for. The caveat is that you will need to wrap your service method calls in a DomainClass.withTransaction closure and supply the non-standard behavior that you're looking for as a parameter map to the withTransaction() method.
As a note, on the backend this is doing exactly what you're talking about above by using the #Transactional annotation to change the behavior of the transaction at runtime. The plugin documentation is excellent, so I don't think you'll find yourself without sufficient guidance.
Hope this is what you're looking for.

junit test case transaction not getting committed - no errors

We have implemented JUnit4 in our application which uses Spring core & JPA with DB2.
We need to test a full functionality which retrieves data from one database and merges into another database.
Test case for retrieving the data from 1st database is written and it is running without any error perfectly but the records are not store into the 2nd database.
Implementation
The TestCase class we have included the following annotations to make the test case run under a transaction if necessary,
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
TransactionalTestExecutionListener.class})
#ContextConfiguration(locations={""})
#TransactionConfiguration(transactionManager="defaultTransactionManager", defaultRollback=false)
#Transactional
In the application we have a manager class to perform this operation with doSynch() method. From that method crudHelper class's txStore() method will be called to initialize and call doStore() method (in same class) to merge the entity to database.
Following are the transactional declarative through out this test case logic
TestCase testSynch() - #Transactional(propagation=Propagation.SUPPORTS)
Manager doSynch() - #Transactional(propagation=Propagation.NEVER)
CRUDHelper txStore() - #Transactional(propagation=Propagation.REQUIRED)
doStore() - No Transactional annotation
doSynch() is marked as NEVER as at that point it doesn't need any transaction and in further levels such as in CRUDHelper the transaction can be marked as REQUIRED to ensure a transaction to be available.
Problem
Here when we run the test case which calls the Manager's doSynch() method to test the functionality, complete flow is working perfect except that records are not merged and no errors are thrown.
The Manager method when called from a JSP works great.
Also we tested by calling txStore() directly from test case and it also works fine.
Please let us know whether the transaction management is not proper or a work around to this issue will be of greater help. Also pls update me if the issue or environment is not clear. Thanks in advance.!!
Do you mark your methods with the #Rollback annotation?
From the JavaDoc:
Test annotation to indicate whether or
not the transaction for the annotated
test method should be rolled back
after the test method has completed.
If true, the transaction will be
rolled back; otherwise, the
transaction will be committed.

Resources