Connecting to a MySQL database from a Spring project - mysql

I have been trying to access MySQL routines from my Spring project using SimpleJdbcDaoSupport.
I have a class called AdminSimpleMessageManager, which implements the interface AdminMessageManager.
AdminSimpleMessageManager has an instance of the class AdminSimpleJdbcMessageDao, which implements the interface AdminMessageDao.
AdminSimpleJdbcMessageDao has the following method:
public class AdminSimpleJdbcMessageDao extends SimpleJdbcDaoSupport implements AdminMessageDao {
public int addMessage(String from, String message) {
return getJdbcTemplate().queryForInt("call insert_contact_message(?, ?)", from, message);
}
}
I have included the following in my application context:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/OctagonDB"/>
</bean>
<bean id="adminMessageManager" class="Managers.AdminSimpleMessageManager">
<property name="adminMessageDao" ref="adminMessageDao"/>
</bean>
<bean id="adminMessageDao" class="Managers.dao.AdminSimpleJdbcMessageDao">
<property name="dataSource" ref="dataSource"/>
</bean>
but I feel there are a few important lines missing. I get the error
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/NewWebsite] threw exception [Request processing failed; nested exception is org.springframework.dao.TransientDataAccessResourceException: PreparedStatementCallback; SQL [call insert_contact_message(?, ?)]; ResultSet is from UPDATE. No Data.; nested exception is java.sql.SQLException: ResultSet is from UPDATE. No Data.] with root cause
java.sql.SQLException: ResultSet is from UPDATE. No Data.
I am wondering if the SQL routine needs to return some confirmation? Or maybe I am accessing the DB with the wrong information, is there a way of determining whether it even connected?
EDIT:
insert_contact_message looks like this:
CREATE DEFINER=`root`#`localhost` PROCEDURE `insert_contact_message`(
_author VARCHAR(45),
_message MEDIUMTEXT
)
BEGIN
INSERT INTO contact_messages (`author`, `message`, `date_sent`) VALUES (_author, _message, NOW());
END

You're using queryForInt, but insert_contact_message doesn't return a result. I haven't used JdbcTemplate before, but it looks like you might want to use execute that doesn't expect a result set.
Another option is to change from using a procedure to a function.
CREATE DEFINER=`root`#`localhost` FUNCTION `insert_contact_message`(
_author VARCHAR(45),
_message MEDIUMTEXT
)
BEGIN
INSERT INTO contact_messages (`author`, `message`, `date_sent`) VALUES (_author, _message, NOW());
RETURN 1;
END

Related

Spring Boot Microservice Jackson JSON serialisation NON NULL

I'm currently working on a Spring Boot ( Version 1.3.1 ) Microservice which connects to MongoDB backend and provides the backend data ( Ex: Provider object ) to the client via controller.
The project has got one class file which extends ResourceSupport ( Ex: ProviderResourceSupport ) and also another class which extends ResourceSupportAssembler class ( Ex: ProviderAssembler ) for generating Links to the Response objects.
Ideally my requirement is to customise the JSON objects on a need basis and as such using #JsonView ( followed this link - https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring ) and added Spring Jackson dependencies in the maven project.
I have also added spring.jackson.serialization-inclusion=non-null & spring.jackson.serialization.indent_output=true in the application.properties.
For one of the method in the controller, the response will be 'ResponseEntity< List< ProviderResourceSupport>>' , and this method is returning with a 'null' response if the data is not present.
I have added #JsonInclude(Include=NON_NULL) on my entity objects and controllers but still getting the 'null' response.
I don't want the 'null' as the response and request you to help me incase if anyone has faced the similar issue.
I fixed this null properties escaping from json response extending a Jackson Mapper Bean but I don't use Spring Boot, take a quickly look and check if this is suitable for you
public class Jackson2ObjectMapperCustom extends Jackson2ObjectMapperFactoryBean {
#Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
getObject().setSerializationInclusion(JsonInclude.Include.NON_NULL).setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
Hibernate5Module hibernateModule = new Hibernate5Module();
hibernateModule.disable(Feature.USE_TRANSIENT_ANNOTATION);
hibernateModule.enable(Feature.FORCE_LAZY_LOADING);
getObject().registerModules(new JavaTimeModule(), hibernateModule);
getObject().configure(SerializationFeature.INDENT_OUTPUT, true);
getObject().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
getObject().setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"));
}
}
And in my case I use Spring Xml configuration
<bean id="objectMapper" class="com.xxx.common.Jackson2ObjectMapperCustom" />
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>

Converting MySQL to H2

I’m working on a project following this code :
Link to download of code: https://bitbucket.org/vrto/spring-tutorial/get/a66534cc7033.zip
Now what I really want, instead of MySQL, is to have an embedded database running HSQL or H2. So I’ve working on my own project trying to implement such a system.
In the tutorial code, he creates a database. And then h2 + hibernates creates the future tables for him – so it would be create if I could do this without having to have an sql schema or anything to set it up.
So I’ve gotten rid of mySql maven dependencies and am working on replacing the persistence-beans.xml
Now I have to replace my dataSource with a relevant h2 or hsql version.
So this is what I’ve gotten.
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name ="driverClassName" value = "org.h2.driver"/>
<property name = "url" value ="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1" />
<property name = "username" value = "sa" />
<property name = "password" value = "" />
</bean>
// I also tried this (but again, having a schema with his code is tricky I’ve found
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:schema.sql"/>
<jdbc:script location="classpath:test-data.sql"/>
</jdbc:embedded-database>
But it fails upon running HibernateConfigurationTest.Java (and in extension – all the others)
Any help would be greatly appreciated.
I've managed to get this test work with my schema
#ContextConfiguration(locations = "/persistence-beans.xml")
public class HibernateConfigurationTest extends AbstractJUnit4SpringContextTests {
#Autowired
private SessionFactory sessionFactory;
#Test
public void testHibernateConfiguration() {
// Spring IOC container instantiated and prepared sessionFactory
assertNotNull (sessionFactory);
}
}
the rest tests are in this link : http://vrtoonjava.wordpress.com/2012/06/17/part-3-dao-and-service-layer/

Session is closed Exception

I am building an application with Struts 2 hibernate spring 3 with my sql as back end and c3p0 connection pooling(c3p0-0.9.1.1 jar).
Sometimes, when executing a query, I get the below error. When ever I am executing query I check if the connection is closed or not, and if it's closed I will open a new connection before executing the query.
public List<T> find(final Query query, final Object[] values) throws HibernateException, NullPointerException {
if (values != null) {
for (int i = 0; i < values.length; i++) {
query.setParameter(i, values[i]);
}
}
List<T> resultList = null;
if (hibernateSession == null || !hibernateSession.isOpen()) {
try {
openHibernateSession();
resultList = query.list();
} catch (Exception e) {
e.printStackTrace();
} finally {
closeHibernateSession();
}
} else {
resultList = query.list();
}
return resultList;
}
public List<T> find(final String queryString, final Object[] values) throws HibernateException {
if (hibernateSession == null || !hibernateSession.isOpen()) {
openHibernateSession();
}
Query queryObject = hibernateSession.createQuery(queryString);
return find(queryObject, values);
}
private void openHibernateSession() throws HibernateException {
try {
hibernateSession = HibernateUtil.getSessionFactory().openSession();
hibernateSession.setFlushMode(FlushMode.MANUAL);
hibernateTransaction = hibernateSession.getTransaction();
hibernateTransaction.begin();
} catch (Exception e) {
e.printStackTrace();
}
}
private void closeHibernateSession() {
try {
if (hibernateTransaction != null) {
hibernateSession.flush();
if (!hibernateTransaction.wasCommitted()) {
hibernateTransaction.commit();
}
}
if (hibernateSession != null) {
if (hibernateSession.isOpen()) {
hibernateSession.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/projectdb</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">1800</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">50</property>
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.c3p0.usesTraditionalReflectiveProxies">true</property>
<property name="connection.pool_size">20</property>
<property name="current_session_context_class">thread</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="hibernate.connection.isolation">4</property>
you can probably fix your most immediate problem pretty easily. have your closeHibernateSession() reliably set hibernateSession to null. that will force your query functions to create new Sessions rather than try to reuse an old, closed session.
but don't just do this. you have much bigger problems.
you need to be much cleaner in how you organize your hibernate sessions. from the code above, it's clear that you have a member variable called hibernateSession that may be shared by across multiple callers or by multiple queries, that is sometimes null and sometimes not, which various functions lazily initialize but may not close until some time down the line. that's no good at all.
in the simplest arrangement, don't hold the session as a member variable. hold it as a local variable. let openHibernateSession() return a session that will be closed with perfect certainty in a finally block. if for some reason you need sessions to outlive what can be encapsulated by a single function call (which might of course call many other functions, each of which might take the session as a parameter), you will have to be very, very careful. sessions that are open must reliably be close()ed, and you must understand their lifecycles. your current approach, which uses a session if one is already open, but creates a temporary session otherwise, is no good. if you insist on maintaining a Session member variable, you must know with perfect certainty, whenever the member variable will be initialized, exactly how and when it will be close()ed and then reset to null or dereferenced for garbage collection.
you also should understand your transactions, none of this "if i have an uncommitted transaction before close(), commit it."
also, please consider migrating to c3p0-0.9.2.1
When you are trying to save or update a transient instance make sure the entities associated with instance are persistent. This is a common error of users trying to persist a new instance of the entity with the detached references. Get the entity from the persistence context before you set its reference to the transient or detached instance that you are going to persist.

Binary File To SQL Database Apache Camel

I need some guidance around which approach to use to load binary files from a folder into a MySQL Database using Camel. Basically I want to store voice logs from our PBX system into a database. The directory with the voice logs will be a remote directory
I have designed a prototype but I am not sure if this is really efficient, it works but I am not happy with the design. Let me explain what I am doing. Camel route as follows:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<package>com.hia.camelone</package>
<route>
<from uri="file://c:/CTest/Inbox?noop=true&recursive=true&delay=3000"/>
<to uri="bean://fileToSQL"/>
<to uri="jdbc://timlogdb"/>
</route>
</camelContext>
<bean id="timlogdb" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value=" com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/TimLog" />
<property name="username" value="root" />
<property name="password" value="blahblah" />
</bean>
<bean id="fileToSQL" class="com.hia.camelone.fileToSQL"/>
And the code to fileToSQL bean is:
public class fileToSQL {
public String toString(#Headers Map<String,Object> header, #Body Object body){
StringBuilder sb = new StringBuilder();
String filename =(String)header.get("CamelFileNameOnly");
String escapedFileName = StringEscapeUtils.escapeJava(filename).replace("\'", "");
String filePath = StringEscapeUtils.escapeJava((String)header.get("CamelFilePath"));
sb.append("insert into FileLog ");
sb.append("(FileName,FileData) values (");
sb.append("'").append(escapedFileName).append("',").append("LOAD_FILE(\"").append(filePath).append("\")");
sb.append(")");
System.out.println(sb.toString());
System.out.println(body);
System.out.println(header.toString());
return sb.toString();
}
}
Ok short explanation I get the file component to consume the files then I build a SQL string using the MySQL LOAD_FILE() function to load the file.
My thoughts around this:
The LOAD_FILE function only works on the local machine and thus this route will only with the files being on the local machine. I could use a file producer to copy the files from some remote directory to a local directory and then use the route. My route would be something like this then:
<route>
<from uri="file://c:/CTest/Inbox?noop=true&recursive=true&delay=3000"/>
<to uri="file://c:/outbox"/>
<to uri="bean://fileToSQL"/>
<to uri="jdbc://timlogdb"/>
</route>
However since I have access to the files content in the message from the files consumer I should be able to theoretically be able to access the body/content of the string and build a SQL command that does NOT use the LOAD_FILE() function.
The only way I know how to build such a string is by using the prepared statement of JDBC. This would be first prize if I could somehow build a insert statement with the content from the file consumer.
Can I create a prepared statement in my fileToSQL bean and pass it to my jdbc component?
Or how do I build a INSERT statement without the LOAD_FILE() function?
Since I have to use the LOAD_FILE() function I would now have to cater for both unix and windows filepaths. While this should not be difficult I just dont like the idea of putting OS specific code into my applications(feels like a work around).
Anybody here ever uploaded binary files to a MySQL database using Camel who can give me some guidance on the points above. While I could work around the problems I just want to make sure I dont miss a obvious way of doing things.
I had a look around here and only found people working with mostly text files. Guys please don't even go down the route of me storing the file on the files system and linking it to the database. We have some very specific disaster recovery requirements and legal requirements that enforce the need for me to store it in a database.
Right so I managed to find a way and it was not that difficult. What I essentially did was get rid of the JDBC Camel Component in the route. I then injected the data source bean into my fileToSQL bean. I then used a simple prepared statement to insert the file and its name into MySQL.
As always code is much more explicit than my english.
<camelContext xmlns="http://camel.apache.org/schema/spring">
<package>com.hia.camelone</package>
<route>
<from uri="file://c:/CTest/Inbox?noop=true&recursive=true&delay=3000"/>
<to uri="bean://fileToSQL"/>
<!--<to uri="jdbc://timlogdb"/>-->
</route>
</camelContext>
<bean id="timlogdb" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value=" com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/TimLog" />
<property name="username" value="root" />
<property name="password" value="lalala" />
</bean>
<bean id="fileToSQL" class="com.hia.camelone.fileToSQL">
<property name="dataSource" ref="timlogdb"/>
</bean>
As you can see I inject my timlogdb bean into my fileToSQL bean. Spring ROCKS!
So here is my fileToSQL bean.
public class fileToSQL {
private DriverManagerDataSource dataSource;
private static final String SQL_INSERT="insert into FileLog(FileName,FileData)values(?,?)";
#Handler
public void toString(#Headers Map<String,Object> header,Exchange exchange){
Connection conn = null;
PreparedStatement stmt=null;
String filename =StringEscapeUtils.escapeJava(((String)header.get("CamelFileNameOnly")).replace("\'", ""));
try {
conn= dataSource.getConnection();
stmt =conn.prepareStatement(SQL_INSERT);
stmt.setString(1, filename);
byte[] filedata = exchange.getIn().getBody(byte[].class);
stmt.setBytes(2,filedata );
int s = stmt.executeUpdate();
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
finally{
try
{
if (stmt!=null)
{
stmt.close();
}
if (conn!=null)
{
conn.close();
}
}
catch(SQLException e)
{
System.out.println(e.getMessage());
}
}
}
/**
* #param dataSource the dataSource to set
*/
public void setDataSource(DriverManagerDataSource dataSource) {
this.dataSource = dataSource;
}
}
The guys from Camel did a great job. Camel is truly flexible especially when you combine it with Spring.
What a ride!

About hibernate NamedNativeQuery

I am a newbie in hibernate, I am using #javax.persistence.NamedNativeQuery to resolve my stored proc calls from hibernate to mysql but i am getting errors.
Please help:
My persistent class is:
#Entity
#javax.persistence.NamedNativeQuery(name = "SampleNameQuery", query = "call spS_NamedQuery(?,?)", resultClass = NamedQuery.class)
public class NamedQuery {
#Id
public String name;
#Column
public String value;
}
My mysql stored proc is:
DELIMITER $$
DROP PROCEDURE IF EXISTS `cpgDB`.`spS_NamedQuery`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `spS_NamedQuery`(IN name VARCHAR(255),OUT var_value VARCHAR(255))
BEGIN
SET var_value = (SELECT value FROM NamedQuery WHERE NamedQuery.name = name);
END$$
DELIMITER ;
The main method that is calling this code is as:
public static void main(String[] args) throws Exception {
Transaction trx = null;
Session session = HibernateSessionFactory.getSession();
try {
trx = session.beginTransaction();
org.hibernate.Query query = session.getNamedQuery("SampleNameQuery");
query.setParameter(0,"fsdfsdf");
String value = "";
query.setParameter(1,value);
List objList = query.list();
trx.commit();
} catch (Exception ex) {
trx.rollback();
throw ex;
} finally {
HibernateSessionFactory.closeSession();
}
}
My hibernate config file is as :
<?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="connection.username">xxxx</property>
<property name="connection.url">jdbc:mysql://127.0.0.1:3306/cpgDB</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="myeclipse.connection.profile">MySQL</property>
<property name="connection.password">xxxxx</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hbm2ddl.auto">update</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<mapping class="Demo.NamedQuery"/>
</session-factory>
</hibernate-configuration>
On code execution i am getting following error/exception:
Sep 15, 2009 8:54:16 PM org.hibernate.util.JDBCExceptionReporter logExceptions
SEVERE: OUT or INOUT argument 2 for routine cpgDB.spS_NamedQuery is not a variable or NEW pseudo-variable in BEFORE trigger
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not execute query
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.loader.Loader.doList(Loader.java:2214)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2095)
at org.hibernate.loader.Loader.list(Loader.java:2090)
at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:289)
at org.hibernate.impl.SessionImpl.listCustomQuery(SessionImpl.java:1695)
at org.hibernate.impl.AbstractSessionImpl.list(AbstractSessionImpl.java:142)
at org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:152)
at Demo.TestDrive.main(TestDrive.java:44)
Caused by: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: OUT or INOUT argument 2 for routine cpgDB.spS_NamedQuery is not a variable or NEW pseudo-variable in BEFORE trigger
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:930)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2864)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1567)
at com.mysql.jdbc.ServerPreparedStatement.serverExecute(ServerPreparedStatement.java:1154)
at com.mysql.jdbc.ServerPreparedStatement.executeInternal(ServerPreparedStatement.java:679)
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1256)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:186)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1778)
at org.hibernate.loader.Loader.doQuery(Loader.java:662)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224)
at org.hibernate.loader.Loader.doList(Loader.java:2211)
... 7 more
Please help what is going wrong and help me get it corrected. Also refer me to suitable links where i can learn more about this technique.
Thanks in advance
Ashish
I was unable to find answer to this question, the solution i implemented then was to not use the 'out' field in my stored procedure and return the result of sql query via select command only.
Possibly Hibernate has not fully implemented this feature of returning 'Out' parameters.