I'm working my way through a Spring tutorial, and I'm having a problem in the JDBC section. The code was copied directly from the tutorial itself, and several calls to the database ran correctly before the one that failed. Can anyone help me? Here is my error trace.
Jul 31, 2012 9:40:03 PM org.springframework.jdbc.core.metadata.GenericCallMetaDataProvider processProcedureColumns
WARNING: Error while retrieving metadata for procedure columns: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: FUNCTION getrecord does not exist
Jul 31, 2012 9:40:03 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
Jul 31, 2012 9:40:03 PM org.springframework.jdbc.support.SQLErrorCodesFactory <init>
INFO: SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase] Exception in thread "main" org.springframework.jdbc.BadSqlGrammarException: CallableStatementCallback; bad SQL grammar [{call getrecord()}]; nested exception is com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: FUNCTION getrecord does not exist
at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:98)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:969)
at org.springframework.jdbc.core.JdbcTemplate.call(JdbcTemplate.java:1003)
at org.springframework.jdbc.core.simple.AbstractJdbcCall.executeCallInternal(AbstractJdbcCall.java:391)
at org.springframework.jdbc.core.simple.AbstractJdbcCall.doExecute(AbstractJdbcCall.java:354)
at org.springframework.jdbc.core.simple.SimpleJdbcCall.execute(SimpleJdbcCall.java:181)
at com.tutorialspoint.StudentJDBCTemplate.getStudent(StudentJDBCTemplate.java:32)
at com.tutorialspoint.MainApp.main(MainApp.java:29)
Caused by: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: FUNCTION getrecord does not exist
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:936)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2985)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1631)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1723)
at com.mysql.jdbc.Connection.execSQL(Connection.java:3277)
at com.mysql.jdbc.Connection.execSQL(Connection.java:3206)
at com.mysql.jdbc.Statement.executeQuery(Statement.java:1232)
at com.mysql.jdbc.DatabaseMetaData.getCallStmtParameterTypes(DatabaseMetaData.java:1607)
at com.mysql.jdbc.DatabaseMetaData.getProcedureColumns(DatabaseMetaData.java:4034)
at com.mysql.jdbc.CallableStatement.determineParameterTypes(CallableStatement.java:709)
at com.mysql.jdbc.CallableStatement.<init>(CallableStatement.java:513)
at com.mysql.jdbc.Connection.parseCallableStatement(Connection.java:4583)
at com.mysql.jdbc.Connection.prepareCall(Connection.java:4657)
at com.mysql.jdbc.Connection.prepareCall(Connection.java:4631)
at org.springframework.jdbc.core.CallableStatementCreatorFactory$CallableStatementCreatorImpl.createCallableStatement(CallableStatementCreatorFactory.java:167)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:947)
... 6 more
Here is the section of my main application where the problem occurs, and I've marked the line in question.
System.out.println("----Listing Record with ID = 2 -----");
// Error occurs in next line
Student student = studentJDBCTemplate.getStudent(2);
System.out.print("ID : " + student.getId());
System.out.print(", Name : " + student.getName());
System.out.println(", Age : " + student.getAge());
StudentJDBCTemplate has these two variables.
private DataSource dataSource;
private SimpleJdbcCall jdbcCall;
StudentJDCBTemplate sets the data source like this, and this may be the genesis of the problem, since I cannot figure out what getRecord refers to.
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcCall = new SimpleJdbcCall(dataSource)
.withProcedureName("getRecord");
}
The problem occurs in this method of StudentJDBCTemplate.
public Student getStudent(Integer id) {
SqlParameterSource in = new MapSqlParameterSource().addValue("in_id",
id);
Map<String, Object> out = jdbcCall.execute(in);
Student student = new Student();
student.setId(id);
student.setName((String) out.get("out_name"));
student.setAge((Integer) out.get("out_age"));
return student;
}
Here is my 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-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://localhost:3306/TEST" />
<property name="username" value="root" />
<property name="password" value="password" />
</bean> <!-- Definition for studentJDBCTemplate bean -->
<bean id="studentJDBCTemplate" class="com.tutorialspoint.StudentJDBCTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
For what it's worth, here is my Student class.
package com.tutorialspoint;
public class Student {
private Integer age;
private String name;
private Integer id;
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
}
Following your tutorial, you missed the creation of the getRecord stored procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS `TEST`.`getRecord` $$
CREATE PROCEDURE `TEST`.`getRecord` (
IN in_id INTEGER,
OUT out_name VARCHAR(20),
OUT out_age INTEGER)
BEGIN
SELECT name, age
INTO out_name, out_age
FROM Student where id = in_id;
END $$
DELIMITER ;
You are trying to execute Stored Procedure "getrecord". Which does not exist or not compiled properly in database. Try to execute first through SQL Client at database side.
Procedure should match with signature as 2 out parameter and one input parameter.
Caused by: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: FUNCTION getrecord does not exist.. So check it once.. Create getrecord function and try once..
Just in case that someone come across this in 2017, here is necessary change to that old tutorial if you are using MySQL Connector version 6.x instead of 5.x
In Beans.xml this line should be:
<property name="url" value="jdbc:mysql://localhost:3306/test?nullNamePatternMatchesAll=true" />
instead of:
<property name="url" value="jdbc:mysql://localhost:3306/test />
SQL error is quite misleading claiming that "out_name" parameter in not defined.
This is due to change in MySQL Connector from version 5.x to 6.x as commented here
Original SO answer is here:
Related
I was facing an issue of inserting data in database where STOCK_ID is identity and STOCK_NAME is string. While inserting the data in database it shows an exception which has mentioned below. Kindly guide me to rectify the issue.
Hibernate: insert into mkyongdb.system.STOCK (STOCK_NAME) values (?)
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not insert: [com.mkyong.user.Stock]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:92)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:64)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2345)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2852)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:320)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:129)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:713)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:701)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:697)
at com.mkyong.common.App.main(App.java:45)
Caused by: java.sql.SQLSyntaxErrorException: ORA-00926: missing VALUES keyword
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:440)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:837)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:445)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:191)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:523)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:207)
at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1010)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1315)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3576)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3657)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1350)
at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:57)
... 16 more
Stock.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.mkyong.user.Stock" table="STOCK" catalog="mkyongdb">
<id name="stockId" type="java.lang.Integer">
<column name="STOCK_ID" />
<generator class="identity" />
</id>
<property name="stockName" type="string">
<column name="STOCK_NAME" length="10" />
</property>
<!-- <one-to-one name="stockDetail" class="com.mkyong.user.StockDetail"
cascade="save-update"></one-to-one> -->
</class>
</hibernate-mapping>
hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:#127.0.0.1:1521/xe</property>
<property name="hibernate.connection.username">system</property>
<property name="hibernate.connection.password">admin</property>
<property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
<property name="show_sql">true</property>
<property name="hibernate.default_schema">system</property>
<property name="hibernate.hbm2ddl.auto">validate</property>
<mapping resource="com/mkyong/user/DBUser.hbm.xml"></mapping>
<mapping resource="com/mkyong/user/Stock.hbm.xml" />
<mapping resource="com/mkyong/user/StockDetails.hbm.xml" />
</session-factory>
</hibernate-configuration>
Stock.java
package com.mkyong.user;
public class Stock implements java.io.Serializable {
private Integer stockId;
private String stockName;
//private StockDetail stockDetail;
/*public StockDetail getStockDetail() {
return stockDetail;
}
public void setStockDetail(StockDetail stockDetail) {
this.stockDetail = stockDetail;
}*/
public Stock() {
//super();
// TODO Auto-generated constructor stub
}
public Stock(Integer stockId, String stockName) {
super();
this.stockId = stockId;
this.stockName = stockName;
}
public Integer getStockId() {
return stockId;
}
public void setStockId(Integer stockId) {
this.stockId = stockId;
}
public String getStockName() {
return stockName;
}
public void setStockName(String stockName) {
this.stockName = stockName;
}
}
Main.java
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Stock stock = new Stock();
stock.setStockName("sam");
session.save(stock);
session.getTransaction().commit();
Create Query:
CREATE TABLE STOCK
(
STOCK_ID numeric(10) not null,
STOCK_NAME varchar2(50) not null,
CONSTRAINT STOCK_PK PRIMARY KEY (STOCK_ID)
);
I think mkyongdb is your schema which has table named STOCK. So,
use mkyongdb.STOCK instead of mkyongdb.system.STOCK in the
insert statement.
STOCK_ID is a mandatory field and missing in the insert statement.
( By the way, If you use Oracle12c this field may not be included in the insert statement provided that defined as STOCK_ID numeric(10) GENERATED by default on null as IDENTITY in the create table DDL statement directly without need of any other mechanism like trigger. If you have version prior to 12c, a before insert trigger may be created which includes :new.STOCK_ID := seq_stock_id.nextval; statement, where seq_stock_id is a sequence )
I have AuthorJDBCDAO class with basic CRUD methods which extends AbstractJDBCDAO class and implements AuthorDAO interface.
I tested all methods via psv main() method and everything was fine.
But Now I have to test it's methods using DBUnit. And here my troubles start.
I try to test just only create() method and it isn't working properly.
I'm using Unitils, Spring DI, Oracle DB to create my application.
I inject bean DataSource(dbcp2) to beanAuthorJDBCDAO. I use XML configuration for injection beans.
Here's my source code and configuration files.
Test class.
#SpringApplicationContext({"spring-test-config.xml"})
#DataSet(value = "AuthorDAOTest.xml", loadStrategy = CleanInsertLoadStrategy.class)
public class AuthorDAOTest extends UnitilsJUnit4 {
#SpringBean("authorJDBCDAO")
private AuthorJDBCDAO authorDAO;
#Test
public void testCreate() throws DAOException {
Author expected = new Author();
expected.setName("BLABLABLA");
expected.setExpiredDate(Timestamp.valueOf(LocalDateTime.now()));
Author result = null;
result = authorDAO.create(expected);
assertEquals(expected.getId(), result.getId());
System.out.println("Hello from test");
}
Here's stacktrace from execution of Test class.
newsportal.exception.DAOException: java.sql.SQLException: Connection is null.
at newsportal.dao.impl.AbstractJDBCDAO.create(AbstractJDBCDAO.java:115)
at com.epam.ivanou.newsportal.dao.impl.AuthorJDBCDAOTest.testCreate(AuthorJDBCDAOTest.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:108)
at org.unitils.UnitilsJUnit4TestClassRunner$TestListenerInvokingMethodRoadie.runTestMethod(UnitilsJUnit4TestClassRunner.java:204)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
at org.unitils.UnitilsJUnit4TestClassRunner$TestListenerInvokingMethodRoadie.runBeforesThenTestThenAfters(UnitilsJUnit4TestClassRunner.java:186)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
at org.unitils.UnitilsJUnit4TestClassRunner.invokeTestMethod(UnitilsJUnit4TestClassRunner.java:95)
at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:59)
at org.unitils.UnitilsJUnit4TestClassRunner.access$000(UnitilsJUnit4TestClassRunner.java:42)
at org.unitils.UnitilsJUnit4TestClassRunner$1.run(UnitilsJUnit4TestClassRunner.java:60)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.unitils.UnitilsJUnit4TestClassRunner.run(UnitilsJUnit4TestClassRunner.java:67)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.sql.SQLException: Connection is null.
at org.apache.commons.dbcp2.DelegatingConnection.checkOpen(DelegatingConnection.java:608)
at org.apache.commons.dbcp2.DelegatingConnection.prepareStatement(DelegatingConnection.java:286)
at com.epam.ivanou.newsportal.dao.impl.AbstractJDBCDAO.create(AbstractJDBCDAO.java:106)
... 29 more
Fragment of code of AbstractJDBCDAO class. In which I get this exception. I tried to debug it and found, that in the second try-catch-with-resources block connection is null. But I can't understand, how does it occur if I try to get connection from DataSource which is BasicDataSource and support connection pooling.
#Override
public T create(T object) throws DAOException {
T persistInstance;
// Add the record
String sql = getCreateQuery();
String idName = getIdString();
String tableName = getTableName();
try (Connection connection = DataSourceUtils.getConnection(dataSource);
PreparedStatement statement = connection.prepareStatement(sql)) {
System.out.println("connection: "+ connection + " data source: " + dataSource);
prepareStatementForInsert(statement, object);
int count = statement.executeUpdate();
if (count != 1) {
throw new DAOException("On persist modify more then 1 record: " + count);
}
} catch (Exception e) {
throw new DAOException(e);
}
// Get recently inserted record
sql = getSelectQuery() + " WHERE " + idName + " = (SELECT MAX(" + idName + ") FROM "
+ tableName + ")";
try (Connection connection = DataSourceUtils.getConnection(dataSource);
PreparedStatement statement = connection.prepareStatement(sql)) //here is connection is null and SQLException is thrown {
System.out.println("connection: "+ connection + " data source: " + dataSource); //TODO connection is null in test method, but is good when using main() method
ResultSet rs = statement.executeQuery();
List<T> list = parseResultSet(rs);
if ((list == null) || (list.size() != 1)) {
throw new DAOException("Exception on findByPK new persist data.");
}
persistInstance = list.iterator().next();
} catch (Exception e) {
throw new DAOException(e);
}
return persistInstance;
}
here're configuration files for my beans:
dao-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-4.2.xsd">
<bean id="authorJDBCDAO" class="newsportal.dao.impl.AuthorJDBCDAO">
<constructor-arg ref="dataSource"/>
</bean>
database-test-config.xml
<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-4.2.xsd">
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>db_test.properties</value>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxIdle" value="${jdbc.maxIdle}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxWaitMillis" value="${jdbc.maxWaitMillis}"/>
<property name="initialSize" value="${jdbc.initialSize}"/>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
spring-test-config.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">
<import resource="database-test-config.xml" />
<import resource="dao-beans.xml" />
</beans>
db_test.properties
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:#localhost:1521:xe
jdbc.username=Yahor_test
jdbc.password=1234
jdbc.maxIdle=100
jdbc.minIdle=10
jdbc.maxWaitMillis=10000
jdbc.initialSize=10
And here's Simple java class for testing:
public class Test {
public static void main(String[] args) throws DAOException {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
AuthorJDBCDAO authorDAO = (AuthorJDBCDAO) ctx.getBean("authorJDBCDAO");
Author author = new Author();
author.setName("Yahor");
author = authorDAO.create(author);
System.out.println(author.getId());
}
And it's working fine =)
May be smth wrong with transactional configurations in my DBUnit Test class?
Problem is solved. I should close connection via DataSourceUtils.doReleaseConnection(). Otherwise connection will be closed physically. It was the keystone of my trouble.
Currently I am new to spring to trying to implement data-source with MySQL but I am facing a error but not able to understand what is main reason or error.
Exception in thread "main" java.lang.ExceptionInInitializerError
Apr 26, 2015 8:09:33 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext#4ee70b: startup date [Sun Apr 26 20:09:33 IST 2015]; root of context hierarchy
Exception in thread "main" java.lang.ExceptionInInitializerError
at org.springframework.context.support.AbstractRefreshableApplicationContext.createBeanFactory(AbstractRefreshableApplicationContext.java:194)
at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:127)
at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:465)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:395)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.rajdeo.jdbcspring.JdbcDemo.main(JdbcDemo.java:12)
Caused by: java.lang.NullPointerException
at org.springframework.beans.factory.support.DefaultListableBeanFactory.<clinit>(DefaultListableBeanFactory.java:104)
... 7 more
JdbcDemo.java
package com.x.jdbcspring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.x.jdbcspring.JdbcDaoImpl;
public class JdbcDemo {
public static void main(String[] args) {
ApplicationContext ctx= new ClassPathXmlApplicationContext("spring.xml");
JdbcDaoImpl dao=ctx.getBean("JdbcDaoImpl",JdbcDaoImpl.class);
/*
//JdbcDaoImpl dao=new JdbcDaoImpl();
Student student=ctx.getStudent(1);
System.out.println("name::\t"+student.getName());
JdbcDaoImpl jdbc=new JdbcDaoImpl();
jdbc.getStudent(1);
System.out.println(jdbc.getStudent(1).getId());*/
}
}
JdbcDaoImpl.java
package com.x.jdbcspring;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class JdbcDaoImpl {
#Autowired
private DataSource datasource;
public DataSource getDatasource() {
return datasource;
}
public void setDatasource(DataSource datasource) {
this.datasource = datasource;
}
public Student getStudent(int id){
Connection con = null;
Student student=null;
try{
/* Class.forName("com.mysql.jdbc.Driver");
System.out.println("Connecting to database...");*/
con = datasource.getConnection();
PreparedStatement stmt=con.prepareStatement("select * from contact where contact_id =?");
stmt.setInt(1, id);
//Excute the query
ResultSet rs=stmt.executeQuery();
while(rs.next()){
String name=rs.getString("name");
student=new Student(id, name);
}
//close the statement and Resultset
stmt.close();
rs.close();
return student;
}catch(Exception e){
e.printStackTrace();
}
finally{
if(con!=null)
try {
con.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return student;
}
}
Student.java
package com.rajdeo.jdbcspring;
public class Student {
private int id;
private String name;
public Student(int id, String name) {
// TODO Auto-generated constructor stub
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
spring.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:annotation-config />
<context:component-scan base-package="com.rajdeo" />
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/student" />
<property name="username" value="root" />
<property name="password" value="xxxx" />
</bean>
</beans>
What is error I am not able to understand it any help is appreciated.
Your spring.xml says to scan the package com.rajdeo for components, but your class JdbcDaoImpl is in package com.x.jdbcspring and so it will not be picked up, even though it has a #Component annotation.
Make sure to include the package that contains JdbcDaoImpl in the component scanning process:
<context:component-scan base-package="com.rajdeo, com.x.jdbcspring" />
Looks like you are getting a bean from the context
ctx.getBean("JdbcDaoImpl",JdbcDaoImpl.class)
but in the spring.xml this bean is not defined. As a result you get NPE = java.lang.NullPointerException.
To resolve this issue you have to configure JdbcDaoImpl service. E.g.
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/student" />
<property name="username" value="root" />
<property name="password" value="xxxx" />
</bean>
<bean id="JdbcDaoImpl"
class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="datasource" ref="datasource"/>
</bean>
in following code method doService1() update correct sql but doService2() sql has some issue , but when i call doService() it has to commit the doService1() update to DB even though the doService2() has a sql exception because doService2() has a REQUIRES_NEW Propagation type but when i nun this doService1() update does not commit DB..
#Service public class DbClass {
static Logger log = Logger.getLogger(
DbClass.class.getName());
#Autowired
private DataSource dataSource;
#Transactional(propagation=Propagation.REQUIRED)
public void doService(){
doService1();
doService2();
}
#Transactional(propagation=Propagation.REQUIRED)
public void doService1(){
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String sql = " update BATCHJOBSTATUS set PROCESSINGDATE = '20130322' " ;
int rowCount1 = jdbcTemplate.update(sql);
System.out.println(" rowCount1 >" + rowCount1);
}
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void doService2(){
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String sql = " update aa set a_name = 'hhh' where a_id = 4 and " ;
int rowCount1 = jdbcTemplate.update(sql);
System.out.println(" rowCount2 >" + rowCount1);
}
}
as your guys suggestion test in following way as well but still facing the same problem.
here i doService2() in a separate class but even though still have the same problem as above
#Service
public class DbClass {
static Logger log = Logger.getLogger(
DbClass.class.getName());
#Autowired
private DataSource dataSource;
#Autowired
private DbClass2 dbClass2;
#Transactional
public void doService(){
doService1();
dbClass2.doService2();
}
#Transactional(propagation=Propagation.REQUIRED )
public void doService1(){
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String sql = " update BATCHJOBSTATUS set PROCESSINGDATE = '20130322' " ;
int rowCount1 = jdbcTemplate.update(sql);
System.out.println(" rowCount1 >" + rowCount1);
}
}
#Service
public class DbClass2 {
#Autowired
private DataSource dataSource;
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void doService2() {
System.out.println("*******doService2*********`");
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String sql = " update aa set a_name = 'hhh' where a_id_ = 4 " ;
int rowCount2 = jdbcTemplate.update(sql);
System.out.println(" rowCount2 >" + rowCount2);
}
}
<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:oxm="http://www.springframework.org/schema/oxm"
xmlns:aop="http://www.springframework.org/schema/aop"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-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/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com.spring"/>
<tx:annotation-driven transaction-manager="txManager1" proxy-target-class="true"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#192.168.8.121:1521:h3" />
<property name="username" value="admin" />
<property name="password" value="admin" />
</bean>
<bean id="txManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="batchJob" class="com.spring.jdbc.BatchJob">
</bean>
</beans>
I had the same problem earlier and it was solved here : Strange behaviour with #Transactional(propagation=Propagation.REQUIRES_NEW)
Using default setting, there won't be any new transaction proxy created when you call doService2() from the same class, as a result your annotation is not user.
To avoid this issue you can put doService2() in another class or use aspectJ for transaction by declaring it like this : <tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>
Best solution will depend on your application. (The second one here seems more appropriate)
The call to doService2() probably doesn't have any transaction advice running on it because I'm assuming you're using a JDK dynamic proxy (interface proxy) instead of CGLIB based proxies. If you don't already know about how this works you might want to read: http://static.springsource.org/spring/docs/3.0.x/reference/aop.html#aop-proxying .
If you're not using CGLIB (target-class proxying), it will never go through the Spring Transaction advisor when you call doService2() since it is invoking the method directly instead of going through the wrapper Spring creates for your service at startup time.
You can get your example working by moving doService2() to a different service class then injecting it on to this service. That way you'll be going through the proxy and the transaction advice will run.
Otherwise, if you're ready to make a bigger change to your project, you could get your example to work as-is:
1) make sure CGLIB is in your classpath, and
2) turn on proxy-target-class , or force it to use CGLIB proxying so by getting rid of your service interface.
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
If you're going to do this, make sure you're read through the first link :).
According to spring documentation(Check section 10.5.6.1),the spring framework transaction will Rollback for only RunTimeException.
Not for other checked excpetions like SqlException.
So if you really want a rollback for this exception you have to specify it like below
#Transactional(propagation=Propagation.REQUIRES_NEW,rollbackFor=SQLException.class)
public void doService2(){
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String sql = " update aa set a_name = 'hhh' where a_id = 4 and " ;
int rowCount1 = jdbcTemplate.update(sql);
System.out.println(" rowCount2 >" + rowCount1);
}
Try this and let me know if it works.
Also this might help more.
I am a newbie to Hibernate and Spring and I am getting the above exception while executing the application.
I am trying to fetch the values of a record from the database.
Following is the exception that I am getting :-
message Request processing failed; nested exception is org.hibernate.HibernateException: /hibernate.cfg.xml not found
description The server encountered an internal error that prevented it from fulfilling this request.
exception
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.HibernateException: /hibernate.cfg.xml not found
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:894)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
root cause
org.hibernate.HibernateException: /hibernate.cfg.xml not found
org.hibernate.util.ConfigHelper.getResourceAsStream(ConfigHelper.java:170)
org.hibernate.cfg.Configuration.getConfigurationInputStream(Configuration.java:1497)
org.hibernate.cfg.Configuration.configure(Configuration.java:1519)
org.hibernate.cfg.Configuration.configure(Configuration.java:1506)
com.me.app.HomeController.handleRequestInternal(HomeController.java:56)
org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
note The full stack trace of the root cause is available in the Apache Tomcat/7.0.34 logs.
Following are my file :-
POJO
public class Usertable {
int id;
String userName;
String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Controller
//#Controller
public class HomeController extends AbstractController{
//private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
/**
* Simply selects the home view to render by returning its name.
*/
// #RequestMapping(value = "/", method = RequestMethod.GET)
// public String home(Locale locale, Model model) {
// logger.info("Welcome home! The client locale is {}.", locale);
//
// Date date = new Date();
// DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
//
// String formattedDate = dateFormat.format(date);
//
// model.addAttribute("serverTime", formattedDate );
//
// return "home";
// }
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String userName = request.getParameter("userName");
String password = request.getParameter("password");
Usertable user;
Configuration cfg = new Configuration();
SessionFactory sf = cfg.configure().buildSessionFactory();
Session hibsession = sf.openSession();
Transaction tx = hibsession.beginTransaction();
user = (Usertable)hibsession.get(Usertable.class, userName);
System.out.println("UserName is "+ user.getUserName());
System.out.println("Password is "+ user.getPassword());
tx.commit();
hibsession.close();
return new ModelAndView("first","abc","abc");
}
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">tiger</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/contacts</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<mapping resource="Usertable.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Usertable.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 20 Mar, 2013 4:26:30 AM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="com.me.app.Usertable" table="USERTABLE">
<id name="id" type="java.lang.Integer">
<column name="UserID" />
<generator class="native" />
</id>
<property name="userName" type="java.lang.String">
<column name="UserName" />
</property>
<property name="password" type="java.lang.String">
<column name="UserPassword" />
</property>
</class>
</hibernate-mapping>
servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
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">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<!-- <resources mapping="/resources/**" location="/resources/" /> -->
<beans:bean id="urlMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<beans:bean name="/books.htm" class="com.me.app.HomeController" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.me.app" />
</beans:beans>
Kindly help me with this issue.Thanks in advance.!
The thing is you shouldn't instantiate your hibernate configuration in your handle of a request but rather let spring instantiate your session factory and inject it into your controller and retrieve the session from there. Doing this, then you won't have to implement a session factory for each request made to your application.
You can check this question or the official documentation to have details on how to instantiate your session factory via spring.
This will (indirectly) solve your problem.
benzonico and KHY thanks for your inputs. The first mistake that I was doing was I placed the hibernate.cfg.xml inside src/main/java/com/me/app/ which should have been src/main/java/. This worked for me. The next part about TypedMismatch was
user = (Usertable)hibsession.get(Usertable.class, userName);
I was trying to get the String reference from the database which was actually Integer. So that solved the typedMismatchException.
I will definitely try injecting the session factory into my code through spring. Since I am new to this frameworks I learnt a loads while discussing with you and trying the new codes.
Thanks again for your valuable feedback.