<bean id="transactionManager"
class="org.springframework.jdbc.datasource.SpringTransactionManager">
<property name="dataSource" ref="dataSource" />
<property name="globalRollbackOnParticipationFailure" value="false" />
</bean>
Can anyone help me to figure out that how "globalRollbackOnParticipationFailure" property works in different scenarios??
Related
I'm working on spring boot application, which already has a database connection established in its applicationContext.xml file and the necessary transaction manager and vendors etc.
I now need to connect the app to a second database. But I'm having issues with this. In my unit tests the connection is fine and can make simple queries to retrieve data, which is all I need it to do. However when I compile the app into a jar and run it, I get the following error
NoUniqueBeanDefinitionException: No qualifying bean of type "org.springframework.transaction.PlatformTransactionManager" available: expected single matching bean but found 2: transactionManager, transactionManager2
I have spent ages looking up how to solve this, and the suggested fixes I have found here , here and here have not worked.
I have one persistence.xml with two persistence units defined. And in my applicaitonContext.xml I defined two datasources, two transaction managers and two entity Manager Factories. I then use the #persitsencecontext and #Transactional("") annotations to say which persistence unit and managers to use, but I still get an error. I also added in the <qualifier> tag to the app context file, as I saw this as a suggested fix with the #transactional annotation, still no luck.
My code is below, can anyone spot an errors I have made, and why it may not be working as expected
applicationContext.xml
<bean id="dataSource1" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="..."/>
<property name="username" value="..."/>
<property name="password" value="..."/>
</bean>
<bean id="entityManagerFactory" name="proxy">
<property name="persistenceUnitName" value="proxy" />
<property name="persistenceUnitXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="dataSource" ref="dataSource1" />
<property name="jpaVendorAdapter" ref="hiberanteVendorAdapter" />
<property name="jpaProperties">
<props>
<prop key="hiberante.hbm2ddl.auto">valudate</prop>
</props>
</property>
</bean>
<bean id="hibernateVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" />
<property name="database" value="HSQL" />
<property name="showSql" value="true" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<qualifier value="transactionManager1" />
</bean>
<!-- Second datasource -->
<bean id="dataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="..."/>
<property name="username" value="..."/>
<property name="password" value="..."/>
</bean>
<bean id="entityManagerFactory2" name="proxy">
<property name="persistenceUnitName" value="proxy2" />
<property name="persistenceUnitXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="dataSource" ref="dataSource2" />
<property name="jpaVendorAdapter" ref="hiberanteVendorAdapter2" />
<property name="jpaProperties">
<props>
<prop key="hiberante.hbm2ddl.auto">valudate</prop>
</props>
</property>
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory2" />
<qualifier value="transactionManager2" />
</bean>
<bean id="hibernateVendorAdapter2" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
<tx:annotation-driven/>
Implementation
#Repository
#Transactional("transactionManager2")
public class myDaoImpl extends GenericJPADao<Integer, Integer> implements ImyDao {
#PersistenceContext(unitName="proxy2")
protected EntityManager em;
}
SOLUTION
The accepted answer was the correct solution for me, but a few things to note. The beans have to point to their respective entityManagerFactory's and you need to be careful on which bean you set the autowire-candidate="false" on, as I set it on the incorrect one at first, and had transactions rolled back as a result. I think there could be cleaner solution to this, but as a quick fix it works fine
try this :
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" autowire-candidate="false">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
I am using Spring Batch 2 version. I am reading data from database using JdbcCursorItemReader.I have successfully fetched the data and also written it to a file.
Below is itemReader bean defined in Job.xml File::
<bean id="itemReader"
class="org.springframework.batch.item.database.JdbcCursorItemReader"
scope="step">
<property name="dataSource" ref="dataSource" />
<property name="sql"
value="select u.ID, u.USER_LOGIN, u.PASSWORD, u.AGE from USERS u" />
</property>
<property name="rowMapper">
<bean class="com.example.UserRowMapper" />
</property>
</bean>
But the issue is,my query is quite big so I just want to keep that query out of xml file and get that query from other file or property file(.property,yaml or xml).
So that I can write xml code as below::
<bean id="itemReader" class="org.springframework.batch.item.database.JdbcCursorItemReader" scope="step">
<property name="dataSource" ref="dataSource" />
<property name="sql" value="$sql_query" />
</property><property name="rowMapper">
<bean class="com.example.UserRowMapper" />
</property>
</bean>
What is best way to achieve this?
<bean id="myProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>path1.properties</value>
<value>path2.properties</value>
.....
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="false"/>
</bean>
...
<bean id="itemReader" class="org.springframework.batch.item.database.JdbcCursorItemReader" scope="step">
<property name="dataSource" ref="dataSource" />
<property name="sql" value="${sql_query}" />
</property><property name="rowMapper">
<bean class="com.example.UserRowMapper" />
</property>
</bean>
path1.properties:
sql_query=value
PropertySourcesPlaceholderConfigurer is preffered in 3.1 and higher, instead of PropertyPlaceholderConfigurer
You can add sql in jobexecutioncontext by using job listener before step.
I am looking using #Transactional on one of the Service methods. However when an exception occurs, the transaction is not getting rolled back. I tried the same with #Transactional(rollbackFor=Exception.class). My code as follows:-
#Override
#Transactional(rollbackFor=Throwable.class)
public boolean addUser(User user) throws Exception{
boolean userAdded = userDao.addUser(user);
boolean userRegistrationRecorded = userDao.recordUserRegistraionDetails(user);
return true;
}
I read lot of posts and every one says that Spring handles only RuntimeExceptions and not checked Exceptions other than RmiException. I need a solution that works for any kind of Exception. Some one suggested me to write own annotation, where as others suggested of having a TransactionManager as part of applicationContext.xml file. A detailed solution will definitely help me.
By the way I am using Spring JdbcTemplate. The strange thing I observe is though the Exceptions raised by Spring are RuntimeExceptions the transaction is not getting rolled back. I am trying to raise an Exception by adding the same User in the above scenario.
My applicationContext.xml is as follows:-
<context:component-scan base-package="org.chaperone.services.security.*" />
<context:annotation-config />
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="searchSystemEnvironment" value="true" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="${DATABASE_URL}" />
<property name="username" value="${DATABASE_USER_NAME}" />
<property name="password" value="${DATABASE_PASSWORD}" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
The ease-of-use afforded by the use of the #Transactional annotation is best illustrated in this link
you have to add :
<tx:annotation-driven transaction-manager="transactionManager" />
I need to configure xml file for DAO. So in my xml file, I have declared two entityManager Factory and I want to set one of them as default persistence unit. I have declared that part as below in my dao.xml
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
property name="defaultPersistenceUnitName" value="pumps-jpa"/>
</bean>
But, it didn't not work for me, it was not taking default persistence unit. I was getting error like this
No unique bean of type is defined: expected single bean but found 2:
After lot of searching, I found one code snippet in which they have mentioned bean id as spring class name i.e. org.springframework.context.annotation.internalPersistenceAnnotationProcessor, as shown below
<bean id="org.springframework.context.annotation.internalPersistenceAnnotationProcessor"
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
property name="defaultPersistenceUnitName" value="pumps-jpa"/>
</bean>
So, after mentioning this bean id, it is taking default persistence unit name. I want to know, why do I need to mention spring class (org.springframework.context.annotation.internalPersistenceAnnotationProcessor) as bean id? Is it a kind of hack or something?
Whole dao.xml is declared below
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="file:${catalina.base}/conf/pumps-dbconfig.properties"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass">
<value>${jdbc.driver}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="user">
<value>${jdbc.user}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
<property name="initialPoolSize"><value>10</value></property>
<property name="minPoolSize"><value>10</value></property>
<property name="maxPoolSize"><value>${jdbc.maxConnections}</value></property>
<property name="maxIdleTimeExcessConnections"><value>600</value></property>
<!-- <property name="timeout"><value>0</value></property> --> <!-- 0 means: no timeout -->
<property name="idleConnectionTestPeriod"><value>60</value></property>
<property name="acquireIncrement"><value>5</value></property>
<property name="maxStatements"><value>0</value></property> <!-- 0 means: statement caching is turned off. -->
<property name="numHelperThreads"><value>3</value></property> <!-- 3 is default -->
<property name="unreturnedConnectionTimeout"><value>0</value></property>
<property name="debugUnreturnedConnectionStackTraces"><value>true</value></property>
<property name="testConnectionOnCheckout"><value>true</value></property>
</bean>
<!--
Configuration for Hibernate/JPA
-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="pumps-jpa" />
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<!-- DEFAULT PERSISTENCE UNIT DECLARATION -->
<bean id="org.springframework.context.annotation.internalPersistenceAnnotationProcessor"
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
<property name="defaultPersistenceUnitName" value="pumps-jpa"/>
</bean>
<bean id="r-dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass">
<value>${r-jdbc.driver}</value>
</property>
<property name="jdbcUrl">
<value>${r-jdbc.url}</value>
</property>
<property name="user">
<value>${r-jdbc.user}</value>
</property>
<property name="password">
<value>${r-jdbc.password}</value>
</property>
<property name="initialPoolSize"><value>10</value></property>
<property name="minPoolSize"><value>10</value></property>
<property name="maxPoolSize"><value>${r-jdbc.maxConnections}</value></property>
<!-- <property name="timeout"><value>0</value></property> --> <!-- 0 means: no timeout -->
<property name="maxIdleTimeExcessConnections"><value>600</value></property>
<property name="idleConnectionTestPeriod"><value>60</value></property>
<property name="acquireIncrement"><value>5</value></property>
<property name="maxStatements"><value>0</value></property> <!-- 0 means: statement caching is turned off. -->
<property name="numHelperThreads"><value>3</value></property> <!-- 3 is default -->
<property name="acquireRetryAttempts"><value>3</value></property>
<property name="testConnectionOnCheckout"><value>true</value></property>
</bean>
<!--
Configuration for Hibernate/JPA
-->
<bean id="r-entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="pumps-jpa" />
<property name="dataSource" ref="r-dataSource" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
</bean>
<bean id="BaseDataConnection" class="com.myntra.commons.dao.impl.BaseDataConnection">
<property name="roEntityManagerFactory" ref="r-entityManagerFactory" />
</bean>
I think your original problem was not what you meant! By configuration you can refer to one of your Entity Manager's existing Persistence Unit implementations as 'the default persistence unit'! You can do this in your XML config! persistence.xml in JPA is your persistence config your beans (configuration) xml is an other option to point to some of the defined persistence units. Please post your whole config xml ...
For the rest of your problem with the Bean ID:
There is already a Bean in your container initialised with the same name.
The Container is using the Bean Id as a unique Id of your identifiable code fragment! If you use another name then your container will initialise another bean instance of the same class and give it the other name. However as I pointed out above this is not related to your problem! (Even if you can bypass your existing bean implementations and redefine your config if you do not have other options!)
I am using Spring and Hibernate with Jta Transactions, I have 2 databases, and I have a problem in a transactional method.
In this method I insert a lot of objects but I throws an exception to rollback the insertions, here the code works as I expected because the objects dont appear into the database.
But if I add a line in the method that get the objects of the same table, the objects are committed into the database.
I think that when I make a SELECT the objects are auto-committed, because the exception its thrown again and the objects persists into the database.
My xml and code:
dao.xml
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:configuracion_dao.properties" />
</bean>
<bean name="productosDAO" class="practica1.hibernate.HibernateProductosDAOImpl"
parent="abstractPracticaBean">
<property name="sessionFactory" ref="hibernateSessionFactory" />
</bean>
<bean name="tercerosDAO" class="${tercerosDAO.classname}" parent="abstractPracticaBean">
<property name="dataSource" ref="dataSourceDatos" />
</bean>
<bean name="auditoriaDAO" class="practica1.hibernate.HibernateAuditoriaDAOImpl" parent="abstractPracticaBean">
<property name="sessionFactory" ref="hibernateSessionFactory2" />
</bean>
<bean id="hibernateSessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSourceDatos" />
<property name="mappingResources">
<list>
<value>hibernate-mappings.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value>
</property>
</bean>
<bean id="hibernateSessionFactory2"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSourceAuditoria" />
<property name="mappingResources">
<list>
<value>hibernate-mappings-auditoria.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value>
</property>
</bean>
<bean name="dataSourceDatos" class="org.enhydra.jdbc.standard.StandardXADataSource">
<property name="driverName" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="url" value="jdbc:derby:/tmp/datos.db;create=true" />
<property name="transactionManager" value="#{txManager.transactionManager}" />
</bean>
<jdbc:initialize-database data-source="dataSourceDatos"
ignore-failures="ALL">
<jdbc:script location="classpath:practica1/sql/creacion_derby.sql" />
<jdbc:script location="classpath:practica1/sql/datos.sql" />
</jdbc:initialize-database>
<bean name="dataSourceAuditoria" class="org.enhydra.jdbc.standard.StandardXADataSource">
<property name="driverName" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="url" value="jdbc:derby:/tmp/auditoria.db;create=true" />
<property name="transactionManager" value="#{txManager.transactionManager}" />
</bean>
<jdbc:initialize-database data-source="dataSourceAuditoria"
ignore-failures="ALL">
<jdbc:script location="classpath:practica1/sql/creacion_auditoria_derby.sql" />
</jdbc:initialize-database>
<bean id="txManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" value="#{jotm.transactionManager}" />
<property name="userTransaction" value="#{jotm.userTransaction}" />
</bean>
<bean id="jotm" class="org.objectweb.jotm.Jotm" destroy-method="stop">
<constructor-arg value="true" />
<constructor-arg value="false" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
bo.xml
<bean name="tercerosBO" class="practica1.impl.TercerosBOImpl"
parent="abstractPracticaBean" autowire="constructor">
</bean>
<bean name="productosBO" class="practica1.impl.ProductosBOImpl"
parent="abstractPracticaBean">
<property name="productosDAO" ref="productosDAO" />
<property name="auditoriaDAO" ref="auditoriaDAO" />
</bean>
aplicacion.xml
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames" value="mensajes" />
</bean>
<bean id="abstractPracticaBean" class="practica1.impl.AbstractPracticaBean" abstract="true">
<property name="messageSource" ref="messageSource"></property>
</bean>
<import resource="bo.xml" />
<import resource="dao.xml" />
Transactional method:
#Transactional
#Override
public void actualizaPrecio(double porcentaje) {
internalActualizaPrecio(porcentaje);
}
private void internalActualizaPrecio(double porcentaje) {
auditoriaDAO.insertAuditoria(getMessageSource().getMessage(
"mensaje.actualizar_productos", new Object[] { porcentaje },
null));
int i = 0;
auditoriaDAO.getAuditorias(); // Without this line its works like I expected
List<Producto> productos = productosDAO.getProductos();
for (Producto producto : productos) {
i++;
if (i > 3)
throw new UnsupportedOperationException(
"Error para que veamos las transacciones");
producto.setPrecio(producto.getPrecio().multiply(
new BigDecimal(porcentaje).divide(new BigDecimal(100))));
productosDAO.updateProducto(producto);
}
}
I realised that if I use auditoriaDAO.getAuditorias() the rollback only affects to Producto but if I use productoDAO.getProductos() the rollback only affects to Auditoria...
You may be mixing up flush and commit here: a SELECT statement usually flushes all previous SQL statements, in order to fetch up-to-date data (regarding the previous changes you made in the tx). It may be possible that before such a SELECT statement is done (the following DAO calls are made to the 2nd sessionFactory if I'm not mistaken), the exception exits the method without a flush. Hence no modification in database.
So the question is: are you sure you're rollbacking the tx effectively? I see you've annotated a private method: the proxy-based mechanism of Spring AOP don't handle that! You must annotate a public method and call it from outside the annotated method's class, due to this very proxy-based mechanism. See the "Method visibility and #Transactional" block in the documentation.
Another lead: you have 2 sessionFactories, so I assume you're using XA transactions/datasources: are you sure this part of the conf is OK?
Please check auditoriaDAO and productosDAO and search for other transactional annotation. I think a new transaction is created somewhere and the UnsupportedException rollbacks only the last transaction, and the parent transaction is committed. Hope I helped!
I have found two example. Please check it.
JOTM transactions in spring and hibernate
Access Multiple Database Using Spring 3, Hibernate 3 and Atomikos