Rollback ORMapper Queries - java

We're using MyBatis (3.0.5) as our or-mapping tool (and I don't have any say-so over that!).
I've created a Response object that, through MyBatis, mapped to our [responses] database table (we use PostgreSQL).
Actually, the ormapping structure we use is as follows:
ResponseMapper.xml - this is the XML file where the PSQL queries are defined and mapped to the ResponseMapper.java** class and its methods
ReponseMapper.java - An interface used by MyBatis for executing the queries defined in the XML file (above)
ResponseDAO.java - An interface used for DI purposes (we use Spring)
ResponseDAOImpl.java - A concrete implementation of ResponseDAO that actually calls ResponseMapper methods; we use Spring to inject instances of this class into our application
So, to INSERT a new [responses] record into PostgreSQL, the code looks like this from the invoking component:
#Autowired
private ResponseDAO response;
public void doStuff()
{
int action = getAction();
response.setAction(action);
response.insert();
}
This set up works beautifully for us. However I am now trying to write a set of JUnit tests for the ResponseDAOImpl class, and I want to make sure that it is correctly executing queries to our PostgreSQL database.
As far as I can tell, there is no way to "mock" an entire database. So my only option (seemingly) is to have the test method(s) execute a query, check for success, and then roll it back regardless.
MyBatis doesn't seem to support this kind of rollback feature. I found this post off the mybatis-user mailing list on Old Nabble, but the poster was using Guice and his/her question seemed to be more about rolling back transactions through Guice.
If MyBatis doesn't support transactions/rollbacks (does it?!?!), then it seems like my only repireve would be if the PostgreSQL-JDBC driver supports these. I guess I could then try to configure my test methods so that they run the ResponseDAO.insert() method, and then manually try to rollback the transaction directly through the driver (sans MyBatis).
Does SO have any experience with this? Code samples? Tips? Best practices? Thanks in advance!

MyBatis allows rollbacks when working with an "SqlSession", the thing is your using the spring dependency injection piece, which automatically commits your transaction when the method completes.
You have a few options, among them
Inject a Mock of your dependencies. There is some rocking libraries to help with this. Like Mockito, here is a good question on Spring Mockito stuff. This will test your business logic in your java, but not your actual queries.
Commit your queries, and delete your data after the test runs. This is the approach we took, because it tests our database as well. You would obviously need a test instance of your database, which some people don't have.
You could try to provide your own test bindings for the classes that do the automatic commit in the MyBatis Spring Integration and override there behavior so that in the test environment the behavior is to rollback the query instead of committing. A similar approach was use in the Guice integration, and it is described here.

Not sure this is what you need, but org.apache.ibatis.session.SqlSession class has rollback() method which can be used to rollback.
Another approach is to use getConnection() method from the same class which will return javax.sql.Connection javax.sql.Connection class which also has commit() and rollback() methods.
Hope it helps.
Remis B

Related

Spring: Rollback transactin in Unittest

I have a complex service method, that loads a lot of data from the db. Since it only reads and validates data I want to make sure
JPA (Hibernate) does not waste time for checking the big persistence
context for changes.
No accidental changes to the data are written
to the db.
Therefore towards the end of my service I have this code
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()
My unit tests have mocks for all db access, so transactioning is not an issue. (I have integration test with #SpringBootTest and full trx support as well.) Unfortunately the rollback statement fails in pure unit tests.
Is there an easy way to get the rollback statement just do nothing in case of a unit test?
For now I just wrote a small component which is easy to mock:
#Component
public class RollBacker {
public void setRollBackOnly() {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
After all it's the singleton approach of TransactionAspectSupport which makes unit testing difficult here. IMHO TransactionAspectSupport should be a spring bean.
Consider to use #Transactional(readOnly=true) instead of TransactionAspectSupport.currentTransactionStatus().setRollbackOnly().
Doc
A boolean flag that can be set to true if the transaction is effectively read-only, allowing for corresponding optimizations at runtime.

JTA & MySQL - How to Retrieve records from database

I am new to JTA and I need a method to retrieve some some elements from the database. I can do this through EntityManager but that works only for ResourceLocal.
I want to know how can I do this:
Query q = em.createNamedQuery("AnyQuery");
q.getResultList();
without the use of EntityManager.
Any ideas?
The question itself shows that you don't understand any of the technologies you try to work with. You probably need to study some more general stuff before you do any actual development.
you are probably confusing JTA and JPA,
your statement about RESOURCE_LOCAL is not true (and irrelevant) - there are JTA and RESOURCE_LOCAL transactions and in Java EE you usually use the former,
your thought of using Named JPA queries without EntityManager is plain absurd and probably stems from misunderstanding of some kind (what would be the point of using named queries without an entity manager?),
saying "some elements from database" shows that you can't really tell the difference between records and mapped objects, in which case you probably should not use JPA at all.
I am not really expecting that you accept this answer. That's just my frustration taking over.
EDIT
OK, now that you mentioned JSF I understand more of your problem.
I assume you want to use JPA. In such case you have a choice of:
creating your own EntityManager (in such case you cannot have it injected; instead you have yo use an EntityManagerFactory and build your own). This is an "application managed EntityManager". You don't really want to do this.
using an injected EntityManaged ("conatiner managed EntityManager"). This is the standard choice.
Now you need a transaction. Since you should be using a JTA EntityManager, you will need a transaction object that is responsible for coordinating the whole thing. Again, you have two choices:
in a JSF bean, inject a UserTransaction (using #Resource annotation). This is messy, error-prone and takes a lot of boilerplate, but you will find all the necessary methods. You can create your own (application managed) EntityManager, call its joinTransaction method and then call begin-commit on UserTransaction. This is would be an "application managed transaction"
move your EntityManager code to EJB. It only takes a couple of lines of code and a single annotation (#Statless). All the code inside an EJB is - magically - wrapped inside a transaction that the container manages for you. This is the "container managed transaction" - the default and common choice.
Each of the things above could (and should) be expanded with some additional information. But the short path for you is:
create an EJB (a simple class with #Stateless annotation),
move the method that uses EntityManager to the EJB,
inject the EJB into your managed bean (using #EJB annotation) and call the relevant method.
The JTA transaction will happen around each call to any EJB method. This should get you started :-)

Rollback transactions in JAX-RS

I have a simple resource class that implements some POST method. How to rollback transaction if there was exceptions in my methods, and commit - if all is ok?
Is there a way to write this code once - not in every resource class that I have?
If you are using Spring, #Transactional will handle your scenario.
http://static.springsource.org/spring/docs/3.0.x/reference/transaction.html
Using a dependency-injection will greatly simplify this. Using #Transactional or similar annotations around the methods where you want to commit/rollback transactions.
If you have to do this manually, you have basically two options:
do it manually for every operation
use the proxy pattern/decorator pattern and proxy/decorate all your classes that require transactions. Then in the proxy/decorator start the transaction, delegate to the target, and commit it after it returns. (this is how DI frameworks do it)

Using and controlling Spring transactions within Struts 2 actions

I have been working for a while on a project with the following components:
Struts2.1.8.1,
Spring 3.0.3
JPA 2.0,
Hibernate 3
I am using Spring's EntityManager magic... But I'm having problems dealing with transactions inside my actions. For instance, I am setting values on my persisted object in several methods within my class, and I want to be able to rollback if the validate method finds a validation error, or commit these changes otherwise. I have already spent quite a long time reading half of the internet for a comprehensive explanation. Unfortunately, no complete examples exist (at least similar to my stack).
I have stumbled with this thread on a mailing list: #Transactional Spring Annotation in a Struts2 Action does not work. The message I'm linking at seems to have a pretty simple and straightforward solution, using a TransactionInterceptor will do the trick it seems... The problem is that I'm not finding useful information regarding this interceptor.
Anyone here has experience with this technology and can spare a tip and a link or two on how to use Spring transactions inside Struts2 actions?
Thanks!
- Edit 1 -
I have set up a test project if you are interested, just download the file and try it out (or inspect it). Thanks!
Generally, controllers/actions/backing beans/etc don't handle transactions. Actions are the web-part of your back-end code - they should only be concerned with gathering request data, and sending response data. The logic itself (including database access) should be done in another layer. E.g. a service layer. So you create another bean, inject it in the action, and make it do the work - userService.register(user). Then configuring transactions on a service layer should be trivial since it is both in the spring documentation and in countless examples:
<tx:annotation-driven /> and #Transactional (btw, make sure you have the <tx:..> now, it might be causing the issue. Even if it works, this does not invalidate my suggestion about the service layer)
I don't like answering my own question, but since I solved this ages ago... I thought I should share the knowledge (or lack of... in this case).
The book I was using to learn about Struts 2 and Spring-JPA-Hibernate, adds the #Transactional annotation right before the declaration of the service class. This is terribly wrong, for all methods (including those that only retrieve stuff from the database) are inside a committable transaction. Long story short everything got committed event if exceptions occurred.
The solution, as Bozho so wisely pointed out, was to look at examples. That is, set your transtactional methods carefully, in my case I set up transactions for the methods that had to write back to the database and everything started to work just fine.
Thanks to Steven and Quaternion too for taking the time to answer my question.
Based on your question, here's what I understand about your problem.
You want to wrap your action invocation in a transaction. If the validate method records validation errors, you want to roll the transaction back. Presumably, you also want to rollback in case of an error.
Solution
Create an interceptor that will:
Start a transaction
Invoke the action inside of a try/catch block
Rollback the transaction if there is an exception or if there are any validation errors on the action (this can be detected using action.hasErrors)
Commit the transaction
You will probably want this interceptor defined pretty early in the stack. I don't know of any pre-built interceptors for this (although there may be some), but it should be fairly easy to assemble.
Update
I don't use Spring, so I can't say how the JPA transaction support works there, but you can handle transactions for your EntityManager like:
try {
entityManager.getTransaction().begin();
// do your thing
entityManager.getTransaction().commit();
} catch (Exception e) {
entityManager.getTransaction().rollback();
throw new PersistenceException(e);
}
This is just a crude example, but it should illustrate the point.

Testing Java database entity classes

Currently we are testing out entity classes and "worker" classes by writing java servlets for each entity and doing Insert,update,delete,find... for each entity to ensure that it works. The worker classes are simply implementations of an interface that persists the entity to the database using JDBC, they do the DB work for the entity.
What I'm wondering is, what is the best way to test entity classes in Java?
I'm looking for an automated approach rather than writing, basically, a mock application that calls all of the functions that I'm trying to test for each new entity that is created.
You should be able to set-up and use entity and "worker" (as you put it) classes independently or servlets and a Web container.
With pure JDBC and JUnit, you would typically do the following:
Open a JDBC connection in TestCase constructor.
Begin a transaction on setUp().
Rollback a transaction on tearDown().
Use the actual entity instances in the particular testXxx() methods.
In this approach, you would be having one, possibly local, database instance per developer. For something more advanced, consider DbUnit.
One option would be to use reflection to find the different pieces of the entities (i.e. different fields) and then have the method call save, update, delete, etc using those different entities. Then, when you added a new entity, if your setup is done using xml or something similar, the test will just pick them up.
I am speaking from a Hibernate user perspective, so this may not be entirely applicable to your situation, but it has worked well for me in the past.

Categories