I am writing an application providing REST services (with Apache-CXF) that manage JPA entities (with Hibernate).
I am a bit lost with Transaction management and would like your advice on this topic.
For now, I have put an intermediate layer between my business REST services and the lower services, solely for transaction management purpose.
Currently, my code looks much like that :
#Service
class PersistanceService<MyBusinessClass>{
MyBusinessClass load(Long id);
void save(MyBusinessClass businessObject);
}
#Service
class BusinessService<MyBusinessClass>{
void doSomethingOn(MyBusinessClass businessObject);
}
#Service
class TransactionBusinessService<MyBusinessClass>{
#Transactional
void doSomethingOn(Long id) {
MyBusinessClass businessObject = persistanceService.load(id);
businessService.doSomethingOn(businessObject);
persistanceService.save(businessObject);
}
}
#Service
#path("/foo")
class RESTService {
#Path("/doSomething")
void doSomethingOn(Long id) {
transactionBusinessService.doSomethingOn(id);
}
}
I think the TransactionBusinessService is overkill. I would like ''Spring'' or ''CXF'' to handle transactions for me : I feel that a request is the good granularity to do so : Init an entity manager at the beginning of each request, and commit updates at the end.
I've tried to add the #Transactional annotation to the REST methods themselves, but it seem to be ignored, or to conflict with CXF.
Do you think it is a good idea to delegate the transaction at the request level and not to bother about it anymore ?
How can I have Spring or CXF bind the transaction management to the requests for me ?
Thanks in advance for you advice.
Do you think it is a good idea to delegate the transaction at the request level and not to bother about it anymore ?
Usually it's not good idea, because:
usually it's not that convenient to separate Transaction isolation
if you need to do some changes in for-loop, each of which has to have own transaction, it's also not
that transparent; meanwhile on service layer you may decide whether you need the whole loop to be transactional or each of iteration;
tx:annotation-driven (and some other AOP-interceptor) sometimes works a bit unpredictable, if you are using AOP annotations in the controllers directly (at least I faced such issues in Spring MVC/struts2 and some other frameworks)
So basically, you have 3 layers:
persistence layer, which is responsible for storing/fetching data only;
service layer, which is responsible for data preparation and for AOP-annotations (#Transactional, #PreAuthorize, #Cacheable and so on), which use persistence layer within;
controller level, which gets request, binds business models, probably validates it, pass model(s) to service layer and returns result from there or handles exception
How can I have Spring or CXF bind the transaction management to the requests for me?
Please make sure, that you:
you have appropriate TransactionManager ('org.springframework.transaction.PlatformTransactionManager` implementation) in your config
you have tx:annotation-driven in your config
those beans are visible in the config of your CXF services
<bean name="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
Related
In hexagonal architecture (or clean architecture), we have use cases that perform one or several interactions with infrastructure components.
These Use Cases are tipically transactional operations (we want them to be atomic).
So we would use the #Transactional annotation at Use Case method level.
#Component
#RequiredArgsConstructor
public class MyShinyUseCase implements MyShinyPrimaryPort {
private final transactionalSecondaryPort trPort1; <--- Database 1
private final anotherTransactionalSecondaryPort trPort2; <--- Database 2
#Override
#Transactional("UPS, THERE ARE 2 TRANSACTION MANAGERS IN THE CONTEXT")
public void useCaseMethod() {
trPort1.operate(); <--- Transactional resource
trPort2.operate(); <--- Transactional resource, is error I want
to rollback the trPort1.operate().
}
The problem comes when the Use Case interacts with more than one transactional resources, each of them with their TransactionManager, because the #Transactional annotation requires a specific TransactionManager to be specified, but the infrastructure specific TransactionManagers are infrastructure concerns: they should not be referenced from the domain layer, and even if we did, there are several TransactionManagers in play...
What would be the way to manage transactions involving several transactional resources in an hexagonal architecture?
For personal education I am currently developing a little application framework around Guice to learn-by-doing how Spring etc. work behind the scenes.
Intro
Just for the sake of context, here is what I have so far and plan to do so you get a feeling for what I try to archive:
Context (Core)
ApplicationContext/-Configuration
Modules (auto discovered, setting up the Guice bindings)
Extensions
Config: #Config
Locale: #Locale and i18n services
Resources: #Property, #Resource and some classes providing easy access to resources
Persistence: Problems - there we go!
Question
I'd like to use the JDO standard (and its reference implementation DataNucleus) for the persistence layer. Setting up the PersistenceManagerFactory was easy, so was using it in a basic manner. I am however targeting a typical service / repository layer architecture, e.g.:
Person
PersonRepository (JDO)
PersonService (Transactions, using PersonRepository)
That alone wouldn't be too hard either, but as soon as I tried properly integrating transactions into the concept I got a bit lost.
Desired
class PersonService {
#Transactional(TxType.REQUIRED)
public Set<Person> doX() {
// multiple repository methods called here
}
}
class PersonRepository {
private PersistenceManagerFactory pmf;
public Set<Person> doX() {
try (PersistenceManager pm = pmf.getPersistenceManager()) {
pm.....
}
}
}
Difficulties
DataNucleus supports RESOURCE_LOCAL (pm.currentTransaction()) as well as JTA transactions and I would like to support both as well (the user should not have to distinguish between the two outside the configuration). He should not have to bother about transaction handling anyway, that is part of the annotation's method interceptor (I guess).
I'd love to support the #Transactional (from JTA) annotation that can be placed on service layer methods. Knowing that annotation is not per-se available in JDO, I thought it could be made usable as well.
How exactly should the repository layer "speak" JDO? Should each method get a PersistenceManager(Proxy)from the PersistenceManagerFactory and close it afterwards (as in the example) or get a PersistenceManager injected (rather than the factory)? Should each method close the PersistenceManager (in both scenarios)? That would not work with RESOURCE_LOCAL transactions I guess since a transaction is bound to one PersistenceManager.
What I tried
I have a JDOTransactionalInterceptor (working with pmf.getPersistenceManagerProxy) and a JTATransactionalInterceptor (very similar to https://github.com/HubSpot/guice-transactional/blob/master/src/main/java/com/hubspot/guice/transactional/impl/TransactionalInterceptor.java working with a ThreadLocal)
Summary
I am aware that my question may not be as clear as desired and mixes the service / repository layer questions (which is my main problem I think) and transaction stuff (which I could figure out once I understand how to properly use PMF/PM in repository layer I think)
There is no scope à la RequestScoped etc. I just want the first #Transactional method call to be the starting point for that whole thing (and that is the point: Is this impossible and the PMF/PM have to be scoped before and I have to direct my thinkings into that direction?)
Thanks for any clarification / help!
I have the following problem:
I'm using Spring MVC 4.0.5 with Hibernate 4.3.5 and I'm trying to create a Restfull Web application. The problem is that I want to exclude some fields from getting serialized as JSON, depending on the method called in the controller using aspects.
My problem now is that Hiberate does not commit the transaction immideatly after it returns from a method but just before serializing.
Controller.java
public class LoginController {
/*
* Autowire all the Services and stuff..
*/
#RemoveAttribues({"fieldA","fieldB"})
#RequestMapping{....}
public ResponseEntity login(#RequestBody user) {
User updatedUser = userService.loginTheUser(user);
return new ResponseEntity<>(updatedUser,HttpStatus.OK);
}
}
Service.java
public class UserService {
#Transactional
public User loginUser(User user) {
user.setLoginToken("some generated token");
return userDao.update(user); //userDao just calls entityManager.merge(..)
}
}
The advice of the aspect does the following:
for every String find the corresponding setter and set the field to null
This is done, like I said, to avoid serialization of data (for which Jackson 2 is used)
The problem now is that only after the advice has finished the transaction is commited. Is there anything I can do to tell hibernate to commit immediatly or do I have to dig deeper and start handling the transactions myself (which I would like to avoid)?
EDIT:
I also have autocommit turned on
<prop key="hibernate.connection.autocommit">true</prop>
I think the problem lies in the fact that I use lazy loading (because each user may have a huge laod of other enities attached to him), so the transaction is not commited until I try to serialze the object.
Don't set auto-commit to true. It's a terrible mistake.
I think you need a UserService interface and a UserServiceImpl for the interface implementation. Whatever you now have in the UserService class must be migrated to UserServiceImpl instead.
This can ensure that the #Transactions are applied even for JDK dynamic proxies and not just for CGLIB runtime proxies.
If you are using Open-Session-in-View anti-patterns, you need to let it go and use session-per-request instead. It's much more scalable and it forces you to handle optimum queries sin your data layer.
Using JDBC Transaction Management and the default session-close-on-request pattern you should be fine with this issue.
I have an abstract class and two sub classes that extend it. I have the following in spring config file
<bean id="importConfigFile" class="xxx.ImportConfigFiles" parent="parentImportFile"></bean>
<bean id="importFile" class="xxx.ImportUMTSKPIFiles" parent="parentImportFile"></bean>
<bean id="parentImportFile" name="parentImportFile" class="xxx.ImportUMTSFiles" abstract="true"></bean>
<tx:annotation-driven transaction-manager="transactionManager" />
In my abstract class I have the following methods
public void importDataToDB(){
//all the good stuff goes in here
}
#Transactional
public void executeInsertUpdateQuery(){
//all the good stuff goes in here
}
My java code
ImportConfigFiles importConfigFiles = (ImportConfigFiles)context.getBean("importConfigFile");
importConfigFiles.setFileLocation(destPath);
importConfigFiles.importDataToDB();
This does not work. executeInsertUpdateQuery() executes just one native sql query. If I put #Transactional on imortDataToDB() it works but then it makes my transaction huge since inside that method I loop through all the rows in a file and insert the records in db.
This is one of the major pitfalls in Spring - if you call #Transactional-method from non-transactional method in the same class, the #Transactional is ignored (unless you use AspectJ weaving). This is not Spring problem per se - the EJB has the same shortcomings.
Unfortunately with interface-based and class-based proxies all you can do is to split your class in two:
public class BeanA() {
#Resource
private BeanB b;
public void importDataToDB(){
b.executeInsertUpdateQuery();
}
}
public class BeanB {
#Transactional
public void executeInsertUpdateQuery(){
//all the good stuff goes in here
}
}
The whole hustle is caused by the internal implementation of AOP proxies in Spring. With the code above new transaction will be started every time you call b.executeInsertUpdateQuery() from non-transactional BeanA.
I wrote about it on my blog Spring pitfalls: proxying, Spring AOP riddle and Spring AOP riddle demystified.
Not quite sure, what the question is, but #Transactional wraps the entire method in one transaction so obviously it will be huge if you import everything in one method. The advantage is, that if at some place your import fails, the entire transaction will not get executed and no faulty data is in your database.
If you don't want that, you'll have to manage the transactions yourself or call a #Transactional annotated method for a subset of your data, like you're doing right now for one import, but maybe you do it for 10 files or other e.g. logical restrictions.
I have an application that I am currently writing that will use Spring and Hibernate. In my services layer I have injected a DAO that will do some very basic CRUD-ing actions. For grins, I have created a method annotated as follows:
#Transactional(readOnly = false, propogation=Propogation.REQUIRES_NEW)
public void doSomeWork(Dao dao, Entity e){
//do some searching
dao.persist(e);
dao.findAll(Entity.clz);
}
The dao persist method looks like this:
public void persist(Entity e){
session.saveOrUpdate(e); //This has already been built using a SessionFactory
}
The dao findAll method looks like this
public void findAll(Class clz) {
session.createCriteria(clz).list();
}
Now, everything seems to run, OK. After I insert (persist) my object, I can see it using the findAll method (along with the new Primary Key ID that it was assigned by the Data Store), however, when the "doSomeWork" method completes, my data does not actually get persisted to the underlying datastore (Oracle 10g).
If, however, I remove the #Transactional annotations and use Hibernate's session.getTransaction().begin() and session.getTransaction().commit() (or rollback), the code works as I would anticipate.
So, my underlying question would then be: Does Hibernate not actually use Spring's transaction management for actual transaction management?
In my bean-config file I am declaring a TransactionManager bean, a SessionFactory bean, and I am also including in the config file.
What could I possibly be missing, aside for a better working-knowledge of Spring and Hibernate?
Don't forget to add <tx:annotation-driven> for #Transactional support
sounds like spring doesnt actually inject the transaction handling code.
do you have something like this in your config file, to tell spring where to look for annotated classes?
<beans xmlns:context="http://www.springframework.org/schema/context" ...
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd ..." >
...
<context:annotation-config/>
<context:component-scan base-package="mypackage.dao.impl"/>
<bean name="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</beans>
what method do you use to obtain the session object from the session factory? Are you using openSession(), or getCurrentSession(), or perhaps something else? This matters because you need to session to be bound to the spring transaction (I doubt if openSession is good for your scenario)
I suggest that you use Spring's hibernateTemplate to invoke saveOrUpdate and persist, instead of using the session object. This way you are guaranteed that it will be bound to the transaction, and, as spring promises, you won't need to change the code if you ever change the transaction management strategy.
Ok, well, thanks to everyone who responded... it helped me to figure out what I am doing wrong...
In my overzealous "proof-of-concepting" it never really dawned on me what was going on until I realized that my "simple java class with a main method that will be doing all my work" isn't managed by spring, therefore no real transaction management. This will in no way behave as a product application would, being managed by an app-server with controller beans, services, etc.
Then it dawned on me... "services"... I'm going to have a services layer, that's where the transaction support will live. So, right as rain, I created a simple service bean (marked with #Transactional) and it works just as I would hope it would. So, I call methods on my service, which calls methods on my Dao and bam!!! it works.
Thanks again to everyone who helped me to come to this conclusion.