Ghaleb Khaled
Ghaleb Khaled

Reputation: 180

AssertionFailure: null id sometimes thrown when Hibernate query objects

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

Answers (1)

ekem chitsiga
ekem chitsiga

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

Related Questions