Reputation: 180
I have a Spring 4.2.4/Hibernate 5.0.6 running on Tomcat v2.2.0 EC2 servers.
The issue I have is after running server for sometime (more than one day) I start to get the following exception occasionally
org.hibernate.AssertionFailure: null id in com.app.core.models.User entry (don't flush the Session after an exception occurs)
org.hibernate.event.internal.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:60)
org.hibernate.event.internal.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:175)
org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:135)
org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:216)
org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:85)
org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:44)
org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1251)
org.hibernate.internal.SessionImpl.list(SessionImpl.java:1767)
org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:363)
com.app.core.dao.AbstractDao.queryBy(AbstractDao.java:57)
com.app.business.MainController.surveryPage(MainController.java:41)
sun.reflect.GeneratedMethodAccessor65.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:178)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:444)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:432)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
The object Survery object have an owner field of type User, as the exception states that the id is null, checking the Datebase, the id is not not null. And actually restarting the server make the error disappear for a while.
@Entity
@Table(indexes={@Index(columnList = "OWNER_ID", name = "OWNER_ID_INDEX")})
public class Survey extends Persistable{
...
@JsonIgnore
@ManyToOne
@JoinColumn(name = "OWNER_ID", nullable = true)
private User owner;
...
}
The query operation I'm doing is:
public List<T> queryBy(String field, Object val) {
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Criteria criteria = session.createCriteria(persistentClass);
criteria.add(Restrictions.eq(field, val));
@SuppressWarnings("unchecked")
List<T> l = criteria.list();
transaction.commit();
return l;
}
Actually I'm worrying if I did something wrong in the session configuration, the configuration for hibernate are below:
import org.apache.commons.dbcp2.BasicDataSource;
import org.hibernate.SessionFactory;
import org.reflections.Reflections;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBuilder;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.app.core.db.PersistableInterceptor;
import com.app.core.db.Persistable;
@Configuration
@EnableTransactionManagement
@Profile("dev")
public class Config {
.....
@Bean
public HibernateTemplate hibernateTemplate() {
return new HibernateTemplate(sessionFactory());
}
@Bean
public SessionFactory sessionFactory() {
if (sessionFactory!= null){
return sessionFactory;
}
Properties p = new Properties();
p.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
p.put("connection_pool_size", "10");
p.put("hibernate.current_session_context_class", "thread");
p.put("show_sql", "true");
p.put("hibernate.hbm2ddl.auto", "update");
p.put("hibernate.default_schema", "app");
p.put("hibernate.jdbc.batch_size", BATCH_SIZE);
SessionFactory sessionFactory = new LocalSessionFactoryBuilder(getDataSource())
.addAnnotatedClasses(ANNOTATED_CLASSES)
.addProperties(p)
.setInterceptor(new PersistableInterceptor())
.buildSessionFactory();
Config.sessionFactory = sessionFactory;
return sessionFactory;
}
@Bean
public HibernateTransactionManager hibTransMan(){
return new HibernateTransactionManager(sessionFactory());
}
.....
}
Any thoughts or suggestion?
Upvotes: 0
Views: 774
Reputation: 5753
You are mixing Hibernate managed transactions with Spring managed transactions. When you are using Spring transaction management abstraction you don`t have to use resource specific transactions
You have Spring transactions enabled via @EnableTransactionManagenent. If your beans have a @Transactional annotation then refactor your code to be
public List<T> queryBy(String field, Object val) {
Session session = sessionFactory.getCurrentSession();
Criteria criteria = session.createCriteria(persistentClass);
criteria.add(Restrictions.eq(field, val));
@SuppressWarnings("unchecked")
List<T> l = criteria.list();
return l;
}
Also change your SessionFactory bean definition to make use of LocalSessionFactoryBean provided by Spring. This provides hooks for transaction management using Spring abstraction. Example
@Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "package.to.your.entity.classes" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
@Bean
public DataSource dataSource(){
//define datasource
}
private Properties hibernateProperties() {
//hibernate props
}
Upvotes: 1