Im creating a simple web app using Spring and Hibernate that has something to do with online shopping. My program is doing well when inserting new data using hibernate. When I check the db, the data is there. The problem is, the moment I fetch the new data I created, it gets nothing. I tried to put data in the db manually and hibernate gets the data. I'm sorry if this seems a beginner question, I'm studying Hibernate as a part of my training as a jr web developer. First, I wanna show you the config:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/------" />
<property name="username" value="----" />
<property name="password" value="------" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="packagesToScan" value="com.qbryx.domain" />
</bean>
Here is the code for adding a new product:
#Override
public void addProduct(Product product) {
Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
Query query = session.createSQLQuery(DAOQuery.HQL_ADD_PRODUCT).setParameter("upc", product.getUpc())
.setParameter("category", product.getCategory().getCategoryId())
.setParameter("name", product.getName()).setParameter("description", product.getDescription())
.setParameter("price", product.getPrice());
query.executeUpdate();
transaction.commit();
} catch (HibernateException e) {
if (transaction != null)
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
#Override
public void addProductStock(InventoryProduct inventoryProduct) {
Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
Query query = session.createSQLQuery(DAOQuery.HQL_ADD_PRODUCT_STOCK)
.setParameter("upc", inventoryProduct.getUpc())
.setParameter("stock", inventoryProduct.getStock());
query.executeUpdate();
transaction.commit();
} catch (HibernateException e) {
e.printStackTrace();
} finally {
session.close();
}
}
This code does fine with adding a new product together with the stock. Here is my code for fetching the product:
#Override
public InventoryProduct getInventoryProductByUpc(String upc) {
InventoryProduct product = null;
Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
Query query = session.createQuery(DAOQuery.HQL_GET_INVENTORY_PRODUCT)
.setParameter("upc", upc);
product = (InventoryProduct) query.getSingleResult();
transaction.commit();
} catch (HibernateException e) {
if (transaction != null)
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
return product;
}
I don't understand why Hibernate can fetch data that is manually added to the database but not the data added through Hibernate. I need help. Thanks!
Related
I'm writing simple app using Hibernate. I have hibernate.cfg.xml file as follows:
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/demo
</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">1234</property>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<!-- Use the C3P0 connection pool provider -->
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<!--List of XML mapping files -->
<mapping class="www.Message"/>
</session-factory>
</hibernate-configuration>
and retrieve SessionFactory object as follows:
//in HibernateUtil.class
SessionFactory sessionFactory;
Configuration configuration=new
Configuration().configure("hibernate.cfg.xml");
sessionFactory=configuration.buildSessionFactory();`
And everything works fine until I add C3P0 jars:
c3p0-0.9.5.2.jar
hibernate-c3p0-5.2.14.Final.jar
mchange-commons-java-0.2.11.jar
After adding jars above, the app throws StackOverflowError.
Here's my main App class:
package www;
import org.hibernate.Session;
import utils.HibernateUtil;
import java.util.List;
public class HelloWorld {
public static void main(String[] args) {
Session session = null;
try {
session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
session.save(new Message("Hello Denmark!"));
session.getTransaction().commit();
session.close();
System.out.println("Message saved...");
session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
List messages = session.createQuery("from Message m order by m.text
asc").list();
System.out.println("Messages found:"+messages.size());
for (Object mes: messages) {
Message message = (Message) mes;
System.out.println(message.getText());
}
session.getTransaction().commit();
session.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (session != null) session.close();
}
}
}
Any help would be appreciated.
My Dao layer has a save method as:
public void savePerson(PersonBean personBean) {
Session currentSession;
try {
currentSession = sessionFactory.getCurrentSession();
} catch (HibernateException e) {
currentSession = sessionFactory.openSession();
System.out.println("Opened Session");
}
currentSession.merge(personBean);
System.out.println("Data Saved");
}
And the applicationContext.xml is defined as :
<bean id="oracleDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url" value="jdbc:oracle:thin:#localhost:1521:{mylocalInstance}" />
<property name="username">
<value>PersonDataBase</value>
</property>
<property name="password">
<value>person</value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="oracleDataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="mappingLocations" value="PersonBean.hbm.xml" />
</bean>
<bean id="testTransactional" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!--<tx:annotation-driven transaction-manager="testTransactional"/>-->
<bean id="personDao" class="com.dao.PersonDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="personService" class="com.service.PersonServiceImpl">
<property name="personDao" ref="personDao"/>
</bean>
It is able to create the tables but the data is not saved, as I have to show the sql, this is the sql generated when trying to save:
INFO: Using DataSource [org.springframework.jdbc.datasource.DriverManagerDataSource#68be8808] of Hibernate SessionFactory for HibernateTransactionManager
Opened Session
Hibernate:
select
max(PERSON_ID)
from
PERSON_BEAN
Data Saved
Why is select query being generated when I am trying to save it.
You need to commit your transaction as well.
Try this:
public void savePerson(PersonBean personBean) {
Session currentSession;
try {
currentSession = sessionFactory.getCurrentSession();
} catch (HibernateException e) {
currentSession = sessionFactory.openSession();
System.out.println("Opened Session");
}
currentSession.beginTransaction();
currentSession.merge(personBean);
currentSession.getTransaction().commit()
System.out.println("Data Saved");
}
EDIT
You can also set hibernate.connection.autocommit property to true in Hibernate configuration if you don't want to handle transactions manually.
<property name="hibernate.connection.autocommit">true</property>
Try currentSession.save(personBean)
and if you properly configured the Spring then you don't need to
beginTransaction() Spring will handle the transaction .
public void savePerson(PersonBean personBean) {
Session currentSession;
try {
currentSession = sessionFactory.getCurrentSession();
} catch (HibernateException e) {
currentSession = sessionFactory.openSession();
System.out.println("Opened Session");
}
currentSession.beginTransaction();
currentSession.save(personBean);
currentSession.getTransaction().commit()
System.out.println("Data Saved");
}
I have a Java web application running on Tomcat 7 - jdk1.7
This application uses Spring 4.1.5.RELEASE and Hibernate 4.2.2.Final
My problem is a OutOfMemoryException of the Heap space on building section factory
This is my static method that opens a SessionFactory
public class GenericDAO {
public static SessionFactory sessionFactory = null;
public static ServiceRegistry serviceRegistry = null;
Transaction tx = null;
public static SessionFactory createSessionFactory() {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings(
configuration.getProperties()). buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
}
And this is an example of DAO
public class SpecificDAO extends GenericDAO {
public int save(MyObject item) {
Session session = createSessionFactory().openSession();
try {
tx = session.beginTransaction();
session.save(item);
tx.commit();
return item.getId();
} catch (HibernateException e) {
if (tx != null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return -1;
}
}
The error occurs at the line containing
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
The problem doesn't occur immediately at the deploy, but after 2 o 3 days of usage
This is my Hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:sqlserver://192.168.XX.XXX:1433;databaseName=DatabaseName</property>
<property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<property name="connection.username">username</property>
<property name="connection.password">password</property>
<mapping class="it.company.client.project.hibernate.MyObject"/>
<!-- DB schema will be updated if needed -->
<!-- <property name="hbm2ddl.auto">update</property> -->
</session-factory>
</hibernate-configuration>
You have to create the session factory only once as it is a heavy weight object, refer to the hibernate documentation for its details.
Here is the sample code from the doc on how it should be created:
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory(
new StandardServiceRegistryBuilder().build() );
}
catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
It is better idea to flush and clear the session after used, you can use both
session.flush();
session.clear();
for more information link1 and link2
You are creating a SessionFactory object for every save() call.
i.e you are creating a new SessionFactory repeatedly for every save() call but not closing the existing SessionFactory objects in memory.
How many times save() is called ? the same no of SessionFactory will be in memory, which causes the memory leak.
SessionFactory are heavy weight objects, so you'd create at application initialization. You can create a SingleTon to instantiate SessionFactory.
Avoid instantiation of SessionFactory object on every DAO action. It is very slow and causes memory leaks. Better explained in this answer
If you're using Spring anyway, better to delegate to Spring work with SessionFactory, transactions and handling SQL exceptions. For example, your save() method will reduce to one line of code sessionFactory.getCurrentSession().save(item); Manual transaction open/commit/rollback should be replaced with #Transactional attribute. Also, usually better place transactions on whole service method, not on every single DAO method, but it depends of business logic.
Here example how to configure spring context for work with Hibernate (just first article for google)
I slightly adopted this example for current question
#Repository
public class SpecificDAO {
private SessionFactory sessionFactory;
#Autowired
public SpecificDAO(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
#Transactional(propagation=Propagation.REQUIRED)
public int save(MyObject item) {
try{
sessionFactory.getCurrentSession().save(item);
}catch (HibernateException e) {
return -1;
}
}
}
Spring configuration
<context:annotation-config/>
<context:component-scan base-package="it.company.client.project"/>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="jdbc:sqlserver://192.168.XX.XXX:1433;databaseName=DatabaseName"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>it.company.client.project.hibernate.MyObject</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.connection.provider_class">org.hibernate.connection.DatasourceConnectionProvider</prop>
<prop key="hibernate.show_sql">false</prop>
<!--prop key="hibernate.hbm2ddl.auto">update</prop-->
</props>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
I am running an Apache CXF web service under spring. I use JPA to persist the information. The service has a method that updates a series of rows. Before persisting each row, I check that the values to be persisted really exist in the databes. If there is a value that does not exists, then an Exception is thrown. The problem is I need to rollback al the values updated. I though that using #Transactional in my web service method would do the trick, but instead of that, the values that got persisted are really modified in the database, wich is not the desired behavior.
This is the code of the web service method
#Transactional( propagation = Propagation.REQUIRED )
public UpdateDescriptionResponse updateDescription(UpdateDescriptionRequest updateDescriptionRequest) throws SIASFaultMessage {
try {
SubstanceEntity substance = service.findSubstanceBySubstanceID(updateDescriptionRequest.getUpdateDescriptionRequestData().getIdentity().getSubstanceID());
if (substance!=null){
for(DescriptionKeyValueType keyValue: updateDescriptionRequest.getUpdateDescriptionRequestData().getSubstanceDescriptionData() ){
boolean descriptionExists = false;
for(DescriptionEntity desc: substance.getDescriptionsById()){
if (desc.getDescKey().equals(keyValue.getKey())) {
descriptionExists = true;
break;
}
}
if (!descriptionExists){
SIASFaultDetail faultDetail = new SIASFaultDetail();
faultDetail.setSIASFaultDescription("Description key does not match given substance ID");
faultDetail.setSIASFaultMessage(SIASFaultCode.INVALID_INPUT.toString());
faultDetail.setSIASFaultType(SIASFaultCode.INVALID_INPUT);
SIASFaultMessage fault = new SIASFaultMessage("Description key does not match given substance ID", faultDetail);
throw fault;
}
else
descriptionLogic.updateDescription(substance.getSubstanceId(), keyValue.getKey(),keyValue.getValue());
}
UpdateDescriptionResponse response = new UpdateDescriptionResponse();
UpdateDescriptionResponse.UpdateDescriptionResponsePackage responsePackage = new UpdateDescriptionResponse.UpdateDescriptionResponsePackage();
ResponseStatus status = new ResponseStatus();
status.setMessage(messageOk);
status.setReturn(BigInteger.valueOf(0));
responsePackage.setResponseStatus(status);
response.setUpdateDescriptionResponsePackage(responsePackage);
return response;
}
else
{
SIASFaultDetail faultDetail = new SIASFaultDetail();
faultDetail.setSIASFaultDescription("Substance ID does not exists");
faultDetail.setSIASFaultMessage(SIASFaultCode.INVALID_SUBSTANCE_ID.toString());
faultDetail.setSIASFaultType(SIASFaultCode.INVALID_SUBSTANCE_ID);
SIASFaultMessage fault = new SIASFaultMessage("Substance ID does not exists", faultDetail);
throw fault;
}
} catch (SIASFaultMessage ex) {
throw ex;
} catch (Exception ex) {
SIASFaultDetail a = new SIASFaultDetail();
a.setSIASFaultDescription("Unknown error processing enroll request");
a.setSIASFaultMessage("SERVICE_ERROR");
a.setSIASFaultType(SIASFaultCode.UNKNOWN_ERROR);
SIASFaultMessage fault = new SIASFaultMessage("Something happened", a);
throw fault;
}
}
This is the code for the instance of descriptionLogic.updateDescription(...)
#Override
public void updateDescription(String substanceID, String key, String value) {
PageRequest page = new PageRequest(1, 1);
Map<String, Object> filters = new HashMap<String, Object>();
filters.put("SUBSTANCE_ID", substanceID);
List<SubstanceEntity> substances = substanceService.findAll(page, filters);
if (substances.size() == 0) {
return;
}
SubstanceEntity substanceEntity = substances.get(0);
for (DescriptionEntity desc : substanceEntity.getDescriptionsById()) {
if (desc.getDescKey().equals(key)) {
desc.setDescValue(value);
descriptionService.persist(desc);
}
}
}
This is the test that fails
#Test()
public void testUpdateDescription_does_not_modify_description_with_invalid_values() throws Exception {
UpdateDescriptionRequest request = new UpdateDescriptionRequest();
UpdateDescriptionRequest.UpdateDescriptionRequestData data = new UpdateDescriptionRequest.UpdateDescriptionRequestData();
SIASIdentity identity = new SIASIdentity();
identity.setSubstanceID("804ab00f-d5e9-40ff-a4d3-11c51c2e7479");
data.getSubstanceDescriptionData().add(new DescriptionKeyValueType() {{
setKey("KEY3_1");
setValue("NEW_VALUE_1");
}});
data.getSubstanceDescriptionData().add(new DescriptionKeyValueType() {{
setKey("KEY3_5");
setValue("NEW_VALUE_2");
}});
data.setIdentity(identity);
request.setUpdateDescriptionRequestData(data);
try {
siasService.updateDescription(request);
}
catch (SIASFaultMessage ex){
}
DescriptionEntity descriptionEntity1 = descriptionService.findById(1);
DescriptionEntity descriptionEntity2 = descriptionService.findById(2);
assertThat("The value does not math",descriptionEntity1.getDescValue(), not(equalTo("NEW_VALUE_1")));
assertThat("The value does not math",descriptionEntity2.getDescValue(), not(equalTo("NEW_VALUE_2")));
Assert.assertEquals("The description does not math","KEY3_1", descriptionEntity1.getDescKey());
Assert.assertEquals("The description does not math","KEY3_2", descriptionEntity2.getDescKey());
}
It fails in this line:
assertThat("The value does not math",descriptionEntity1.getDescValue(), not(equalTo("NEW_VALUE_1")));
This is my datasource configuration in my spring context configuration file
.
.
.
<bean id="myDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<jdbc:initialize-database data-source="myDataSource">
<jdbc:script location="classpath:test-data.sql" />
</jdbc:initialize-database>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="packagesToScan" value="cu.jpa"/>
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
<property name="jpaDialect">
<bean class="cu.jpa.specifications.IsolationSupportHibernateJpaDialect" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">${hdm2ddl.auto}</prop>
</props>
</property>
<property value="/META-INF/persistence.xml" name="persistenceXmlLocation"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven/>
.
.
.
This is my persistence.xml file content:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="NewPersistenceUnit">
<class>cu.jpa.entities.PatternEntity</class>
.
.
.
<class>cu.jpa.entities.TraceRegEntity</class>
</persistence-unit>
</persistence>
Extract of the test class:
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/repositories.xml"})
public class ServiceImplUpdateDescriptionTest {
.
.
.
#Test()
public void testUpdateDescription_does_not_modify_description_with_invalid_values() throws Exception{
.
.
.
}
}
Spring will only rollback the transaction if it is an unchecked exception, if the exception is a checked exception then you will have to add that to your #Transactional annotation.
#Transactional(rollbackFor = SIASFaultMessage.class)
I am using hibernate with spring frame work and my beans are in singleton mode.did i supposed to close my session or no (because they are in singleton mode)?
the reality is that we got some problems on our server and too many connections problem
and i thought may be that is the problem.thanks.
this is my codes:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" scope = "singleton" >
<property name="dataSource" ref local="dataSource" property/>
<property name="packagesToScan" >
<value>Model.Entity</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.auto_close_session">false</prop>
</props>
</property>
and this is the way i use , i close all sessions after i used
#Autowired
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void updateDB() {
Session session = getSessionFactory().openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
transaction.commit();
} catch (HibernateException e) {
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
If you configure the spring and hibernate configuration you don't need to close the connections and sessions, Spring will do that for you.
See this example http://howtodoinjava.com/2013/03/21/spring-3-and-hibernate-integration-tutorial-with-example/