com.service.EmployeeService has method create createEmployee which calls method under dao class i.e com.dao.EmployeeDao(having EntityManager as dependency).
Now i want to make method createEmployee transactional with #Transactional. Is it mandatoty to declare the package com.service
under packagesToScan in spring config file ?
I mean is it mandatory to declare the package of class using #Transactional under packagesToScan to make it work ?
FYI I referred the how-does-spring-transactional-really-work to understand how spring transactions works internally
#Transactional is used on a class or method for the transaction management whereas packagesToScan is used by spring for scanning annotations on your entity classes
<property name="packagesToScan">
<list>
<value>com.xyz.EntityName</value>
</list>
</property>
I used #Transactional on my DaoImpl methods(CRUD) and used packagesToScan on the entities for spring to pick.
When you use spring with hibernate it is the responsibility of the spring's class i.e org.springframework.orm.hibernate4.LocalSessionFactoryBean
as in <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
instead of Hibernate's new Configuration().configure().buildSessionFactory()
Moreover in hibernate you use to tell hibernate to consider the entities which are using annotation as in hibrnate.cfg.xml by using
<mapping class="com.hiber.hr.Countries"/>
<mapping class="com.hiber.hr.Departments"/>
Similarly you need to tell spring the same through packagesToScan property.
Internally Spring calls the Hibernate's addAnnotatedClass method of org.hibernate.cfg.Configuration class
Hibernate method called from Spring:-
public Configuration addAnnotatedClass(Class annotatedClass)
{
XClass xClass = reflectionManager.toXClass(annotatedClass);
metadataSourceQueue.add(xClass);
return this;
}
Transactional makes a Spring bean method transactional.
packagesToScan is a property of the Spring sessionFactory / entityManagerFactory beans, that tell them where to find JPA entities.
They are completely orthogonal. Entities are not Spring beans. And transactional Spring beans are not entities that must be found by the SessionFactory / EntityManagerFactory.
Related
I am trying to nest transactions with different transaction managers wherein if the nested transaction fails the outer main transaction needs to rollback as well
#Transactional(transactionManager = "txManager1", propagation = Propagation.REQUIRED)
public int doOps() {
doSuccessfulDatabaseThings();
doOps2();
}
#Transactional(transactionManager = "txManager2", propagation = Propagation.REQUIRED)
public int doOps2() {
//this throws error
}
My spring config file has
<bean id="dataSource1" class ="com.mchange.v2.c3p0.ComboPooledDataSource">
...
</bean>
<bean id="txManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource1" />
</bean>
<!-- txManager2 defined similarly -->
<tx:annotation-driven/>
However, when doOps2() fails, the transaction in doOps() doesn't rollback. How to make the rollback work?
Bold Statement
You're doing it wrong.
Based on you description,
you want a ChainedTransactionManager.
Create a transaction manager for each of your datasources,
then pass the transaction manager to the ChainedTransactionManager
constructor.
Name the ChainedTransactionManager bean and reference the name in a
#Transactional annotation.
I think the property is named "transactionManager".
For example,
#Transactional(transactionManager = "chainedTransactionManagerBeanName")
When you are referencing the method inside the same bean, the #Transaction will be ignored. These annotations are only used when referenced via Spring bean management, which will make a proxy:
https://www.javacodegeeks.com/2016/05/understanding-transactional-annotation-spring.html#:~:text=At%20a%20high%20level%2C%20when,has%20no%20knowledge%20of%20it.
So calling doOps2 doesnt do anything with the #Transactional txmanager2
I have a project which deals with two different database instances.
Each access to a database is transactional, but the transaction on database1 do not need to be linked to transaction on database2.
I am using Hibernate and spring-tx 4.0.3 Release, spring Ioc4 and hibernate4.
I use #Transactional annotation in my DAO services.
So I configure two datasource beans, two sessionFactory beans and two HibernateTransactionManager beans.
But doing so, I get an UniqueBeanException as the TransactionAspectSupport.determineTransactionManager tries to find only one instance of class implementing PlatformTransactionManager interface.
I have seen that I can make my java configuration class implements TransactionManagementConfigurer, so that I can specifically tell which transaction-manager bean to use, and I was hoping to implement a ProxyTransactionManager who could delegate to each appropriate transaction-manager depending on which database the current call need to be made.
The problem is implementing such ProxyPlatformTransactionManager methods, how can I know which database is being accessed, or which SessionFactory is being accessed? Otherwise I an not know which PlatformTransactionManager to use.
Has anyone faced that type of issue yet?
Thanks,
Mel
In your application context, you need to define 2 transactionalManagers as below
<bean id="txMngr1" class="org.springframework.orm.hibernate5.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory1">
<qualifier value="txMngr1"/>
</bean>
<bean id="txMngr2" class="org.springframework.orm.hibernate5.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory2">
<qualifier value="txMngr2"/>
</bean>
And then use the Transactional Qualifier with your DAOs/Services.
#Transactional("txMngr2")
FYI: You can access multiple sessionFactories from your code using qualifiers as well
#Autowired
#Qualifier(value="sessionFactory2")
private SessionFactory sessionFactory;
I have a problem, where Spring is injecting proxy to DAO object into service, but this service is injected into controller it is concrete class. This does not allow me to use service-wide transaction and launches transaction for each DAO call separatly. It's behavious I would expect.
Configuration:
Controller is class with #Controller annotation and constructor DI.
Service:
#Component
#Transactional
public class UserServiceImpl implements UserService { ...}
Dao:
#Component
#Transactional
public class UserDaoImpl implements UserDao {
JPA Config:
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="xxxPersistenceUnit"/>
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven />
Anyone has any idea why is it happening?
Most likely your UserServiceImpl is created in the servlet context by mistake - please check context:component-scan expressions to check that only Controller classes are included there.
See #Service are constructed twice
for examples of component scan filters.
For example if transaction manager bean and <tx:annotation-driven> are declared in the root web app context, then the transaction proxies will be created only for the beans in the root app context (from Spring Documentation):
BeanPostProcessor interfaces are scoped per-container. This is only
relevant if you are using container hierarchies. If you define a
BeanPostProcessor in one container, it will only do its work on the
beans in that container. Beans that are defined in one container are
not post-processed by a BeanPostProcessor in another container, even
if both containers are part of the same hierarchy.
Less likely is that the transactional configuration of the user service is configured to use another transaction manager(or another default propagation), but in that case TransactionInterceptor invocation would be present in the stack trace of DAO method.
It's absolutely OK to have #Transactional on the DAO classes in Spring, if you understand what you are doing - the idea that repository or DAO cannot open transactions comes from the dark times when you had to create a boilerplate code to open transactions and it was hard to manage the transaction instances(and you could not be sure on how transactions are managed). But when you are using declarative configuration the things are not that bad. Spring promotes convention-over-configuration style where most methods use Propagation.REQUIRED transaction mode. In Spring Propagation.REQUIRED is the default mode when you decorate methods with #Transactional(this propagation is hardcoded to #Transactional annotation declaration), that means that the new logical transaction is mapped to the same physical transaction, so decorating your DAO classes with #Transactional is harmless.
See http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/transaction.html#tx-propagation for the reference on transaction propagation in Spring
In Spring Data JPA(I'm pretty sure that they know what they are doing), for example, CRUD methods on repository instances are transactional by default. That may be useful in some cases, the mechanism is same as when Hibernate allows you to get() some arbitrary objects from the Session for displaying without declaring an explicit transaction(of course it does not mean that the framework somehow manages to go without transaction - it's implicit in this case).
I'm having a little trouble understanding what you're saying, but it appears that you're surprised that you're getting a new transaction for every DAO call, instead of just on the service call. Unfortunately, that's exactly what you've specified by putting "#Transactional" on the DAO class. Your DAO should not be transactional, at least if you're following the usual pattern. If I've understood you correctly, you should remove the #Transactional annotation on your DAO class.
The other responders are correct in that you should not be annotate your DAO as #Transactional, but to really understand what is happening you should refer to the Transaction Propagation section in the Spring Reference Manual. The default propagation when using #Transactional is REQUIRES_PROPAGATION, so review that specifically.
Your question isn't that specific so I'm not sure exactly what you're looking for.
Edit: Upon re-reading your question it's possible that there may be an issue with your component scanning. Check to make sure that your <tx:annotation-driven /> is in the same application context where you're component scanning your service classes.
You shouldn't use that "#Transactional" annotation in your DAO object. You are defining it in your Service and that will grant that all your DAOs methods, called inside a service method, are executed within the same transaction, which seems to be exactly what you want, when you say "service-wide transaction", right?
Also, as suggested, you might want to change your annotation from "#Component" to "#Service" in UserServiceImpl and to "#Repository" in UserDaoImpl.
Best regards.
I'm using Spring 3.0.6, with Hibernate 3.2.7.GA in a Java-based webapp. I'm declaring transactions with #Transactional annotations on the controllers (as opposed to in the service layer). Most of the views are read-only.
The problem is, I've got some DAOs which are using JdbcTemplate to query the database directly with SQL, and they're being called outside of a transaction. Which means they're not reusing the Hibernate SessionFactory's connection. The reason they're outside the transaction is that I'm using converters on method parameters in the controller, like so:
#Controller
#Transactional
public class MyController {
#RequestMapping(value="/foo/{fooId}", method=RequestMethod.GET)
public ModelAndView get(#PathVariable("fooId") Foo foo) {
// do something with foo, and return a new ModelAndView
}
}
public class FooConverter implements Converter<String, Foo> {
#Override
public Foo convert(String fooId) {
// call FooService, which calls FooJdbcDao to look up the Foo for fooId
}
}
My JDBC DAO relies on SimpleJdbcDaoSupport to have the jdbcTemplate injected:
#Repository("fooDao")
public class FooJdbcDao extends SimpleJdbcDaoSupport implements FooDao {
public Foo findById(String fooId) {
getJdbcTemplate().queryForObject("select * from foo where ...", new FooRowMapper());
// map to a Foo object, and return it
}
}
and my applicationContext.xml wires it all together:
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="FooConverter"/>
<!-- other converters -->
</set>
</property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
FooConverter (which converts a path variable String to a Foo object) gets called before MyController#get() is called, so the transaction hasn't been started yet. Thus when FooJdbcDAO is called to query the database, it has no way of reusing the SessionFactory's connection, and has to check out its own connection from the pool.
So my questions are:
Is there any way to share a database connection between the SessionFactory and my JDBC DAOs? I'm using HibernateTransactionManager, and from looking at Spring's DataSourceUtils it appears that sharing a transaction is the only way to share the connection.
If the answer to #1 is no, then is there a way to configure OpenSessionInViewFilter to just start a transaction for us, at the beginning of the request? I'm using "on_close" for the hibernate.connection.release_mode, so the Hibernate Session and Connection are already staying open for the life of the request.
The reason this is important to me is that I'm experiencing problems under heavy load where each thread is checking out 2 connections from the pool: the first is checked out by hibernate and saved for the whole length of the thread, and the 2nd is checked out every time a JDBC DAO needs one for a query outside of a transaction. This causes deadlocks when the 2nd connection can't be checked out because the pool is empty, but the first connection is still held. My preferred solution is to make all JDBC DAOs participate in Hibernate's transaction, so that TransactionSynchronizationManager will correctly share the one single connection.
Is there any way to share a database connection between the SessionFactory and my JDBC DAOs? I'm using HibernateTransactionManager, and from looking at Spring's DataSourceUtils it appears that sharing a transaction is the only way to share the connection.
--> Well you can share database connection between SessionFactory and JdbcTemplate. What you need to do is share same datasource between the two. Connection pooling is also shared between the two. I am using it in my application.
What you need to do is configure HibernateTransactionManager for both transactions.
Add JdbcDao class(with properties jdbcTemplate and dataSource with getter-setter) in your existing package structure(in dao package/layer), Extend your jdbc implementation classes by JdbcDao. If you have configured, hibernateTxManager for hibernate, you will not need to configure it.
The problem is, I've got some DAOs which are using JdbcTemplate to query the database directly with SQL, and they're being called outside of a transaction. Which means they're not reusing the Hibernate SessionFactory's connection.
--> You may be wrong here. You may be using same connection, I think, only problem may lie in HibernateTransaction configuration.
Check HibernateTransactionManager javadoc : This transaction manager is appropriate for applications that use a single Hibernate SessionFactory for transactional data access, but it also supports direct DataSource access within a transaction (i.e. plain JDBC code working with the same DataSource). This allows for mixing services which access Hibernate and services which use plain JDBC (without being aware of Hibernate)!
Check my question : Using Hibernate and Jdbc both in Spring Framework 3.0
Configuration : Add dao classes and service classes with your current hibernate classes, do not make separate packages for them, If you want to work with existing configuration. Otherwise configure HibernateTransactionManager in xml configuration and Use #Transactional annotation.
Mistake in your code :
#Controller
#Transactional
public class MyController {......
Use #Transactional annotation in service classes(best practice).
Correction :
#Transactional(readOnly = true)
public class FooService implements FooService {
public Foo getFoo(String fooName) {
// do something
}
// these settings have precedence for this method
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// do something
}
}
<context:annotation-config/>
<context:component-scan...
this is used for class that i need to annotated with #Repository #Service #Component...
<context:spring-configured />
<context:component-scan...
use if i need to use #Configurable
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan...
use if i need #Transactional , beside this what other metadata do I need to add in xml in order to use transaction management?
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
what is the need to add this in xml ? for what purpose?
<tx:annotation-driven transaction-manager="transactionManager" />
In order to use transaction management you also need to declare a transactionManager to use. That declaration depends on the approach you use to access the data. For example, for plain JDBC you write:
<bean id = "transactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name = "dataSource" ref = "dataSource" />
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
This declaration is used to handle #PersistenceContext and #PersistenceUnit annotations for JPA data access configuration. Hovewer, support for this annotations also included in <context:annotation-config />, so you don't need to declare it explicitly if you use <context:annotation-config />.
From spring javadoc
BeanPostProcessor that processes PersistenceUnit and PersistenceContext annotations, for injection of the corresponding JPA resources EntityManagerFactory and EntityManager. Any such annotated fields or methods in any Spring-managed object will automatically be injected.
This post-processor will inject sub-interfaces of EntityManagerFactory and EntityManager if the annotated fields or methods are declared as such. The actual type will be verified early, with the exception of a shared ("transactional") EntityManager reference, where type mismatches might be detected as late as on the first actual invocation.