Use Single Instance of JdbcTemplate - spring

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?

Related

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 ;

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

Spring: Autowired or "Plain" Call by using the #Configuration annotations?

i have the following JAVA supported in Spring 4.0.3 configuration, that have two DataSource und JdbcTemplate beans:
#PropertySource("classpath:db.properties")
#Configuration
public class DBConfiguration {
.....
#Autowired
Environment env;
#Bean
public DataSource internalDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
// init dataSource setters for DATABASE_1
return dataSource;
}
#Bean
public DataSource publicDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
// init dataSource setters for DATABASE_2
return dataSource;
}
}
...
#Bean
public JdbcTemplate internalJDBCTemplate() {
return new JdbcTemplate(internalDataSource());
}
#Bean
public JdbcTemplate publicJDBCTemplate() {
return new JdbcTemplate(publicDataSource());
}
___
I have other configuration bean class, that autowires the first configuration and calls internalDataSource() method:
#Import(DBConfiguration.class)
#Configuration
public class AuthConfiguration {
#Autowired
private DBConfiguration dbConfiguration;
#Autowired
private TokenStore tokenStore;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dbConfiguration.securityDataSource());
}
...}
I suppose, that even DBConfiguration was imported and autowired into AuthConfiguration class, the each call of dbConfiguration.securityDataSource() will be cause the new DriverManagerDataSource() with each time intializing of data source.
Is it correkt or not?
The default bean scope in Spring is singleton so the data source will be initialized only once.
When a DI container creates bean TokenStore it gets a bean defined in DBConfiguration by the securityDataSource method. But it doesn't call the method directly, it takes a bean instance from the DI container. An initialization of all beans is done by Spring transparently to a developer.
Note that classes annotated with #Configuration are just a definition for the framework and they aren't executed directly.

Spring jdbc configuration

I have been trying to implement a web service using spring. This webservice will provide data access to a mySQL database using JDBC. I am trying to not use any xml configuration files, so I have come across a problem trying to connect to the database.
I am following the tutorial: http://spring.io/guides/tutorials/rest/ but I changed a few things along the way.
Now that I am trying to implement the connection with the database I get an error when trying to execute the tomcat instance, and I guess the problem is within the configurations.
Here follows some of my code:
Datasource configuration:
#Configuration
#Profile("mySQL")
#PropertySource("classpath:/services.properties")
public class MySQLDataSourceConfiguration implements DataSourceConfiguration{
#Inject
private Environment environment;
#Bean
public DataSource dataSource() throws Exception {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setPassword(environment.getProperty("dataSource.password"));
dataSource.setUrl(environment.getProperty("dataSource.url"));
dataSource.setUsername(environment.getProperty("dataSource.user"));
dataSource.setDriverClassName(environment.getPropertyAsClass("dataSource.driverClass", Driver.class).getName());
return dataSource;
}
}
the file service.properties is where I keep my configurations for the database, so when I desire to change the database I will just have to change 4 fields.
The JDBCConfiguration class for the setup of the JDBCtemplate
#Configuration
#EnableTransactionManagement
#PropertySource("classpath:/services.properties")
#Import( { MySQLDataSourceConfiguration.class })
public class JdbcConfiguration {
#Autowired
private DataSourceConfiguration dataSourceConfiguration;
#Inject
private Environment environment;
#Bean
public JdbcTemplate setupJdbcTemplate() throws Exception {
return new JdbcTemplate(dataSourceConfiguration.dataSource());
}
#Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) throws Exception {
return new DataSourceTransactionManager(dataSource);
}
}
Then there is the Repository, that recieves the template.
#Transactional
#Repository
#Qualifier("jdbcRepository")
public class JdbcIndividualRepository implements IndividualsRepository{
private static final Logger LOG = LoggerFactory.getLogger(JdbcIndividualRepository.class);
#Autowired
private JdbcTemplate jdbcTemplate;
#Autowired
public JdbcIndividualRepository(DataSource jdbcDataSource) {
LOG.info("JDBCRepo arg constructor");
this.jdbcTemplate = new JdbcTemplate(jdbcDataSource);
}
#Override
public Individual save(Individual save) {
String sql = "INSERT INTO Individual(idIndividual, Name) VALUES(?,?)";
this.jdbcTemplate.update(sql, save.getId(), save.getName());
return save;
}
#Override
public void delete(String key) {
String sql = "DELETE FROM Individual WHERE idIndividual=?";
jdbcTemplate.update(sql, key);
}
#Override
public Individual findById(String key) {
String sql = "SELECT i.* FROM Individual i WHERE i.idIndividual=?";
return this.jdbcTemplate.queryForObject(sql, new IndividualRowMapper(), key);
}
#Override
public List<Individual> findAll() {
String sql = "SELECT * FROM Individual";
return new LinkedList<Individual>(this.jdbcTemplate.query(sql, new IndividualRowMapper()));
}
}
Then I register the jdbc configuration in the initializer class when creating the root context of the application as follows:
private WebApplicationContext createRootContext(ServletContext servletContext) {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(CoreConfig.class, SecurityConfig.class, JdbcConfiguration.class);
rootContext.refresh();
servletContext.addListener(new ContextLoaderListener(rootContext));
servletContext.setInitParameter("defaultHtmlEscape", "true");
return rootContext;
}
However, the Tomcat server wont run because it can't autowire the class MySQLDataSourceConfiguration.
Anyone knows what the problem might be? I can give more details on the code, but the question is already really large.
Appreciate any kind of help!
Cheers
EDIT
Solved changing the JdbcConfiguration class to:
#Configuration
#EnableTransactionManagement
#PropertySource("classpath:/services.properties")
#Import( { MySQLDataSourceConfiguration.class })
public class JdbcConfiguration {
#Autowired
private DataSource dataSource;
#Inject
private Environment environment;
#Bean
public JdbcTemplate setupJdbcTemplate() throws Exception {
return new JdbcTemplate(dataSource);
}
#Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) throws Exception {
return new DataSourceTransactionManager(dataSource);
}
#Bean
public IndividualsRepository createRepo(){
return new JdbcIndividualRepository(dataSource);
}
}
Remove
#Autowired
private DataSourceConfiguration dataSourceConfiguration;
Because that's not how it's supposed to be used. Instead add to the same class the following:
#Autowired DataSource dataSource;
and use it like this: new JdbcTemplate(dataSource);
Also, try adding #ComponentScan to JdbcConfiguration class. From what I see in your code the class JdbcIndividualRepository is not picked up by anything.
In your class JdbcConfiguration, you are trying to autowire DataSourceConfiguration. I'm not really sure if that's possible - typically you should try to autwire the DataSource, not the DataSourceConfiguration.
#Import( { MySQLDataSourceConfiguration.class })
public class JdbcConfiguration {
#Autowired
private DataSource dataSource;
#Bean
public JdbcTemplate setupJdbcTemplate() throws Exception {
return new JdbcTemplate(dataSource);
}
Also if you have several DataSources and you're using Spring profiles to separate them, it's easier to provide all the DataSource beans in one file and annotate each bean with a different profile:
#Configuration
public class DataSourceConfig {
#Bean
#Profile("Test")
public DataSource devDataSource() {
.... configure data source
}
#Bean
#Profile("Prod")
public DataSource prodDataSource() {
... configure data source
}

Singleton vs prototype JdbcTemplate

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.

Resources