In my spring batch job, my item processor splits the object, which the item reader reads, into seven lists of variable lengths. These lists have to be written to seven tables in the DB and any errors (like db rejecting records for any reason) must cause the transaction to rollback on all seven tables.
Currently, I create a wrapped object with these seven lists which are passed to the custom item writer. The writer takes all these items, creates its own seven lists so that it only has seven batched writes (using DAOs based on JdbcTemplate) for a batch of the wrapped objects returned by the item processor.
My writer calls the insert function for each of these tables sequentially which I would like to speed up. I was wondering if I could write the lists, to their respective tables, in parallel so that the overall execution time is the time of the longest write. One requirement I cannot compromise is that this has to be in a single transaction which needs to be rolled back should any of the writers have any exceptions.
here's a simple solution utilizing a TaskExecutor and extending on the org.springframework.batch.item.support.CompositeItemWriter.
package de.incompleteco.spring.batch.item.support;
import java.util.List;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.CompositeItemWriter;
import org.springframework.core.task.TaskExecutor;
import org.springframework.util.Assert;
import de.incompleteco.spring.domain.SimpleEntity;
public class ParallelCompositeItemWriter extends CompositeItemWriter<SimpleEntity> {
private List<ItemWriter<? super SimpleEntity>> delegates;
private TaskExecutor taskExecutor;
#Override
public void write(final List<? extends SimpleEntity> item) throws Exception {
for (final ItemWriter<? super SimpleEntity> writer : delegates) {
taskExecutor.execute(new Runnable() {
#Override
public void run() {
try {
writer.write(item);
} catch (Throwable t) {
rethrow(t);
}
}
private void rethrow(Throwable t) {
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
}
else if (t instanceof Error) {
throw (Error) t;
}
throw new IllegalStateException(t);
}
});
}//end for
}
public void setTaskExecutor(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
#Override
public void setDelegates(List<ItemWriter<? super SimpleEntity>> delegates) {
this.delegates = delegates;
super.setDelegates(delegates);
}
#Override
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
Assert.notNull(taskExecutor,"Task executor needs to be set");
}
}
an example configuration would look something like this;
<batch:job id="simpleJob">
<batch:step id="simpleJob.step1">
<batch:tasklet>
<batch:chunk reader="reader" writer="writer" commit-interval="10"/>
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="reader" class="org.springframework.batch.item.support.IteratorItemReader">
<constructor-arg ref="itemList"/>
</bean>
<bean id="writer" class="de.incompleteco.spring.batch.item.support.ParallelCompositeItemWriter">
<property name="delegates" ref="writerDelegates"/>
<property name="taskExecutor" ref="writerTaskExecutor"/>
</bean>
<util:list id="writerDelegates">
<bean class="org.springframework.batch.item.database.JdbcBatchItemWriter">
<property name="dataSource" ref="dataSource1"/>
<property name="sql" value="insert into test_table (idcol,stuff) values (:idCol,:stuff)"/>
<property name="itemSqlParameterSourceProvider">
<bean class="org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider"/>
</property>
</bean>
<bean class="org.springframework.batch.item.database.JdbcBatchItemWriter">
<property name="dataSource" ref="dataSource2"/>
<property name="sql" value="insert into test_table (idcol,stuff) values (:idCol,:stuff)"/>
<property name="itemSqlParameterSourceProvider">
<bean class="org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider"/>
</property>
</bean>
</util:list>
<util:list id="itemList">
<bean class="de.incompleteco.spring.domain.SimpleEntity">
<constructor-arg value="stuff1"/>
</bean>
<bean class="de.incompleteco.spring.domain.SimpleEntity">
<constructor-arg value="stuff2"/>
</bean>
<bean class="de.incompleteco.spring.domain.SimpleEntity">
<constructor-arg value="stuff3"/>
</bean>
</util:list>
<task:executor id="writerTaskExecutor" pool-size="3"/>
<bean id="dataSource1" class="bitronix.tm.resource.jdbc.PoolingDataSource" init-method="init" destroy-method="close">
<property name="className" value="org.h2.jdbcx.JdbcDataSource" />
<property name="uniqueName" value="#{T(System).currentTimeMillis()}" />
<property name="allowLocalTransactions" value="true"/>
<property name="maxPoolSize" value="2" />
<property name="driverProperties">
<props>
<prop key="URL">jdbc:h2:mem:a;DB_CLOSE_DELAY=-1</prop>
</props>
</property>
</bean>
<bean id="dataSource2" class="bitronix.tm.resource.jdbc.PoolingDataSource" init-method="init" destroy-method="close">
<property name="className" value="org.h2.jdbcx.JdbcDataSource" />
<property name="uniqueName" value="#{T(System).currentTimeMillis()}" />
<property name="allowLocalTransactions" value="true"/>
<property name="maxPoolSize" value="2" />
<property name="driverProperties">
<props>
<prop key="URL">jdbc:h2:mem:b;DB_CLOSE_DELAY=-1</prop>
</props>
</property>
</bean>
<jdbc:initialize-database data-source="dataSource1">
<jdbc:script location="classpath:/META-INF/sql/schema-h2.sql"/>
</jdbc:initialize-database>
<jdbc:initialize-database data-source="dataSource2">
<jdbc:script location="classpath:/META-INF/sql/schema-h2.sql"/>
</jdbc:initialize-database>
<!-- XA transaction -->
<bean id="btmConfig" factory-method="getConfiguration" class="bitronix.tm.TransactionManagerServices"/>
<bean id="BitronixTransactionManager" factory-method="getTransactionManager"
class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig" destroy-method="shutdown" />
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="BitronixTransactionManager" />
<property name="userTransaction" ref="BitronixTransactionManager" />
</bean>
this example uses the following;
Bitronix JTA to support transactions across multiple databases
a very simple model of a simple entity into a simple jdbc record
(the stuff in the database is very crude and just an example)
Related
I have a Spring Batch partition job. I’m using CompositeProcessor, read data from DB and save these items into an CopyOnWriteArrayList. Because the environment is concurrent but my CopyOnWriteArrayList is being utilized for other threads and mix information, I don’t know why and what I am doing bad, and the output writing them into files for each thread.
public class CustomerItemProcessor implements ItemProcessor<beangenerico,CopyOnWriteArrayList<beanCustomer>> {
private CustomerDAO customerDAO;
private CopyOnWriteArrayList<beanCustomer> listbean;
public CopyOnWriteArrayList<beanCustomer> process(beangenerico rangos) throws Exception {
listbean = customerDAO.getAccAgentes(rangos);
if(listbean != null) {
//customer.setId(currentCustomer.getId());
return listbean;
}else{
return null;
}
}
The configuration of my batch im XML:
<batch:job id="partitionJob" xmlns="http://www.springframework.org/schema/batch">
<batch:step id="masterStep">
<batch:partition step="slave" partitioner="rangePartitioner">
<batch:handler grid-size="10" task-executor="taskExecutor"/>
</batch:partition>
</batch:step>
</batch:job>
<!-- each thread will run this job, with different stepExecutionContext values. -->
<batch:step id="slave" xmlns="http://www.springframework.org/schema/batch">
<batch:tasklet task-executor="taskExecutor" throttle-limit="1">
<batch:chunk reader="beaniniendreader" writer="tempRecordsWriter" processor="completeItemProcessor" commit-interval="1" />
</batch:tasklet>
</batch:step>
<bean id="taskExecutor" class="org.springframework.core.task.SimpleAsyncTaskExecutor" />
<bean id="rangePartitioner" class="my.package.springbatch.RangePartitioner" />
<bean id="beaniniendreader" class="my.package.springbatch.FormiikReader" scope="step"></bean>
<bean id="beanprocessor" class="my.package.springbatch.FormiikProcessor" scope="step">
<property name="accountExecutiveDao" ref="accountExecutiveDao"/>
</bean>
<bean id="beanprocessor2" class="my.package.springbatch.CustomerItemProcessor" scope="step">
<property name="customerDAO" ref="customerAccDao"/>
</bean>
<bean id="completeItemProcessor" class="org.springframework.batch.item.support.CompositeItemProcessor">
<property name="delegates">
<list>
<ref bean="beanprocessor2"/>
<ref bean="accItemprocessor"/>
<ref bean="beanaccDataItem"/>
</list>
</property>
</bean>
<bean id="tempRecordsWriter" class="my.package.springbatch.ListDelegateWriter" scope="step">
<property name="delegate" ref="flatFileItemWriterPartition"/>
</bean>
<!-- csv file writer -->
<bean id="flatFileItemWriterPartition" class="org.springframework.batch.item.file.FlatFileItemWriter"
scope="step" >
<property name="resource"
value="file:csv/outputs/users.processed#{stepExecutionContext[fromId]}-#{stepExecutionContext[toId]}.csv" />
<property name="appendAllowed" value="false" />
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<property name="delimiter" value="," />
<property name="fieldExtractor">
<bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<property name="names" value="cuenta, name, purchasedPackage" />
</bean>
</property>
</bean>
</property>
</bean>
I going back to take the subject of my code, it is advised to me using Threadlocal for storing thread-specific data whereby it´s works . Here I put my code again. Thanks for your replies.
public class CustomerItemProcessor implements ItemProcessor<beangenerico,ThreadLocal<CopyOnWriteArrayList<beanCustomer>>> {
private CustomerDAO customerDAO;
private ThreadLocal<CopyOnWriteArrayList<beanCustomer>> listbean = new ThreadLocal<CopyOnWriteArrayList<beanCustomer>>();
public ThreadLocal<CopyOnWriteArrayList<beanCustomer>> process(beangenerico rangos) throws Exception {
listbean.set(new CopyOnWriteArrayList<beanCustomer>());
listbean = customerDAO.getAccAgentes(rangos);
if(listbean != null) {
return listbean;
} else {
return null;
}
}
public void setCustomerDAO(CustomerDAO customerDAO) {
this.customerDAO = customerDAO;
}
}
I have a problem with transaction auto committed after call another dao native query.
Both service and dao signed as #Transactional.
What am I doing wrong here?
Spring 4.2.x
Hibernate 5.1.0
Atomikos 3.9.3
This is my setup:
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="jtaPlatformAdapter" class="com.xxx.JtaPlatformAdapter">
<property name="jtaTransactionManager" ref="transactionManager" />
</bean>
<bean class="com.atomikos.icatch.jta.UserTransactionManager" destroy-method="close" id="atomikosTransactionManager" init-method="init">
<property name="forceShutdown" value="true" />
<property name="startupTransactionService" value="true" />
</bean>
<bean class="com.atomikos.icatch.jta.UserTransactionImp" id="atomikosUserTransaction" />
<bean class="org.springframework.transaction.jta.JtaTransactionManager" id="transactionManager">
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="userTransaction" ref="atomikosUserTransaction" />
</bean>
<bean id="datasouce" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
...
</bean>
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" id="JPAVendorAdapter">
...
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="emf" depends-on="transactionManager,jtaPlatformAdapter">
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="packagesToScan" value="com.xxx.server"/>
<property name="dataSource" ref="datasouce" />
<property name="persistenceUnitName" value="pun" />
<property name="jpaVendorAdapter" ref="JPAVendorAdapter" />
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.connection.release_mode" value="on_close" />
<entry key="hibernate.transaction.jta.platform" value="com.xxx.server.JtaPlatformAdapter" />
</map>
</property>
</bean>
persistence.xml
<persistence-unit name="pun" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
service
#Transactional
#Scope("prototype")
public synchronized void save(EntityObj model) throws Exception {
model.setX(30);
model.setY(40);
EntityObj oldModel = entityObjDAO.findById(model.getId());
// after call findById, the model had been commit to DB
...
...
...
entityObjDAO.store(model); // this will call entityManager.merge(model)
entityObjDAO.flush();
}
DAO
#Transactional
public EntityObj findById(String id) {
EntityObj model = null;
String sql = "select id,x,y from EntityObj where id = :id"; // this is a native sql query
Query query = this.entityManager.createNativeQuery(sql);
query.setParameter("id", id);
Object[] rs = (Object[]) query.getSingleResult();
if (rs != null) {
model = new EntityObj();
model.setId(id);
model.setX(rs[1] == null ? null : (Integer) rs[1]);
model.setY(rs[2] == null ? null : (Integer) rs[2]);
}
return model;
}
thanks!
If you are using #Transactional in your code, Spring creates a proxy object for your Dao object (wrapper).
So it looks like this if your application is running:
public EntityObj proxyMethodForFindById(String id) {
try {
// 1. start transaction
startTransaction();
// 2. execute your code
return yourDaoObject.findById(id);
} finally { // [!] PSEUDO CODE: NO EXCEPTION HANDLING
// commit transaction
commitTransaction();
}
}
So what happens in your code?
Your save method is marked also as #Transactional. So if you are changing your object by setting:
model.setX(30);
model.setY(40);
Spring creates two proxies. One for Service and one four your Dao. On the End of the findById-Transaction this changes will be commited. Nested transactions is the keyword.
You should remove #Transaction in your findById-Method or better in the whole Dao object. Service should be transactional, not Dao-layer.
I have an sql session thus defined:
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
<constructor-arg index="1" value="BATCH" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="..." />
</bean>
<bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="25" />
</bean>
Now, in my service, I have to make some select on a table and some inserts in a different table.
#Transactional
public class MyWebService{
#Autowired
private TaskExecutor executor;
#Autowired
private SelectTableMapper sm;
#Autowired
private InsertTableMapper it;
public void service(){
int rowCount = ...//getting row count
int batch = rowCount/numThreads;
//computing an interval for each thread with non overlapping rows
for(int i=0;i<numThread;i++)
executor.execute(new MyTask(//interval//));
..waiting for all tasks and finally returning
}
private class MyTask implements Runnable{
public void run(){
List<Row> rows = sm.select(//interval//);
for(Row row : rows){
if(//some condition//)
it.insert(row); //if I comment here it successfully completes
}
}
}
}
Problem is that program just freezes! And I am sure it is not my logic's fault because program successfully ends by commenting the insertion line.
So I guess it is a concurrency problem on the second table, the one I am inserting data in.
I'm trying to implement LDAP transaction using Spring.I have configured the spring xml based on the spring Doc, but while running the program i'm getting below mentioned error:
java.lang.IllegalStateException: No value for key [org.springframework.ldap.core.support.LdapContextSource#27bd27bd] bound to thread [main]
at org.springframework.transaction.support.TransactionSynchronizationManager.unbindResource(TransactionSynchronizationManager.java:199)
at org.springframework.transaction.compensating.support.AbstractCompensatingTransactionManagerDelegate.doCleanupAfterCompletion(AbstractCompensatingTransactionManagerDelegate.java:122)
at org.springframework.ldap.transaction.compensating.manager.ContextSourceTransactionManager.doCleanupAfterCompletion(ContextSourceTransactionManager.java:135)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager.java:1011)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:877)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:822)
at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:411)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:114)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy11.createUser(Unknown Source)
Note:I'm trying to rollback LDAP as well as DB.
Code snippet:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.apps.ldap.manager.UserManger;
import com.apps.ldap.model.UserBean;
public class SpringFrameworkLDAPClient {
private static ApplicationContext context = null;
public static void main(String[] args) {
try {
context = new ClassPathXmlApplicationContext("conf/springldap.xml");
UserManger userservice = (UserManger)context.getBean("userManger");
UserBean userbean = new UserBean();
userbean.setCommonName("Santhosh5");
userbean.setLastName("Rajendran5");
userbean.setEmail("rsanthoshkumarr#gmail.com");
userbean.setFirstName("Santhosh5");
userbean.setUserID("Santhosh5");
userservice.createuser(userbean);
} catch (Exception e) {
System.out.println("Error occured " + e);
e.printStackTrace();
}
}
}
UserService
#Transactional
public void createuser(UserBean contactDTO) {
Attributes personAttributes = new BasicAttributes();
BasicAttribute personBasicAttribute = new BasicAttribute("objectclass");
personBasicAttribute.add("person");
personAttributes.put(personBasicAttribute);
personAttributes.put("cn", contactDTO.getCommonName());
personAttributes.put("sn", contactDTO.getLastName());
DistinguishedName newContactDN = new DistinguishedName("ou=users");
newContactDN.add("cn", contactDTO.getCommonName());
ldapTemplate.bind(newContactDN, null, personAttributes);
}
XML:
<bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="ldap://xxxx:389" />
<property name="base" value="dc=xxx" />
<property name="userDn" value="cn=xxx" />
<property name="password" value="xxx" />
</bean>
<bean id="contextSource" class="org.springframework.ldap.transaction.compensating.manager.TransactionAwareContextSourceProxy">
<constructor-arg ref="contextSourceTarget" />
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource" />
</bean>
<bean id="transactionManager" class="org.springframework.ldap.transaction.compensating.manager.ContextSourceTransactionManager">
<property name="contextSource" ref="contextSource" />
</bean>
<bean id="contactDao" class="com.apps.ldap.daos.impl.Userservice">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
<bean id="myDataAccessObject" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="contactDao" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRES_NEW</prop>
</props>
</property>
</bean>
JARs used:
apache-commons-lang.jar
commons-logging-1.1.1.jar
ibatis-2.3.0.677.jar
jt400.jar
ldapbp-1.0.jar
org.springframework.aop-3.0.5.RELEASE.jar
org.springframework.asm-3.0.5.RELEASE.jar
org.springframework.beans-3.0.5.RELEASE.jar
org.springframework.context-3.0.5.RELEASE.jar
org.springframework.expression-3.0.5.RELEASE.jar
org.springframework.jdbc-3.0.5.RELEASE.jar
org.springframework.oxm-3.0.5.RELEASE.jar
org.springframework.test-3.0.5.RELEASE.jar
org.springframework.transaction-3.0.5.RELEASE.jar
org.springframework.web-3.0.5.RELEASE.jar
spring-core-3.0.4.RELEASE.jar
spring-ldap-1.1.2.jar
spring-ldap-core-1.3.2.RELEASE.jar
spring.jar
SpringUtils-0.2.jar
I am new to Spring but in general I am aware of it's features so I decided to use it in one of my projects. Main problem however is with Hibernate. Before this idea of introducing spring the premise is this:
My application (not web) had to connect to a DB and gather information from it using "persistence_1.xml" with it's own set of entity classes. In other words everything related to "persistence_1.xml" was read only so that no tragedies would occur. Also "persistence_1.xml" with persistence-unit of name "p1" came from web-app dependencies. So picture is this: my app (not-web) written with the support of maven, took dependencies of the other application to access database and gather information.
And the other "persistence_2.xml" with persistence-unit name of "p2" and it's own subset of entities was created by me to store gathered and processed information into the same database.
So originally I had two entity managers one responsible for "p1" another for "p2".
I have seen some material on the internet where they show how to configure two entity managers with different dataSources but I can not figure out how to create two entity managers in SPRING using their own set of ENTITIES.
Let's say "test" is only associated with "UserEntity" and "dummy" is only associted with "DumbEntity".
Now everything get's mashed up along the way and no matter which PU name I type in in #PersistenceContext(name = "test") - it can query for any entity in database.
This is example of persistence.xml:
<persistence-unit name="test" type="RESOURCE_LOCAL">
<class>org.test.db.UserEntity</class>
</persistence-unit>
<persistence-unit name="dummy" type="RESOURCE_LOCAL">
<class>org.test.db.DumbEntity</class>
</persistence-unit>
Bean definition:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/spring"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="test" />
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
</bean>
</property>
</bean>
<bean id="entityManagerFactory2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="dummy" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
</bean>
</property>
</bean>
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory2"/>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean name="userDao" class="org.test.services.UserDaoImpl" />
My UserDaro service
public class UserDaoImpl implements UserDao {
#PersistenceContext(unitName = "test")
private EntityManager entityManager;
public UserDaoImpl() {
}
public UserDaoImpl(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
#Override
public void saveUser(UserEntity user) {
entityManager.persist(user);
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
#Override
public void saveUser(DumbEntity user) {
entityManager.persist(user);
}
#Override
public List<UserEntity> fetchAllUsers() {
String sql = "FROM UserEntity";
Query query = entityManager.createQuery(sql);
return query.getResultList();
}
#Override
public List<DumbEntity> fetchAllUsers2() {
String sql = "FROM DumbEntity";
Query query = entityManager.createQuery(sql);
return query.getResultList();
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
In any way whether or not I use fetchAllUsers() or fetchAllUsers2() I get the result, but I would like that each of these would only work with entityManager that only has the knowledge about about specific entities.
I would like you to share your thoughts on this one. Thank You.