mybatis+oracle two DAO error - java

Is using two DAO at the same time impossible?
Error
private SqlSessionFactory factory = MyBatisconfig.getSqlSessionFactory();
getSqlSessionFactory(); <-- this is red line
Error
Syntax: The method getSqlSessionFactory() from the type MyBatisconfig refers to the missing type SqlSessionFactory
Here is the code I'm using :
public class MyBatisconfig {
private static SqlSessionFactory sqlSessionFactory;
public static SqlSessionFactory getSqlSessionFactory() {
if (sqlSessionFactory == null) {
String resource = "mybatis-config.xml";
Reader reader;
try {
reader = Resources.getResourceAsReader(resource);
sqlSessionFactory =
new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
return sqlSessionFactory;
}
}
AdminDAO.class
private SqlSessionFactory factory = MyBatisconfig.getSqlSessionFactory();
UserDAO.class
private SqlSessionFactory factory = MyBatisconfig.getSqlSessionFactory();
mybatis-config.xml
<configuration>
<properties resource="db.properties" />
<typeAliases>
<typeAlias type="human.vo.User" alias="user" />
<typeAlias type="human.vo.Admin" alias="admin" />
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mappers/userMapper.xml" />
<mapper resource="mappers/adminMapper.xml" />
</mappers>
</configuration>
Two sqlSessionFactory <--- impossible??

Related

Entries missing in database when using Spring jdbcTemplate batch insert in a multithreaded environment

I am trying to add multiple records into an Oracle 12c database using a simple spring jdbcTemplate call to batchUpdate() method. The code that makes the batchUpdate() call is in my DAO class. However the code that calls the service method is multi-threaded.
This is what my DAO class looks like (there are more like this):
public void batchInsertSessionSignature(final List<SessionSignature> sessionSignatures, DataSource dataSource) {
Assert.notNull(sessionSignatures, "Checking to see if the SessionSignature objects passed in are null");
if (dataSource != null) {
jdbcTemplate.setDataSource(dataSource);
}
if (!sessionSignatures.isEmpty()) {
log.debug("Inserting batch entries into lev_session_signature_temp of size: " + sessionSignatures.size());
int[] res = jdbcTemplate.batchUpdate(insertSessionSig, new BatchPreparedStatementSetter() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
#Override
public void setValues(PreparedStatement pstmt, int i) throws SQLException {
SessionSignature ss = sessionSignatures.get(i);
String created_date = sdf.format(ss.getCreated_date());
pstmt.setLong(1, ss.getId());
pstmt.setString(2, ss.getHost());
pstmt.setString(3, ss.getSession_id());
pstmt.setString(4, ss.getIp_address());
pstmt.setString(5, ss.getAccountName());
try {
pstmt.setInt(6, sysInfoBean.getSysinfoID(ss.getSysinfo()));
pstmt.setDate(7, new Date(sdf.parse(created_date).getTime()));
} catch (ParseException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
pstmt.setString(8, ss.getCountry());
pstmt.setInt(9, ss.getAccountID());
pstmt.setString(10, ss.getBusinessUnit());
}
#Override
public int getBatchSize() {
return sessionSignatures.size();
}
});
log.debug(res.length + " entries inserted into lev_session_signature_temp");
}
}
This is the service layer method that makes the call to the DAO classes (the method is thread safe)
#Transactional(propagation= Propagation.REQUIRES_NEW, rollbackFor=Exception.class)
public synchronized void writeTargetDaoEntries(TargetDao targetDao, DataSource dataSource, ArrayList<SessionSignature> tgtSessionSignatures,
ArrayList<Session> tgtSession, ArrayList<SearchGroup> tgtSearchGroup, ArrayList<Search> tgtSearches,
ArrayList<LuceneEvent> tgtEvents, ArrayList<EventAnalysisDaoUtil> eventAnalysisList) throws Exception {
targetDao.batchInsertSessionSignatures(tgtSessionSignatures, dataSource);
targetDao.batchInsertUserSessions(tgtSession, dataSource);
targetDao.batchInsertSearchGroups(tgtSearchGroup, dataSource);
targetDao.batchInsertSearches(tgtSearches, dataSource);
targetDao.batchInsertEvents(tgtEvents, dataSource);
targetDao.batchInsertEventAnalysis(eventAnalysisList, dataSource);
}
My spring configuration looks like this
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:annotation-config/>
<context:property-placeholder location="app.properties"/>
<bean id="dataSourceQa" class="oracle.ucp.jdbc.PoolDataSourceFactory"
factory-method="getPoolDataSource" lazy-init="true">
<property name="connectionFactoryClassName"
value="oracle.jdbc.pool.OracleDataSource" />
<property name="user" value="${qaTargetId}" />
<property name="password" value="${qaTargetPswd}" />
<property name="URL" value="${qaTargetURL}" />
<property name="minPoolSize" value="2" />
<property name="maxPoolSize" value="10" />
</bean>
<bean id="dataSourceProd" class="oracle.ucp.jdbc.PoolDataSourceFactory"
factory-method="getPoolDataSource" lazy-init="true">
<property name="connectionFactoryClassName"
value="oracle.jdbc.pool.OracleDataSource" />
<property name="user" value="${prodSourceId}" />
<property name="password" value="${prodSourcePswd}" />
<property name="URL" value="${prodSourceURL}" />
<property name="minPoolSize" value="2" />
<property name="maxPoolSize" value="10" />
</bean>
<!-- JDBC Template Configuration -->
<bean id = "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate">
<property name = "dataSource" ref = "dataSourceQa"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceQa" />
</bean>
<bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="WaitForTasksToCompleteOnShutdown" value="true" />
</bean>
<!-- DAO Bean Configuration -->
<bean id = "eventDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.EventDao" />
<bean id = "searchDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.SearchDao" />
<bean id = "searchGroupDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.SearchGroupDao" />
<bean id = "userSessionDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.UserSessionDao" />
<bean id = "sessionSignatureDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.SessionSignatureDao" />
<bean id = "eventAnalysisDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.EventAnalysisDao" />
<bean id = "dailySummaryDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.DailySummaryDao" />
<bean id = "keyGeneratorBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.KeyGenerator" />
<bean id = "machineLearningDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.MachineLearningDao" />
<bean id = "sourceDaoBean" abstract = "true" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.SourceDao" />
<bean id = "desktopSourceDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.DesktopSourceDao" />
<bean id = "mobileSourceDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.MobileSourceDao" />
<bean id = "webSourceDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.WebSourceDao" />
<bean id = "tempTableDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.TempTableDao" />
<bean id = "targetDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.TargetDao">
<constructor-arg ref = "eventDaoBean" />
<constructor-arg ref = "searchDaoBean" />
<constructor-arg ref = "searchGroupDaoBean" />
<constructor-arg ref = "userSessionDaoBean" />
<constructor-arg ref = "sessionSignatureDaoBean" />
<constructor-arg ref = "eventAnalysisDaoBean" />
</bean>
<!-- Parser Bean Configuration -->
<bean id = "userSessionParserBean" class = "com.uptodate.lucene.tool.analysis.transfer.parser.UserSessionParser" scope = "prototype" />
<bean id = "searchParserBean" class = "com.uptodate.lucene.tool.analysis.transfer.parser.SearchParser" scope = "prototype" />
<bean id = "searchGroupParserBean" class = "com.uptodate.lucene.tool.analysis.transfer.parser.SearchGroupParser" scope = "prototype" />
<bean id = "eventParserBean" abstract = "true" class = "com.uptodate.lucene.tool.analysis.transfer.parser.EventParser" scope = "prototype" />
<bean id = "mobileEventParserBean" class = "com.uptodate.lucene.tool.analysis.transfer.parser.MobileEventParser" scope = "prototype" />
<bean id = "webEventParserBean" class = "com.uptodate.lucene.tool.analysis.transfer.parser.WebEventParser" scope = "prototype" />
<bean id = "logParserBean" class = "com.uptodate.lucene.tool.analysis.transfer.LogParser" scope = "prototype">
<constructor-arg ref = "keyGeneratorBean" />
<constructor-arg ref = "searchParserBean" />
<constructor-arg ref = "searchGroupParserBean" />
<constructor-arg ref = "userSessionParserBean" />
</bean>
<!-- Transfer Bean Configuration -->
<bean id = "dailySummaryGeneratorBean" class = "com.uptodate.lucene.tool.analysis.transfer.DailySummaryGenerator" />
<!-- Util Bean Configuration -->
<bean id = "sysInfoBean" class = "com.uptodate.lucene.tool.analysis.vo.SysInfo">
<property name = "dataSource" ref = "dataSourceProd" />
</bean>
I have tried adding support for transactions hoping that would help make sure the entries are committed to the database but that did not help. I can see in the code that all entries sent to the database were written to it but when I check the number of records in the database the same number is not reflected. I'm not sure if this is because of the multithreaded nature of the code that a batch of entires is overwritten somehow? Using 1 thread seems to work fine making me believe its a multithreading issue but I'm not sure where the problem is. Any help on this issue is appreciated.

Spring with two transaction managers and one within another

I have two transaction managers defined in my context file as follows
<tx:annotation-driven transaction-manager="firstTransactionManager" />
<bean id="secondDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="---" />
<property name="url" value="datasource1" />
<property name="username" value="----" />
<property name="password" value="----" />
</bean>
<bean id="firstTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="firstDataSource" />
<qualifier value="firstTxManager"/>
</bean>
<bean id="secondTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="secondDataSource" />
<qualifier value="secondTxManager"/>
</bean>
<bean id="firstDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="---" />
<property name="url" value="datasource2" />
<property name="username" value="---" />
<property name="password" value="---" />
</bean>
And I my class definitions are as follows
#Transactional("firstTransactionManager")
public class JdbcMain {
#Autowired
private static DataSource dataSource;
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public static void main(String args[]){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
TransactionExample example = (TransactionExample) ctx.getBean("transExample");
example.create();
}
}
And my example class is as follows:
#Transactional("secondTransactionManager")
public void create(DataSource dataSource2) {
try {
this.jdbcTemplate = new JdbcTemplate(dataSource2);
String sql = "insert into testtable values (?,?)";
getJdbcTemplate().update(sql,1,"1244343");
String marksSql="insert into testtable values (?,?)";
int i=2/0; //added to depict roll back behaviour of the transaction when exception occurs
getJdbcTemplate().update(marksSql,2,"sujay");
System.out.println("transaction committed");
} catch (RuntimeException e) {
throw e;
}
}
But the second transaction manager doesn't seem to work and the transaction is not rolled back (The first insert is executed). Can you provide me an idea.

Spring batch integration

I am looking for a guidance/solution with Spring batch integration. I have a directory to which external application will send xml files. My application should read the file content and move the file to another directory.
The application should be able to process the files in parallel.
Thanks in advance.
You can use Spring Integration ftp / sftp combined with Spring Batch:
1.Spring Integration Ftp Configuration :
<bean id="ftpClientFactory"
class="org.springframework.integration.ftp.session.DefaultFtpSessionFactory">
<property name="host" value="${host.name}" />
<property name="port" value="${host.port}" />
<property name="username" value="${host.username}" />
<property name="password" value="${host.password}" />
<property name="bufferSize" value="100000"/>
</bean>
<int:channel id="ftpChannel" />
<int-ftp:outbound-channel-adapter id="ftpOutbound"
channel="ftpChannel" remote-directory="/yourremotedirectory/" session-factory="ftpClientFactory" use-temporary-file-name="false" />
2.Create your reader and autowire a service to provide your items if needed :
#Scope("step")
public class MajorItemReader implements InitializingBean{
private List<YourItem> yourItems= null;
#Autowired
private MyService provider;
public YourItem read() {
if ((yourItems!= null) && (yourItems.size() != 0)) {
return yourItems.remove(0);
}
return null;
}
//Reading Items from Service
private void reloadItems() {
this.yourItems= new ArrayList<YourItem>();
// use the service to provide your Items
if (yourItems.isEmpty()) {
yourItems= null;
}
}
public MyService getProvider() {
return provider;
}
public void setProvider(MyService provider) {
this.provider = provider;
}
#Override
public void afterPropertiesSet() throws Exception {
reloadItems();
}
}
3. Create Your Own Item Processor
public class MyProcessor implements
ItemProcessor<YourItem, YourItem> {
#Override
public YourItem process(YourItem arg0) throws Exception {
// Apply any logic to your Item before transferring it to the writer
return arg0;
}
}
4. Create Your Own Writer :
public class MyWriter{
#Autowired
#Qualifier("ftpChannel")
private MessageChannel messageChannel;
public void write(YourItem pack) throws IOException {
//create your file and from your Item
File file = new File("the_created_file");
// Sending the file via Spring Integration Ftp Channel
Message<File> message = MessageBuilder.withPayload(file).build();
messageChannel.send(message);
}
5.Batch Configuration :
<bean id="dataSourcee"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="" />
<property name="url" value="" />
<property name="username" value="" />
<property name="password" value="" />
</bean>
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="dataSource" ref="dataSourcee" />
<property name="transactionManager" ref="transactionManagerrr" />
<property name="databaseType" value="" />
</bean>
<bean id="transactionManagerrr"
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
6.Another ApplicationContext file to Configure Your Job :
<context:annotation-config />
<bean id="provider" class="mypackage.MyService" />
<context:component-scan base-package="mypackage" />
<bean id="myReader" class="mypackage.MyReader"
<property name="provider" ref="provider" />
</bean>
<bean id="myWriter" class="mypackage.MyWriter" />
<bean id="myProcessor" class="mypackage.MyProcessor" />
<bean id="mReader"
class="org.springframework.batch.item.adapter.ItemReaderAdapter">
<property name="targetObject" ref="myReader" />
<property name="targetMethod" value="read" />
</bean>
<bean id="mProcessor"
class="org.springframework.batch.item.adapter.ItemProcessorAdapter">
<property name="targetObject" ref="myProcessor" />
<property name="targetMethod" value="process" />
</bean>
<bean id="mWriter"
class="org.springframework.batch.item.adapter.ItemWriterAdapter">
<property name="targetObject" ref="myWriter" />
<property name="targetMethod" value="write" />
</bean>
<batch:job id="myJob">
<batch:step id="step01">
<batch:tasklet>
<batch:chunk reader="mReader" writer="mWriter"
processor="mProcessor" commit-interval="1">
</batch:chunk>
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="myRunScheduler" class="mypackage.MyJobLauncher" />
<task:scheduled-tasks>
<task:scheduled ref="myJobLauncher" method="run"
cron="0 0/5 * * * ?" />
<!-- this will maker the job runs every 5 minutes -->
</task:scheduled-tasks>
7.Finally Configure A launcher to launch your job :
public class MyJobLauncher {
#Autowired
private JobLauncher jobLauncher;
#Autowired
#Qualifier("myJob")
private Job job;
public void run() {
try {
String dateParam = new Date().toString();
JobParameters param = new JobParametersBuilder().addString("date",
dateParam).toJobParameters();
JobExecution execution = jobLauncher.run(job, param);
execution.stop();
} catch (Exception e) {
e.printStackTrace();
}
}

Mybatis Spring multiple databases Java configuration

I'm working with Spring and Mybatis and I have two databases, the configuration for the first database was relative easy, but I can't get to work the second database with Spring and transactions, here is my code
#Configuration
#ComponentScan(basePackages = {"hernandez.service", "hernandez.dao"})
#EnableTransactionManagement
#MapperScan(basePackages="hernandez.mapper" )
#Import(DbConfig2.class)
public class AppConfig {
#Bean(name = "dataSource")
public DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource("com.mysql.jdbc.Driver",
"jdbc:mysql://localhost:3306/northwind", "root", "");
return ds;
}
#Bean
public SqlSessionFactoryBean sqlSessionFactory() {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource());
return factoryBean;
}
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
#Configuration
#MapperScan("loli.mapper" )
public class DbConfig2 {
#Bean(name = "dataSource_2")
public DataSource dataSource2() {
DriverManagerDataSource ds = new DriverManagerDataSource("com.mysql.jdbc.Driver",
"jdbc:mysql://localhost:3306/dmsolut_dmsms", "root", "");
return ds;
}
#Bean
public SqlSessionFactory sqlSessionFactory2() throws Exception{
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource2());
return factoryBean.getObject();
}
#Bean(name = "transactionManager_2")
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource2());
}
}
Is there a way to get this working with pure Spring Java configuration or at least with some XML? There's no official documentation to get two databases working in the Mybatis-Spring project
Multi datasources with mybatis are used in my project right now. This is an Example, add to your application.xml
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="${center.connectionURL}"/>
<property name="username" value="${userName}"/>
<property name="password" value="${password}"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xxx.dao.center"/>
<property name="sqlSessionFactoryBeanName" value="cneterSqlSessionFactory"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" name="cneterSqlSessionFactory">
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath*:mapperConfig/center/*.xml"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--center db end-->
<!--exdb-->
<bean id="dataSourceEx" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="${ex.connectionURL}"/>
<property name="username" value="${userName}"/>
<property name="password" value="${password}"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xxx.dao.ex"/>
<property name="sqlSessionFactoryBeanName" value="exSqlSessionFactory"/>
</bean>
<bean id="sqlSessionFactoryEx" class="org.mybatis.spring.SqlSessionFactoryBean" name="exSqlSessionFactory">
<property name="dataSource" ref="dataSourceEx"></property>
<property name="mapperLocations" value="classpath*:mapperConfig/ex/*.xml"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean id="transactionManagerEx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceEx"/>
</bean>
Add answer with java config example we use in our project:
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
#Configuration
#ComponentScan(basePackages = "com.mycompany")
#EnableTransactionManagement(proxyTargetClass = true)
public class ApplicationConfig2 {
public static final String DATA_SOURCE_NAME_1 = "jdbc/dataSource1";
public static final String DATA_SOURCE_NAME_2 = "jdbc/dataSource2";
public static final String SQL_SESSION_FACTORY_NAME_1 = "sqlSessionFactory1";
public static final String SQL_SESSION_FACTORY_NAME_2 = "sqlSessionFactory2";
public static final String MAPPERS_PACKAGE_NAME_1 = "com.mycompany.mappers.dao1";
public static final String MAPPERS_PACKAGE_NAME_2 = "com.mycompany.mappers.dao2";
#Bean
public DataSource dataSource1() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
return dsLookup.getDataSource(DATA_SOURCE_NAME_1);
}
#Bean
public DataSource dataSource2() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
return dsLookup.getDataSource(DATA_SOURCE_NAME_2);
}
#Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean(name = SQL_SESSION_FACTORY_NAME_1)
public SqlSessionFactory sqlSessionFactory1(DataSource dataSource1) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setTypeHandlersPackage(DateTimeTypeHandler.class.getPackage().getName());
sqlSessionFactoryBean.setDataSource(dataSource1);
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject();
sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
return sqlSessionFactory;
}
#Bean(name = SQL_SESSION_FACTORY_NAME_2)
public SqlSessionFactory sqlSessionFactory2(DataSource dataSource2) throws Exception {
SqlSessionFactoryBean diSqlSessionFactoryBean = new SqlSessionFactoryBean();
diSqlSessionFactoryBean.setTypeHandlersPackage(DateTimeTypeHandler.class.getPackage().getName());
diSqlSessionFactoryBean.setDataSource(dataSource2);
SqlSessionFactory sqlSessionFactory = diSqlSessionFactoryBean.getObject();
sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
return sqlSessionFactory;
}
#Bean
public MapperScannerConfigurer mapperScannerConfigurer1() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage(MAPPERS_PACKAGE_NAME_1);
configurer.setSqlSessionFactoryBeanName(SQL_SESSION_FACTORY_NAME_1);
return configurer;
}
#Bean
public MapperScannerConfigurer mapperScannerConfigurer2() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage(MAPPERS_PACKAGE_NAME_2);
configurer.setSqlSessionFactoryBeanName(SQL_SESSION_FACTORY_NAME_2);
return configurer;
}
}
In my experience, you should also add #Primary to one of the DataSource beans. Otherwise it will throw NoUniqueBeanDefinitionException.
#Bean
#Primary
public DataSource dataSource1() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
return dsLookup.getDataSource(DATA_SOURCE_NAME_1);
}
#Bean
public DataSource dataSource2() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
return dsLookup.getDataSource(DATA_SOURCE_NAME_2);
}
You can use spring's AbstractRoutingDataSource by extending it and overriding the method determineCurrentLookupKey().
Spring Configuration
You can define separate datasource in spring configuration.
<!-- db2 data source -->
<bean id="db2DataSource" class="com.ibm.db2.jdbc.app.DB2Driver">
<property name="serverName" value="${db2.jdbc.serverName}" />
<property name="portNumber" value="${db2.jdbc.portNumber}" />
<property name="user" value="${db2.jdbc.username}" />
<property name="password" value="${db2.jdbc.password}" />
<property name="databaseName" value="${db2.jdbc.databaseName}" />
</bean>
<!-- mysql data source -->
<bean id="mysqlDataSource" class="com.mysql.jdbc.Driver">
<property name="serverName" value="${mysql.jdbc.serverName}" />
<property name="portNumber" value="${mysql.jdbc.portNumber}" />
<property name="user" value="${mysql.jdbc.username}" />
<property name="password" value="${mysql.jdbc.password}" />
<property name="databaseName" value="${mysql.jdbc.databaseName}" />
</bean>
Associate the datasource with customer:
<bean id="customer" class="com.example.Customer">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="com.example.datasource.CustomerRoutingDataSource">
<property name="targetDataSources">
<map key-type="com.example.Customer">
<entry key="db2" value-ref="mysqlDataSource"/>
<entry key="mysql" value-ref="db2DataSource"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="mysql"/>
</bean>
Java
package com.example;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class CustomerRoutingDataSource extends AbstractRoutingDataSource {
#Bean
CustomerContextHolder context;
#Override
protected Object determineCurrentLookupKey() {
return context.getCustomerType();
}
}
Basically, each request will have its context. You can associate datasource with request using mapped key. You can find more details here dynamic-datasource-routing
<bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource1" />
<property name="configLocation">
<value>classpath:com/dtcc/dao/impl/DaoSqlMapConfig_MyBatis1.xml</value>
</property>
<property name="transactionFactory">
<bean class="org.apache.ibatis.transaction.managed.ManagedTransactionFactory" />
</property>
<property name="mapperLocations" value="classpath*:com/dtcc/dao/impl/DaoEmfMyBatis.sp.xml"/>
</bean>
<bean id="sqlSession1" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory1" />
</bean>
<!-- MyBatis Changes Ends -->
<bean id="daoEmf" class="com.dtcc.dao.DaoEmfImpl">
<property name="connectionType"><ref local="com.dtcc.sharedservices.utils.resources.ConnTypes.IBM_DB2_CONNECTION" /></property>
<property name="jndiNameForLogging"><ref local="dataSourceName1" /></property>
<property name="sqlSessionTemplate"> <ref local="sqlSession1" /></property>
<property name="applicationLog"><ref local="appLog" /></property>
</bean>
As mentioned above, we need to give corresponding sessionFactory in your DaoImpl. You can not autowire SqlSessionTemplate in your DaoImpl class if you have more than one sessionFactory. Give unique name for each session factory and map it to your respective DaoImpl class.
All you have to do is just to create object for SqlSessionTemplate with Setter method in DaoImpl class and you can make your db call using sqlSessionTemplate object as below,
this.sqlSessionTemplate.selectList("ProcedureID", parameter);

how to configure a mail server using spring mvc and jsp?

I would just like to ask how can i setup a simple mail server and be able to send an email. Im using apache tomcat 6.0 as my localhost server and spring framework+jsp as well. I'm quite new on this. So if someone can give a nice tutorial, it will be of great help. thanks
Below is how you would get the spring configuration. probably applicationContext-mail.xml. Import that into applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"autowire="byName">
default-autowire="byName">
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${mail.host}" />
<property name="port" value="${mail.port}" />
<property name="username" value="${mail.username}" />
<property name="password" value="${mail.password}" />
</bean>
<bean id="freemarkerConfiguration"
class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
<property name="templateLoaderPath" value="/WEB-INF/templates" />
</bean>
<!-- KINDLY MAINTAIN ALPHABETICAL ORDER THIS LINE ONWARDS -->
<bean id="notificationService" class="com.isavera.service.NotificationServiceImpl"
scope="prototype">
<property name="mailSender" ref="mailSender" />
<property name="freemarkerConfiguration" ref="freemarkerConfiguration" />
<property name="freemarkerTemplate" value="accountInformation.ftl" />
<property name="fromAddress" value="info#apnagenie.com" />
<property name="subject" value="Your account information" />
</bean>
Below is the NotificationServiceImpl
public class NotificationServiceImpl implements NotificationService, Runnable {
private boolean asynchronous = true;
private JavaMailSender mailSender;
private Configuration freemarkerConfiguration;
private String freemarkerTemplate;
private Map<String, Object> attributes;
private String deliveryAddress;
private String[] deliveryAddresses;
private String fromAddress;
private String subject;
private SimpleMailMessage message;
private MimeMessage mimeMessage;
public void deliver() {
message = new SimpleMailMessage();
if (getDeliveryAddresses() == null) {
message.setTo(getDeliveryAddress());
} else {
message.setTo(getDeliveryAddresses());
}
message.setSubject(subject);
message.setFrom(fromAddress);
// Merge the model into the template
final String result;
try {
result = FreeMarkerTemplateUtils.processTemplateIntoString(freemarkerConfiguration.getTemplate(appendApplicationName(freemarkerTemplate)), attributes);
message.setText(result);
if (asynchronous) {
Thread emailThread = new Thread(this);
emailThread.start();
} else {
run();
}
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
}
}
}

Categories