I am looking for a way to put CRUD of two data source into one transaction by Spring/JTA, but have following questions:
Is it ok that the datasource is is made oforg.apache.commons.dbcp.BasicDataSource instead of JNDI?
There are two parameters to intitiate a JtaTransactionManager:
public JtaTransactionManager(UserTransaction userTransaction,
TransactionManager transactionManager)
From Spring document:
userTransaction - the JTA UserTransaction to use as direct reference
transactionManager - the JTA TransactionManager to use as direct reference
If I have a datasource DS_A and another datasource DS_B, which both requires within the same transaction manager, then which should be the UserTransaction and how to define the TransactionManager, as I am just creating the JtaTransactionManager, does it mean another JtaTransactionManager? Also it looks both parameters are not required so how JtaTransactionManager can detect them from:
<context:annotation-driven/>
<tx:jta-transaction-manager/>
If everything is well defined in application context, then which transaction manager bean should referred in #Transactional annotation, if there are two datasources?
Is it ok that the datasource is is made oforg.apache.commons.dbcp.BasicDataSource instead of JNDI?
JNDI is just a way to access the datasource. To have distributed transactions across databases you need to use transactional data sources. For e.g. microsoft sql server jdbc driver has a transactional data source - com.microsoft.sqlserver.jdbc.SQLServerXADataSource.
If I have a datasource DS_A and another datasource DS_B, which both requires within the same transaction manager, then which should be the
UserTransaction and how to define the TransactionManager, as I am just
creating the JtaTransactionManager, does it mean another
JtaTransactionManager?
JtaTransactionManager is an implementation for JTA, delegating to a backend JTA provider. So you would need a JTA provider that implements distributed transactions. Bitronix is one such JTA provider. There are various configurations needed
a. hibernate.properties
<prop key="hibernate.transaction.factory_class">
<prop key="hibernate.transaction.manager_lookup_class">
<property name="useTransactionAwareDataSource" value="true"/>
b. Defining transaction manager and usertransaction beans
<bean id="BitronixTransactionManager" factory-method="getTransactionManager"
class="bitronix.tm.TransactionManagerServices" depends-on="bitronixConfiguration"
destroy-method="shutdown">
</bean>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="BitronixTransactionManager"/>
<property name="userTransaction" ref="BitronixTransactionManager"/>
<property name="allowCustomIsolationLevels" value="true"/>
</bean>
c. Transaction Interceptor and annotation support
<bean id="annotationTransactionSource"
class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"/>
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref local="transactionManager"/>
</property>
<property name="transactionAttributeSource">
<ref local="annotationTransactionSource"/>
</property>
</bean>
Spring 3.1 also introduced a #EnableTransactionManagement annotation so another way to configure would be
#Configuration
#EnableTransactionManagement
public class PersistenceJPAConfig{
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){
...
}
#Bean
public PlatformTransactionManager transactionManager(){
//configure JTA transaction manager
return transactionManager;
}
}
If everything is well defined in application context, then which transaction manager bean should referred in #Transactional annotation,
if there are two datasources?
I assume the above explanation should answer this question. There is just one transaction manager managing transactions over the two data sources. These are called distributed transaction and they use a two phase commit protocol. Go through this link for an introductory article on XA transactions.
Related
I have a Spring Boot 2 + Hibernate 5 Multi-tenant application that connected to multiple oracle databases. when I use JpaRepository, everything is fine, ie after recieving http request, the 'Interceptor' detects the data source and the 'MultiTenantConnectionProvider' implementation selects the correct DataSource to be used by TransactionManager.
What is the problem?
I want to use TransactionInterceptor to handle transactions on some methods(with method names) from specific beans(that extends JdbcDaoSupport or inject JdbcDaoSupport implementations). Sorry if I explained a little confusing.
But for every http request, the data source of that beans is immutable(the default data source). while injected repositories operate on the correct data source within the correct transaction.
<bean id="txProxyTemplate" abstract="true"
depends-on="transactionManager"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED,-Exception</prop>
</props>
</property>
</bean>
<bean id="genericJdbcDao" parent="txProxyTemplate">
<property name="target">
<bean class="org.broker.dao.impl.BaseGenericJdbcDAOImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
</property>
</bean>
Can anyone help solve this problem?
I finally solved the problem. Follow the code section:
#Bean("jdbcTemplate")
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public JdbcTemplate jdbcTemplate(
#Qualifier("tenantIdentifierResolver") TenantIdentifierResolverImpl tenantResolver,
#Qualifier("tenantConnectionProvider") DataSourceMultiTenantConnectionProviderImpl dataSourceProvider) {
return new RhaJdbcTemplate(dataSourceProvider.selectDataSource(tenantResolver.resolveCurrentTenantIdentifier()));
}
#Bean(value = "transactionInterceptor")
public TransactionInterceptor transactionInterceptor(
#Qualifier("txProxyTemplateConfig") Properties txProxyTemplateConfig,
#Qualifier("transactionManager") PlatformTransactionManager transactionManager) {
TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
transactionInterceptor.setTransactionAttributes(txProxyTemplateConfig);
transactionInterceptor.setTransactionManager(transactionManager);
return transactionInterceptor;
}
#Bean("genericJdbcDAO")
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public ProxyFactoryBean genericJdbcDAO(
#Qualifier("jdbcTemplate") JdbcTemplate jdbcTemplate) throws ClassNotFoundException {
BaseGenericJdbcDAOImpl genericJdbcDAO = new BaseGenericJdbcDAOImpl();
genericJdbcDAO.setJdbcTemplate(jdbcTemplate);
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(genericJdbcDAO);
proxyFactoryBean.setProxyInterfaces(new Class[] {BaseGenericJdbcDAO.class});
proxyFactoryBean.setInterceptorNames("transactionInterceptor");
return proxyFactoryBean;
}
Then inject BaseGenericJdbcDAO into the controller, as a sample:
#RestController
public class VoucherLineRest {
#Resource(name = "genericJdbcDAO")
private BaseGenericJdbcDAO genericJdbcDAO;
}
You will see that for every request the correct data source selected and TransactionInterceptor intercept every method called from BaseGenericJdbcDAO bean and apply the correct transaction propagation on it.
I hope you enjoy this experience.
I'm trying to properly use spring transaction-management functionality provided by MyBatis
I'm creating sqlSessionFactor in the following manner:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:some/package/**/*.xml" />
<property name="transactionFactory">
<beanclass="org.mybatis.spring.transaction.SpringManagedTransactionFactory" />
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
Now there is this section called "Programmatic Transaction Management" here which gets the reference of transactionManager and using this transactionManager we are doing rollback or commit depending upon whether we got an exception or not.
Now my question is that in my DAO layer should I explicitly do something like
public class UserDao extends SqlSessionDaoSupport {
PlatformTransactionManager transactionManager; // wired using bean-property
public void insertUser(Integer userId) {
try {
getSqlSession().insert("user-map.insertUser", userId);
} catch (Exception e) {
transactionManager.rollback(txStatus);
throw e;
}
transactionManager.commit(txStatus);
}
}
or just using the following thing (without programmatic transactions) will also perform all the insertions in a transactional way.
public class UserDao extends SqlSessionDaoSupport {
public void insertUser(Integer userId) {
getSqlSession().insert("user-map.insertUser", userId);
}
}
my mapper file looks something like this:
<insert id="insertUser" parameterType="HashMap">
<!-- this contains multiple insert queries -->
</insert>
Note that I've multiple inserts inside <insert>...</insert> and I want either all of them to happen or non-of them to happen.
This is another reference that I was using.
So a general question is that will MyBatis provide an automatic transaction-management around my <insert>...</insert> or will I have to explicitly use the transactionManager to achieve the transaction-management feature?
Here's the quote from the documentation you referenced:
MyBatis SqlSession provides you with specific methods to handle transactions programmatically. But when using MyBatis-Spring your beans will be injected with a Spring managed SqlSession or a Spring managed mapper. That means that Spring will always handle your transactions.
With the setup you provided transaction timespan is completely managed by spring that is if
you use declarative transaction management you don't need to do anything additionally. Spring will start transaction at the point it is directed to by your configuration.
The simple way to enable declarative transaction management is to add this to spring configuration:
<tx:annotation-driven/>
And then use #Transactional on your service methods:
#Service
public class MyService {
#Autowired
private UserDao userDao;
#Transactional
public addUser(User user) {
userDao.insertUser(user);
}
}
The section in the documentation you mentioned is about the (rare) cases when you want to use programmatic transaction management.
I'm able to call entityManager.merge(obj), but not entityManager.flush().
I am getting "no transaction in progress".
My application context has:
<jee:jndi-lookup jndi-name="${persistenceEMFJndiServerName}"
id="entityManagerFactory" expected-type="javax.persistence.EntityManagerFactory" />
<bean id="entityManager"
class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" >
</bean>
My persistence unit says transaction-type="JTA"
and I'm loading it via
#PersistenceContext
private EntityManager entityManager;
I've tried a few things, like:
entityManager.joinTransaction(),
entityManager.getTransaction().begin()/.end(),
#Resource UserTransaction with BEAN transaction management, but it says I cant, with JTA. There's just no transaction going on.
My method has
#Transactional
#TransactionAttribute(TransactionAttributeType.REQUIRED)
and it's an EJB, so I'm getting pretty annoyed. CMT JTA is supposed to do transactions all by itself.
Turns out it wasn't a JPA/JBoss/etc. issue. It was because my thread ran in a camel context.
It took me a day of searching to find out:
Important
: One transaction is associated with a single thread of execution!
– If you use “seda”, “vm”, “jms” or any other protocol in your sub route which will process the exchange in an different thread, this execution will not be part of this transaction context!
FYI:
"asynchronous transactions in Camel 3.0.0"
I had my entityManager.merge/flush code in a thread. Hence, no transaction. Got rid of thread, and now it works fine.
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.
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="data.emf" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="data.emf" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager2" />
In my service layer, can I use #Transactional(name="transactionManager2"); to identify which transaction manager I use if I have multiple transaction managers?
You can specify which tx manager to use with #Transactional using the value attribute:
A qualifier value for the specified
transaction.
May be used to determine the target
transaction manager, matching the
qualifier value (or the bean name) of
a specific PlatformTransactionManager
bean definition.
For example:
#Transactional("txManager1");
Alternatively, you can use the more explicit TransactionProxyFactoryBean, which gives you finer-grained control over what objects gets proxied by what tx managers. This still uses the annotations, but it doesn't auto-detect beans, it's configured explicitly on a bean-by-bean basis.
This normally isn't an issue, but it's not wise to have multiple transaction managers unless you have a very good reason to do so. If you find yourself needing two tx managers, it's usually better to see if you can make do with one. For example, if you have two data sources configured in your app server, you can incorporate both in a single JtaTransactionManager, rather than two seperate JpaTransactionManager or DataSourceTransactionmanagers.
More on the need for more than one transaction manager. You might be trying to do nested or separate transactions in sequence -- then you can use different propagation settings. You can achieve that with configuration using single transaction manager see Transaction propagation.