I am new to Spring MVC and JDBCTemplate and badly need some help on this. I've declared the following in applicationContext.xml:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://" />
<property name="username" value="user" />
<property name="password" value="pwd" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
In my DAOImpl class, I've the following code:
#Repository
public class ABCDAOImpl implements ABCDAO
{
private String INSERT_SQL = null;
private JdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource(DataSource dataSource)
{
this.jdbcTemplate = new JdbcTemplate( dataSource );
}
#Override
public boolean insertDataInDataBase(final Object obj)
{
boolean insertSuccessful = false;
INSERT_SQL = "INSERT INTO XXX " +
"(AA, BB, CC, DD, EE, " +
"FF, GG, HH, II) VALUES (?,?,?,?,?,?,?,?,?)";
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator()
{public PreparedStatement createPreparedStatement(Connection connection)
throws SQLException
{
PreparedStatement ps = null;
ps = connection.prepareStatement(INSERT_SQL);
ps.setString(1, xx);
ps.setString(2, xx);
ps.setString(3, xx);
ps.setString(4, xx);
ps.setString(5, xx);
ps.setString(6, xx;
ps.setString(7, xx);
ps.setString(8, xx);
ps.setString(9, xx);
return ps;
}}, keyHolder);
return insertSuccessful;
}
}
Test class:
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class ABCDAOImplTest
{
private Object object = new Object();
private ABCDAOImpl abcDAOImpl;
#Before
public void setup()
{
object.setAllVaribles();
abcDAOImpl = new ABCDAOImpl();
}
#Test
public void testRepositoryInsert()
{
System.out.println(abcDAOImpl.insertDataInDataBase(object));
assertTrue(abcDAOImpl.insertDataInDataBase(object));
}
}
Then I use jdbcTemplate to carry out an insert statement using PreparedStatementCreator.
Now, I am trying to test (without mocking, I am hardcoding the values just to test..) whether this code works or not? When I run this test, it gives me NPE saying jdbcTemplate is null. Is there something wrong with my code or is there something with the way I am testing it? Any help would be greatly appreciated.
Happy New Year :)
PS - I have annotated the Test class with #RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:applicationContext.xml"}) only after comment from #Pradeep. And now I get another exception: "Failed to load ApplicationContext."
The most obvious answer is that your test hasn't called the setDataSource() method or done anything else that would cause the JdbcTemplate to be created. You haven't shown enough code for someone to point out where the problem is, though.
Update: In your test, you say abcDAOImpl = new ABCDAOImpl();, and that's all. How do you expect the JdbcTemplate/DataSource to be injected? It won't happen by magic. Either you have to finish wiring it all up manually, or else let Spring inject the DAO into your test. To do that, just add a field like this:
#Autowired
private ABCDAO abcDao;
Maybe your missing Import of applicationContext.xml file in test-applicationContext.xml file
<import resource="classpath:applicationContext.xml" />
Related
I am trying to learn Spring MVC.I have a registration form which I am trying to persist. I have MySQL as backend.I have a test java application which is able to connect to MySQL and insert into table. But the same thing does not work for the web application. I am using Eclipse as IDE and Maven for build and tomcat as webserver.
Datasource file
<beans xmlns="http://www.springframework.org/schema/beans"
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-2.5.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/chorechart" />
<property name="username" value="username" />
<property name="password" value="password*" />
</bean>
DAO
package com.chorechart.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import javax.sql.DataSource;
import org.springframework.stereotype.Service;
import com.chorechart.dao.RegisterDAO;
import com.chorechart.model.Register;
#Service("registerDAO")
public class JdbcRegisterDAO implements RegisterDAO{
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
#Override
public void insertUser(Register registerUser) {
String sql = "Insert into register"+"
(FirstName,LastName,Email_username,password)"
+ "values(?,?,?,?)";
);
try {
System.out.println("DataSourrce"+dataSource);
Connection conn = dataSource.getConnection();
System.out.println("coonection"+conn);
PreparedStatement ps= conn.prepareStatement(sql);
ps.setString(1,registerUser.getFirstName());
ps.setString(2,registerUser.getLastName());
ps.setString(3, registerUser.getEmail_username());
ps.setString(4, registerUser.getPassword());
int x = ps.executeUpdate();
}catch(Exception ex) {
System.out.print("JDBCRegisterDao");
ex.printStackTrace();
}
}
}
#Override
public Register findUser(String userName, String userPwd) {
// TODO Auto-generated method stub
return null;
}
public DataSource getDataSource() {
return dataSource;
}
I have my own DAO which extends NamedJdbcDaoSupport. This DAO is created using the Spring framework.
I have written a small test application which accesses the DAO multiple times from the main thread without wait.
In this scenario everything works fine.
But if I access the DAO from different threads I receive the following NPE:
java.lang.NullPointerException
at org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.createPreparedStatement(PreparedStatementCreatorFactory.java:238)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:627)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:684)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:711)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:761)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:192)
at test.DAO.loadData(DAO.java:29)
at test.Application$1.run(Application.java:19)
at java.lang.Thread.run(Unknown Source)
In the description of the NamedJdbcDaoSupport is the following note:
"NOTE: An instance of this class is thread-safe once configured."
So why am I receiving this NPE? If I go into the Spring source I can see that the DBConnection seems to be null. But why? Normally Spring returns with a SQLException if it is not able to get a connection from the connection pool. So an NPE should never be possible.
Can someone help me understand why the NamedJdbcDaoSupport is not thread-safe despite the comments suggesting otherwise. And what I can do?
This is my Application:
public class Application {
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("ServerContext.xml");
DAO bean = (DAO)classPathXmlApplicationContext.getBean("dao");
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
#Override
public void run() {
for (int j = 0; j < 100; j++) {
bean.loadData();
}
}
}).start();
}
}
}
This is my gradle script:
repositories {
mavenCentral()
}
dependencies {
compile group: 'org.springframework', name: 'spring-context', version: '4.3.11.RELEASE'
compile 'org.springframework:spring-jdbc:4.3.11.RELEASE'
compile 'commons-dbcp:commons-dbcp:1.4'
compile files('lib/ojdbc6.zip')
}
This is my DAO:
public class DAO extends NamedParameterJdbcDaoSupport {
public List<String> loadData() {
Date fromDate = null;
Date toDate = null;
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("fromDate", fromDate);
namedParameters.addValue("toDate", toDate);
String sql = "SELECT * FROM myTable";
return getNamedParameterJdbcTemplate().query(sql, namedParameters, new RowMapper<String>() {
#Override
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
return null;
}
});
}
}
And this is my Spring context:
<!-- Database -->
<bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
<property name="URL" value="jdbc:oracle:thin:#localhost:1521:orcl"/>
<property name="user" value="user"/>
<property name="password" value="passwort"/>
<property name="connectionCachingEnabled" value="true" />
<property name="connectionCacheName" value="my_connection_pool" />
<property name="connectionCacheProperties">
<value>
MinLimit: 10
MaxLimit: 10
InitialLimit: 10
ValidateConnection: true
</value>
</property>
</bean>
<bean id="dao" class="test.DAO">
<property name="dataSource" ref="dataSource"/>
</bean>
So I implemented jdbc in my java programm. The "old-fashion" way works fluently and i get access to the database.
Now I wanted to refactor my code to Spring JDBC, because it offers more opportunities. But somehow my injection from beans.xml does not work. The dataSource is always null, therefore I can't execute any SQL Querys... because it is always null.
Beans.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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driverClassName}"></property>
<property name="url" value="${db.url}"></property>
</bean>
<bean id="userService" class="beco.webservice.service.impl.UserServiceImpl">
<property name="userDAO" ref="userDAO"></property>
</bean>
<bean id="userDAO" class="beco.webservice.dao.impl.UserDAOImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>database.properties</value>
</list>
</property>
</bean>
</beans>
database.properties
db.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
db.url=jdbc:sqlserver://XX-XXXXXX\\XXXXX;databaseName=BBSupportQA;integratedSecurity=true
UserDataAccessObject.java
import java.util.List;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import beco.webservice.dao.UserDAO;
import beco.webservice.model.User;
public class UserDAOImpl implements UserDAO {
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
#Override
public void createUser(User user) {
String SQL = "INSERT INTO dbo.BCO_Person(USER_ID, Email, Nickname) VALUES (?,?,?)";
int update = jdbcTemplate.update(SQL, user.getUserId(), user.getEmail(), user.getNickname());
if(update>0)
System.out.print("User is created...");
}
[...]
}
So I always get a Nullpointer and i debugged it and saw that DataSource / JDBCTemplate is always null.
If i use the old fashion way:
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
conn = DriverManager.getConnection("jdbc:sqlserver:sqlserver://XX-XXXXXX\\XXXXX;databaseName=BBSupportQA;integratedSecurity=true");
System.out.println(LOG_TAG + "Database successfully connected.");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
It works without any problems. What am I doing wrong? Is the url schema in the Spring properties different from the normal jdbc? I have no explanation for this.
I have implemented transactional rollback in the following way. This code worked well when I tried to implement the same on HSql DB and SQL Server. But the same transactional rollback is not working when implemented on MySQL DB. What could be the possible solution for rolling back the transaction in case of MySQL?
Here is my code -
xml file-> implement.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd ">
<!-- Initialization for data source -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://(mydb details)"/>
<property name="username" value="(my db username)"/>
<property name="password" value="(my db password)"/>
</bean>
<!-- Initialization for TransactionManager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Definition for studentJDBCTemplate bean -->
<bean id="implementOnlyTransactions" class="Transactions.implementOnlyTransactions">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
</bean>
</beans>
implementOnlyTransactions.java->
package Transactions;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
public class implementOnlyTransactions {
private DataSource dataSource;
private JdbcTemplate jdbcTemplateObject;
private PlatformTransactionManager transactionManager;
public void setDataSource(DataSource dataSource) throws SQLException {
this.dataSource = dataSource;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void create(Integer id, String name) throws Exception {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
String SQL1 = "insert into Student (ID,Name) values (?, ?)";
int r = jdbcTemplateObject.update(SQL1, id, name);
System.out.println("Inserted Name = " + name + ", ID = " + id);
if(r>0){
transactionManager.rollback(status);
}
transactionManager.commit(status);
} catch (DataAccessException e) {
System.out.println("Error in creating record, rolling back");
//transactionManager.rollback(status);
throw e;
}
}
}
MainClass.java -->
package Transactions;
import java.sql.SQLException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainClass {
public static void main(String[] args) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("xmlFiles/implement.xml");
implementOnlyTransactions implemt =
(implementOnlyTransactions)context.getBean("implementOnlyTransactions");
try {
implemt.create(36,"bye2");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I have trying to insert record into different table using spring jdbc template and transaction approach but not able to do that.
The code looks like this:
#Transactional
public void insertIntoTwoTables(){
final KeyHolder keyHolder = new GeneratedKeyHolder();
insertRole(keyHolder);
final String person = "insert into person (first_name, last_name, description, role_id) values ('?,?,?,?)";
keyHolder.getKey().longValue();
jdbcTemplate.update(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection con)
throws SQLException {
PreparedStatement ps = con.prepareStatement(person);
ps.setObject(1, "sahil");
ps.setObject(2, "Goyal");
ps.setObject(3, "This is again test");
ps.setObject(4, keyHolder.getKey().longValue());
return ps;
}
});
}
private KeyHolder insertRole(KeyHolder keyHolder){
final String role = "insert into role (name, code) values (?,?)";
jdbcTemplate.update(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection con)
throws SQLException {
PreparedStatement ps = con.prepareStatement(role, new String[]{"id"});
ps.setObject(1, "Manager");
ps.setObject(2, "MANAGER");
return ps;
}
}, keyHolder);
return keyHolder;
}
When I run this code it runs perfectly fine but does not insert anything into data base.
This problem happen when I run it using #Transactional annotation. If I delete then it works fine. So, I this task can be done in transactional environment.
Config file looks like this
<bean id="bDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="username" value="postgres" />
<property name="password" value="postgres" />
<property name="url" value="jdbc:postgresql://localhost:5432/test" />
<property name="defaultAutoCommit" value="true" />
</bean>
I test the code in both cases
but it does not inser anything into database.