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 ;
Related
I have defined the following configuration in my application
#Bean
#Primary
#ConfigurationProperties(prefix="database1")
public DataSource rameshDS()
{
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "rameshEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean rameshEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(rameshDS())
.packages("com.nandagiri.entities")
.build();
}
#Primary
#Bean(name = "rameshTransactionManager")
public PlatformTransactionManager rameshTransactionManager(
final #Qualifier("rameshEntityManagerFactory") LocalContainerEntityManagerFactoryBean rameshEntityManagerFactory) {
return new JpaTransactionManager(rameshEntityManagerFactory.getObject());
}
If I try to insert data into one of the tables in the following way, the data is not persisted. But if I uncomment the lines to explicitly begin/commit transactions then it is working fine. But, I wanted to use declarative way of transactions. How to achieve that?
#Autowired
#Qualifier("rameshEntityManagerFactory")
EntityManagerFactory rameshEntity;
#Override
#Transactional(value = "rameshTransactionManager")
public void storeInfo(Ramesh ramesh)
{
EntityManager em = rameshEntity.createEntityManager();
//em.getTransaction().begin();
em.persist(ramesh);
//em.getTransaction().commit();
}
If I persist the entities with repository interface it is working absolutely fine without any issues. please find the code below.
#Repository
public interface RameshRepository extends JpaRepository<Ramesh, String>
{
}
#Transactional(transactionManager = "rameshTransactionManager", propagation = Propagation.REQUIRED)
public void saveRameshs()
{
saveRamesh1();
saveRamesh2();
}
#Transactional
public void saveRamesh1()
{
Ramesh ramesh = new Ramesh();
ramesh.setId("8");
ramesh.setFname("jagadeesh");
ramesh.setLname("K");
repository.save(ramesh);
}
#Transactional
public void saveRamesh2()
{
Ramesh ramesh = new Ramesh();
ramesh.setId("9");
ramesh.setFname("jagadeesh123");
ramesh.setLname("k123");
repository.save(ramesh);
//int x = 5/0;
}
I have made two test methods. One uses JdbcTemplate to make the query while other uses NamedParameterJDBCTemplate.
Using NamedParameterJdbcTemplate:
#Autowired
JdbcTemplate jdbcTemplate;
public Student findById(long id) {
NamedParameterJdbcTemplate apptemplate = new NamedParameterJdbcTemplate(jdbcTemplate.getDataSource());
return apptemplate.queryForObject("select * from student where id="+id, Collections.emptyMap(),
new BeanPropertyRowMapper< Student >(Student.class));
}
Using JdbcTemplate
#Autowired
JdbcTemplate jdbcTemplate;
public Student findById(long id) {
return jdbcTemplate.queryForObject("select * from student where id=?", new Object[] {
id
},
new BeanPropertyRowMapper< Student >(Student.class));
}
I am using below pointcut to intercept:
For JdbcTemplate:
#Pointcut("execution(* org.springframework.jdbc.core.JdbcOperations+.*(..))")
public void forJdbcTemplate() {
}
For NamedParameterJdbcTemplate:
#Pointcut("execution(* org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations+.*(..))")
public void forNamedParameterJdbcTemplate() {
}
Why does my pointcut for JdbcTemplate work but pointcut for NamedParameterJdbcTemplate does not work?
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
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
}
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.