Singleton vs prototype JdbcTemplate - spring

In the Spring documentation the recommended way to use JdbcTemplate is to create new template for every class you use it in...
public class JdbcCorporateEventDao implements CorporateEventDao {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
}
I was wondering, what is the advantage of this solution over define the jdbctemplate as singleton in the context and directly inject it in the Dao
public class JdbcCorporateEventDao implements CorporateEventDao {
#Autowired
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}

From the class-level documentation of JdbcTemplate:
* Can be used within a service implementation via direct instantiation
* with a DataSource reference, or get prepared in an application context
* and given to services as bean reference.
Either is ok. Here I have a large application (50 DAOs, 100 concurrent users) and there is one jdbcTemplate object for the entire application, defined in the spring context. This works fine.

One drawback of injecting the JdbcTemplate directly is if you need to/decide to use a SQLExceptionTranslator.
If your JdbcTemplate is a singleton, setting a SQLExceptionTranslator in any class affects all classes using that template.
For example...
public class JbdcUserDAO implements UserDAO{
#Autowired
private JdbcTemplate jdbcTemplate;
public JbdcUserDAO() {
this.jdbcTemplate.setExceptionTranslator(new UserSQLExceptionTranslator());
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
AND
public class JdbcCompanyDAO implements CompanyDAO{
#Autowired
private JdbcTemplate jdbcTemplate;
public JdbcCompanyDAO() {
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
SQLExceptions raised through JdbcCompanyDAO will also be run through UserSQLExceptionTranslator even though it looks like no translator is registered.

Related

Not able to mock jdbcTemplate(datasource) in springboot test class using testNG

I am getting a null pointer exception on jdbcTemplate object in this MyMain.java class while mocking the jdbcTemplate.update() method. I have used #Mock for this in the MyMainTest.java class. Here are my code snippets:
MyMain.java
#Component
public class MyMain {
private JdbcTemplate jdbcTemplate;
#Autowired
#Qualifier("myDatasource")
Datasource myDatasource;
#PostConstruct
public void initialize() {
jdbcTemplate = new JdbcTemplate(myDatasource);
}
public void saveData() {
jdbcTemplate.update("query", "parameter passing here"); // In this line only I am getting Nullpointer exception on jdbcTemplate.
}
}
MyMainTest.java
public class MyMainTest {
#Mock
JdbcTemplate jdbcTemplate;
#Test
public void saveDataTest() {
when(jdbcTemplate.update(Mockito.any(), Mockito.any()).thenReturn(1);
new MyMain().saveData();
}
}
I have tried several alternative ways and I am still getting this issue.
Note: I am using TestNG for running the test classes. It's a Spring Boot project.

Can we insert data into tables without entity in spring boot?

I have a large amount of data, so can I insert it into the database without creating an Entity class?
you can use JdbcTemplate to insert, update, delete and more.
Using Java Config it would be:
#Configuration
public class DBConfig {
#Bean
public DataSource dataSource() {
//create a data source
}
#Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
#Bean
public TransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
you should create a repository that uses JdbcTemplate could be:
#Repository
public class JdbcSomeRepository implements SomeRepository {
private final JdbcTemplate jdbcTemplate ;
#Autowired
public JdbcSomeRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
#Override
#Transactional
public int someUpdate(SomeType someValue, SomeOtherType someOtherValue) {
return jdbcTemplate.update("INSERT INTO SomeTable(column1, column2) VALUES(?,?)", someValue, someOtherValue)
}
}
you can also directly Autowired in the controller.
#Autowired
JdbcTemplate jdbcTemplate ;

Use Single Instance of JdbcTemplate

I have OracleConfiguration class where i have the DataSource and Jdbctemplate defined .Below is the code snippet
#Configuration
//#ConfigurationProperties("oracle")
#PropertySource("classpath:dev.properties")
public class OracleConfiguration {
//omitted variable names,getters n setter for brevity
DataSource dataSource() throws SQLException {
OracleDataSource dataSource = new OracleDataSource();
dataSource.setDriverType(driverType);
dataSource.setUser(username);
dataSource.setPassword(password);
dataSource.setURL(url);
dataSource.setImplicitCachingEnabled(true);
dataSource.setFastConnectionFailoverEnabled(true);
return dataSource;
}
#Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.setResultsMapCaseInsensitive(true);
return jdbcTemplate;
}
Now to connect to database in every repository i create one instance of
JdbcTemplate and annotate it with Autowire which works fine .
#Component
public class RolesDaoImpl implements RolesDao {
#Autowired
private JdbcTemplate jdbcTemplate;
// works fine able to perform jdbc operations
But i read there should be only one instance of JdbcTemplate per Database schema .So how can i make this JdbcTemplate code generic.I tried the below but i am not able to connect to Db using the below technique
public class JdcTemplateDaoImpl {
private JdbcTemplate jdbcTemplate; //SETTER NOT REQUIRED
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setDataSource ( DataSource dataSource )
{
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
And my every other DaoImpl can extend this JdcTemplateDaoImpl .How can i achieve it?
From the posted configurations, it looks like the JdbcTemplate is a singleton bean (scope singleton is a default scope in spring).
So, there is one instance of JdbcTemplate type in the application context and it gets injected into repositories.
Place a breakpoint in different repositories and the chances are that you'll see that the instance is the same (the same address in memory).
So the technique presented in the last code snippet is not required
Why do you think that it's not the same instance?

how to inject multiple JdbcOperations into Spring Test Case

Here is my Code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/load-BMS-data-job-launcher-context.xml" })
public class SimpleJobLaunchFunctionalTests {
#Autowired
private JobLauncherTestUtils jobLauncherUtils;
#Autowired
private JdbcOperations jdbcTemplate;
#Autowired
private JdbcOperations jdbcTemplateBMS;
#Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
#Autowired
public void setDataSource(DataSource BMSdataSource) {
this.jdbcTemplateBMS = new JdbcTemplate(BMSdataSource);
}
#Before
public void setUp() {
jdbcTemplate.update("DELETE from SHADOW_BMS");
// jdbcTemplate.update("DELETE from CMNREF.CNTRCT_EXTRNL_KEY_REF_V");
jdbcTemplateBMS.update("DELETE from CNTRCT_EXTRNL_KEY_REF_V");
I want to wire two separate JdbcTemplates to operate on two distinct databases inside this test class. I fail to know how to set different dataSources - I get an exception when I try to invoke the second setDataSource(DataSource BMSdataSource) method.
How do I do that?
You can create beans with name="template1" and name="template2" (with annotations #Bean(name = "template1") ). In the test you use them as follows:
#Qualifier("template1")
#Autowired
private JdbcOperations jdbcTemplate1;
#Qualifier("template2")
#Autowired
private JdbcOperations jdbcTemplate2;

How to use Multiple JdbcOperations and Multiple JdbcTemplates in Spring

I have 2 different datasrouces from which I want to use in the same file and query each of them using JdbcOperations implementation. Is this possible?
#Repository
public class TestRepository {
private JdbcOperations jdbcOperations;
#Inject
#Qualifier("dataSource1")
private DataSource dataSource1;
#Inject
#Qualifier("dataSource2")
private DataSource dataSource2;
#Bean
#Qualifier("jdbcTemplate1")
public JdbcTemplate jdbcTemplate1(#Qualifier("dataSource1") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
#Bean
#Qualifier("jdbcTemplate2")
public JdbcTemplate jdbcTemplate1(#Qualifier("dataSource2") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
#Inject
public TestRepository(JdbcOperations jdbcOperations) {
this.jdbcOperations = jdbcOperations; //HOW DO I SPECIFY WHICH JDBCTEMPLATE SHOULD BE USED FOR INITIALIZING THIS JDBCOPERATIONS
}
}
Above is my code, note that JdbcOperations is initialized in the constructor. But no way to specify which jdbcTemplate should the jdbcOperations use.
The qualifier should actually be put at the parameter level:
public TestRepository(#Qualifier("jdbcTemplate2")JdbcOperations jdbcOperations) {
this.jdbcOperations = jdbcOperations;
}
Uses the bean named jdbcTemplate2

Resources