I have the below configuration of my db-config.xml file in several applications in work. We are using Spring Batch and each app is harvesting data from several external DB's. Everything is working fine but the problem is that all apps are deployed on different servers and every time when the password expires for one of the "Data sources", we have to go on each server and change the password manually on the db-config file for each application.
Since all applications are using more or less the same Data Sources for harvesting (about 9 in total) I am currently looking at some alternatives, so rather then declaring the "Harvest Data sources" into the db-config.xml file to place all properties into a DB table and load the properties from there. When a password expire we do the change in one single place rather then x places.
I would really appreciate any pointers in the right direction just to get started...
Sample of my db-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver"></property>
<property name="url" value="jdbc:db2://1.111.1.11:50000/EX1"></property>
<property name="username" value="xxxxx" />
<property name="password" value="xxxxx" />
</bean>
<bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="ef_DataSource">
<property name="driverClass" value="com.ibm.db2.jcc.DB2Driver"></property>
<property name="acquireIncrement" value="5"></property>
<property name="maxIdleTime" value="3600"></property>
<property name="maxPoolSize" value="15"></property>
<property name="minPoolSize" value="5"></property>
<property name="numHelperThreads" value="3"></property>
<property name="unreturnedConnectionTimeout" value="3600"></property>
<property name="idleConnectionTestPeriod" value="100"></property>
<property name="jdbcUrl" value="jdbc:db2://2.222.2.22:50000/EX2"></property>
<property name="user" value="xxxxx" />
<property name="password" value="xxxxxx" />
</bean>
<!-- Harvest Data sources -->
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="rep1">
<property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver"></property>
<property name="url" value="jdbc:db2://1.11.11.111:60000/REPONE"></property>
<property name="username" value="xxxxxxxx" />
<property name="password" value="xxxxxxxx" />
</bean>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="rep4">
<property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver"></property>
<property name="url" value="jdbc:db2://22.444.44.44:50000/REPTWO"></property>
<property name="username" value="xxxxxxxx"></property>
<property name="password" value="xxxxxxxx"></property>
</bean>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="rep5">
<property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver"></property>
<property name="url" value="jdbc:db2://555.55.55.55:50000/REPTHREE"></property>
<property name="username" value="xxxxxxxx" />
<property name="password" value="xxxxxxxx" />
</bean>
<!-- More Harvest Data sources -->
Sample of the AbstractImportTasklet java class extended by all Tasklets classes
#Component
public abstract class AbstractImportTasklet implements ResourceLoaderAware, InitializingBean, Tasklet{
private ResourceLoader resourceLoader;
private JdbcTemplate jdbcTemplate;
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private DataSource dataSource;
#Autowired
AmDbDAO dao;
#Autowired
protected JobExplorer jobExplorer;
public AbstractImportTasklet() {
super();
}
#Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate(){
return namedParameterJdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void setNamedParameterJdbcTemplate(NamedParameterJdbcTemplate namedParameterJdbcTemplate){
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
}
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
#Override
public void afterPropertiesSet() throws Exception {
/*TimeZone.setDefault(TimeZone.getTimeZone("UTC"));*/
if(dataSource != null){
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
}
}
One of the possible approach would be to add a step at the beginning who would read the database containing the informations on the other ones (if I understood your use case correctly). This step would then load the results in the JobExecutionContext. The results would be used in the definition of the datasources.
Here's an example (step) :
public class LoadDatasources implements Tasklet {
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
// Query database here
[...]
// Save results in context
chunkContext.getStepContext().getJobExecutionContext().put(key, value)
return null;
}
}
XML configuration of the datasources :
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" step="scope">
<property name="driverClassName" value="#{jobExecutionContext['datasource1.driver']}"></property>
<property name="url" value="#{jobExecutionContext['datasource1.url']}"></property>
<property name="username" value="#{jobExecutionContext['datasource1.username']}"></property>
<property name="password" value="#{jobExecutionContext['datasource1.password']}"></property>
</bean>
This is the exact use case that Spring Cloud's Configuration Server solves. It allows you to configure things, like datasources, in a central repository. From there, you can refresh the configuration of the applications using it. You can read more about the Spring Cloud Configuration Server in the documentation here: https://github.com/spring-cloud-samples/configserver
Related
I have embedded H2 database for my Spring unit tests. The tables and data should be initialized with Liquibase. However, when a test is running, there are no data in the table.
I'm using Spring 4.2.1, Liquibase 4.7.1 and H2 2.1.210.
Below is my implementation:
The datasource is declare in .xml file
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:test;MODE=Oracle;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE" />
<property name="username" value="test" />
<property name="password" value="test" />
</bean>
<bean id="liquibase" class="liquibase.integration.spring.SpringLiquibase">
<property name="dataSource" ref="dataSource" />
<property name="changeLog" value="classpath:liquibase/changelog/sil_client_init.h2.sql" />
<property name="contexts" value="test" />
</bean>
<!-- Session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate-config.xml" />
</bean>
<!-- Transaction manager -->
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
The sil_client_init.h2.sql file contains SQL contains changeset for creating and inserting several data in the table.
I have a super class which load the context, including the "liquibase" bean declared above.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:applicationContext.xml" })
#Ignore
public class SpringApplicationContextIT {
#Before
public void setUp() {
BasicConfigurator.configure();
FacesContextMocker.mockFacesContext();
assertNotNull(applicationContext);
}
#Autowired
private ApplicationContext applicationContext;
}
From which my test class inherits
public class ClientDAOTest extends SpringApplicationContextIT {
#Autowired
private IClientDAO simpleClientDAO;
#Test
#Transactional
public void getAllClients() throws ClientDAOException {
simpleClientDAO.find();
}
When running getAllClients(), the context are loaded and there is log showing that my changesets Liquibase were running. However, when the test arrives at simpleClientDAO.find(), my Client table is empty.
Any idea of how to fix, how this could happen or how I could investigate the reason would be appreciated. Thank you so much in advance!
For those who might have the same problem, turn out the datasource is properly loaded but my sessions are not correctly connected.
I had to specify a package to scan for my sessionFactory bean:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<value>com.myApp.dao.entity</value>
</property>
<property name="configLocation" value="/WEB-INF/classes/hibernate-config.xml" />
</bean>
I have a spring batch application that uses Azure SQL server, it runs without any issues and updates the Database for a most part however I am getting the following error occasionally
what does it mean? how to handle this?
Note: this is a long running job executes for more than 2hrs. The above error reported after ~1.45hrs.
I am reading the data from CSV file using FlatfileReader & writing into Azure SQL Server using ItemWriter as mentioned below
public class StoreWriter implements ItemWriter<List<Store>> {
Logger logger = Logger.getLogger(StoreWriter.class);
private HibernateItemWriter<Store> hibernateItemWriter;
public StoreWriter(HibernateItemWriter<Store> hibernateItemWriter) {
this.hibernateItemWriter = hibernateItemWriter;
}
#Override
public void write(List<? extends List<Store>> items) throws Exception {
for (List<Store> Store : items) {
hibernateItemWriter.write(Store);
}
logger.info(String.format("Store Processing Completed %s", new LocalDateTime()));
}
}
Below is my Hibernate configuration
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager" lazy-init="true">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- HikariCP Database bean -->
<bean id="demoDataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig" />
</bean>
<!-- HikariConfig config that is fed to above dataSource -->
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="maximumPoolSize" value="50" />
<property name="idleTimeout" value="30000" />
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="url" value="jdbc:sqlserver://demo.database.windows.net:1433;database=sqldb;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;" />
<property name="username" value="user1" />
<property name="password" value="p#ssword1" /
</bean>
<bean class="org.springframework.batch.core.scope.StepScope" />
Please try using the annotation "#Transactional (propagation = Propagation.REQUIRES_NEW)" on the method where the records were committed.
I am using apache commons httpclient 4.3.x along with spring3. I am trying to wire up a connectionpool with it's associated socketconfig instance.
http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.html
http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/config/SocketConfig.html?is-external=true
My code looks like this:
<bean id="socketConfig" class="org.apache.http.config.SocketConfig" factory-method="custom" init-method="build">
<property name="soTimeout" value="60000"/>
<property name="soLinger" value="5" />
</bean>
<bean name="poolingHttpConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager" depends-on="socketConfig">
<property name="maxTotal" value="20" />
<property name="defaultMaxPerRoute" value="20" />
<property name="defaultSocketConfig" ref="socketConfig" />
</bean>
However, this is not working. The instance type that is used to setDefaultSocketConfig() on PoolingHttpClientConnectionManager is of type SocketConfig.Builder instead of SocketConfig.
What I want to have happen is as follows:
SocketConfig config = SocketConfig.custom()
.setSoTimeout(60000)
.setSoLinger(5)
.build()
So, I expect that the socketConfig bean type should be a SocketConfig instance, not a SocketConfig.Builder instance.
As per spring docs, I thought this should work.
http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#beans-factory-class-static-factory-method
is there anything I am doing wrong? Or is this just not supported in spring?
It turns out that the socketconfig builder instance is not designed to work with spring very well.
I had to use a spring beanfactory implementation to create the instance.
The bean class:
import org.apache.http.config.SocketConfig;
import org.springframework.beans.factory.FactoryBean;
public class SocketConfigFactoryBean implements FactoryBean<SocketConfig> {
int soLinger;
int soTimeout;
public SocketConfig getObject() throws Exception {
return SocketConfig.custom()
.setSoLinger(soLinger)
.setSoTimeout(soTimeout)
.build();
}
public Class<?> getObjectType() {
return SocketConfig.class;
}
public boolean isSingleton() {
return true;
}
public int getSoLinger() {
return soLinger;
}
public void setSoLinger(int soLinger) {
this.soLinger = soLinger;
}
public int getSoTimeout() {
return soTimeout;
}
public void setSoTimeout(int soTimeout) {
this.soTimeout = soTimeout;
}
}
The bean definition
<bean name="poolingHttpConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager">
<property name="maxTotal" value="20" />
<property name="defaultMaxPerRoute" value="20" />
<property name="defaultSocketConfig">
<bean class="org.apache.http.config.SocketConfig" factory-method="custom" init-method="build">
<bean class="com.ex.spring.beans.factory.SocketConfigFactoryBean">
<property name="soTimeout" value="60000"/>
<property name="soLinger" value="5" />
</bean>
</property>
</bean>
I was able to achieve it by doing the next configuration in spring:
<bean id="socketConfig" class="org.apache.http.config.SocketConfig" factory-method="custom">
<property name="soTimeout" value="1000" />
<property name="soLinger" value="5" />
</bean>
<bean name="poolingHttpConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager">
<property name="maxTotal" value="20" />
<property name="defaultMaxPerRoute" value="20" />
<property name="defaultSocketConfig">
<bean factory-bean="socketConfig" factory-method="build" />
</property>
</bean>
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)
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.