Spring annotation transaction mangement - spring

I have a Spring & Hibernate web application in which I would to connect to two databases.
In the web.xml I have configured the path of the application context files as following
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:config/*.xml
</param-value>
</context-param>
where I have three files under the config directory
1- primary-hibernateContext.xml
2- secondary-hibernateContext.xml
3- root-context.xml
In the first file I have configured the primary data source, session factory, and transaction manager(primary_manager)
I did the same in the second file
In the third file I have configured the component scan, and transaction annotation configuration as following
<tx:annotation-driven/>
<!-- Enable Spring annotation configuration -->
<context:annotation-config />
<!-- Scan the application for all possible Services & autowire -->
<context:component-scan base-package="net.mr2.*.service" />
<context:component-scan base-package="net.mr2.*.dao" />
I have a servlet context xml file in which I have configured the dispatcher servlet as following
<annotation-driven />
<context:component-scan base-package="net.mr2.*.web" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
The service class is annotated #service & #Transactional(value="secondary_transactionManager", readOnly=true, rollbackFor=Exception.class).
I have a single controller in which the service is autowired.
From the controller I call three methods in the service class (save1(), save2(), save3()). and I throw exception in the third method and I assume that the third method should rollback but this does not happen.
I have opened the mysql logs and checked the three saving statements and I found that the statements are not executed in a transaction. I realized that as I did not find SET AUTOCOMMIT statements before and after the insert statement.
So, I assume that the transactions are not configured well.
What would be the problem in my settings ?

You configured the app so that it opens a new transaction for every call to the service (which is the class that is transactional ). You need to either start the transaction in the controller or wrap your calls in another method on service level.

I have realized that I annotated the service with the wrong transaction manager and this what leads to the previous strange behavior
The service (I was using) was annotated with
#transactional(value='transaction_manger_1')
This transaction manager is configured to work with the read_only DB while the injected DAO was using the correct session factory which works with the read/write DB.
So I have changed the transaction manager to the correct one and every thing goes fine.

Related

Transactional annotation does not save on exit

I have configured spring jpa with annotation driven. I would expect the following code to persist the changes to the database upon method exist.
#Transactional
public Foo changeValue(int id){
final Foo foo = fooRepository.findOne(id);
if(foo != null){
foo.setValue("new value");
//fooRepository.save(foo);
}
}
FooRepository is a JPARepository and the foo object is getting fetched so it is managed. Based on what I read about #Transactional I would expect that even without the fooRepository.save(foo) call the changes in foo's value column in the database would be persisted upon method exist. However, this only happens if I uncomment the call to fooRepository.save(foo)
No exceptions are thrown and the configuration for the jpa datasource is as below.
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
...
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory" />
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan
base-package="com.example.package.data" />
<jpa:repositories
base-package="com.example.package.data.repository"
entity-manager-factory-ref="entityManagerFactory"
transaction-manager-ref="transactionManager" />
Any ideas?
Update
I do have a ContextLoaderListener and a DispatcherServlet but I do not have component scan for both.
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
</servlet>
....
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Update
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
And there I do
<context:component-scan base-package="com.example.package">
<context:exclude-filter type="regex"
expression="com.example.package.data.*" />
<context:exclude-filter type="regex"
expression="com.example.package.web.controller.*" />
<context:exclude-filter type="regex"
expression="com.example.package.web.service.*" />
</context:component-scan>
And in servlet-context
<context:component-scan base-package="com.example.package.web" />
Your general approach is correct. The changes should get saved and committed on exit of the method. While this approach works great when it works it is a bitch to debug.
Your configuration looks ok to me, so I would double check, that you actually have Spring Beans at your disposal and not some instance that you created simply by calling the constructor.
To verify this, just put a breakpoint at the code point where the annotated method gets called. The bean with the annotated method should NOT by of the class you wrote, but some ProxySomething class.
This article also provides some pointers what might be wrong with your setup.
If you have both a ContextLoaderListener and DispatcherServlet they both load a configuration file.
Judging from your configuration the services are loaded by the DispatcherServlet and your <tx:annotation-driven /> is loaded by the ContextLoaderListener. They both create an ApplicationContext and as AOP is only applied to the beans in the same context your services will not be transactional (Transaction management is done by using AOP).
As a rule of thumb your ContextLoaderListener should contain all shared or global resources (like services, daos, datasources etc.) whereas your DispatcherServlet should only contain web related beans like controllers, view resolvers etc.

Configure singleton CacheManager for multiple web applications with Spring Caching

I have multiple web applications deployed in Tomcat and service jar shared in TOMCAT_HOME/lib/ext. All of the application are using Spring, and in the service jar I have beans, annotated with Spring 3.1 Caching annotations . I am using Ehcache provider. And I want to have one single CacheManager used by all the web applications. If I define spring cache configurations at web application level, caching works, but separate cacheManager is created for every app/context. 'Shared' Cache Manager is causing problems, because if one the those applications gets undeployed, this shared cacheManager is shut down. So I want a single CacheManager , configured in my service jar, and used for all the calls to methods made from beans from the web apps. My current try is to define following confuguration in service.jar's applicationContext.xml:
<context:annotation-config/>
<context:component-scan base-package="com.mycompany.app" />
<context:component-scan base-package="com.mycompany.portal.service" />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehCacheManager"/>
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="ehcache.xml" ></bean>
<cache:annotation-driven cache-manager="cacheManager"/>
I have defined parent application context via beanRefContext.xml:
<bean id="service.parent.context" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>applicationContext.xml</value>
</list>
</constructor-arg>
</bean>
And I am using this context as a parent context for all of my web apps with following contextParam in web app's web.xml:
<context-param>
<param-name>parentContextKey</param-name>
<param-value>service.parent.context</param-value>
</context-param>
The result is that this parentContext is loaded, but caching doesn't work at all
How can I solve this? Am I on the right way with the defining of the parentContext in the service.jar?
I don't think so. It looks like you are trying to have a single cache for multiple applications by "hacking" the root classloader.
If you need to share your cache across several applications, use a cache manager that supports that use case (i.e. that provides you a service you can reach from each application).

Spring JTA transaction with JPA and jndi datasource for Websphere

I am having multiple datasource and one one database configured with JPA. I am using websphere 7. I want all these datasouces to be configured as global transactions. I am using below spring configurations but the transactions are not working as expected global transaction. If one db is failing then the other db is getting commited which is not expected as single global transactions. Can you please help me where i m doing incorrect,
I am having 2 datasouce one as configured below with id="us_icfs_datasource" and another using JPA
<jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/persistenceUnit"/>
<bean id="pabpp" class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
<!-- Needed for #Transactional annotation -->
<tx:annotation-driven/>
<jee:jndi-lookup id="US_ICFS_DATASORCE"
jndi-name="jdbc/financing_tools_docgen_txtmgr"
cache="true"
resource-ref="true"
proxy-interface="javax.sql.DataSource" />
also I have added below code in web.xml
<persistence-unit-ref>
<persistence-unit-ref-name>persistence/persistenceUnit</persistence-unit-ref-name>
<persistence-unit-name>persistenceUnit</persistence-unit-name>
</persistence-unit-ref>
<persistence-context-ref>
<persistence-context-ref-name>persistence/persistenceUnit</persistence-context-ref-name>
<persistence-unit-name>persistenceUnit</persistence-unit-name>
</persistence-context-ref>
below is my code where i m using transaction
> #Transactional public TemplateMapping addTemplateMapping(User user,
> TemplateMapping templateMapping) throws
> TemplateMappingServiceException { .... }
On Websphere you should use this bean to hook into the Websphere transaction manager:
<bean id="transactionManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager"/>
See also this article
EDIT:
In order to use 2-phase commit (i.e. ensuring consistency across multiple resources), you will need to use XA data sources. See this article for details.
First of all your data sources that participate in global transaction must be of javax.sql.XADataSource type.
You also have to set transaction type in your persistence unit to JTA (not RESOURCE_LOCAL).
And you need to inform your JPA implementation that you want to do global transactions.

spring basic mvc sample application, annotation scan confusion

Little confused, the basic spring mvc app has this:
app-config.xml
<context:component-scan base-package="org.springframework.samples.mvc.basic" />
and the mvc-config.xml has:
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven />
Do you really need both?
for component-scan, does this mean if I don't put the correct package path my #Controller and #Service markers will have no effect?
If I need more than one package, do I just duplicate the entry?
I tried using just the mvc:annotation-driven but that didn't work, I had to put com.example.web.controllers in the component-scan xml node to make it work.
context:component-scan is clear
Scans the classpath for annotated components that will be auto-registered as Spring beans. By default, the Spring-provided #Component, #Repository, #Service, and #Controller stereotypes will be detected.
So #Controller is just a Spring bean. Nothing else.
And
mvc:annotation-driven
registers the HandlerMapping and HandlerAdapter required to dispatch requests to your #Controllers
Which is similar to
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
If I need more than one package, do I just duplicate the entry?
You can if you want. context:component-scan is just a bean post-processor.
<context:component-scan base-package="br.com.app.view.controller"/>
<context:component-scan base-package="br.com.app.service"/>
Or
Use a comma-separated list of packages to scan for annotated components.
<context:component-scan base-package="br.com.app.view.controller,br.com.app.service"/>
mvc:annotation-driven allows you to configure behavior of Spring MVC. See details in documentation .For basic usage of Spring MVC you do not need it.
If you need more than one package just mention parent one: <context:component-scan base-package="org.springframework.samples.mvc" />

Can Spring Webflow define beans within flow.xml definitions?

I'm defining a lot of flows and each of my flows has a lot of actions within its states.
The namespace seems to be getting fairly crowded now, so I'm wondering if it's possible to define the spring beans for flow actions from within the flow.xml
or some other way such that it's visible to the flow, but not to other flows, but still has access to the greater spring context (for things such as service injections)
You have 1 spring context and therefore you can't have beans invisible for each other. That said, you can put different beans wit different ids in different xmls, using either:
in web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/flow1.xml,/WEB-INF/flow2.xml</param-value>
</context-param>
or in applicationContext.xml (your flowX.xml should be under /WEB-INF/classes - i.e. the root of the classpath):
<import resource="classpath*:/flow1.xml" />
<import resource="classpath*:/flow2.xml" />

Resources