2

We have an existing fully functional web solution in production since a couple of years. The key technologies are

Wildfly 10.1.0 Java 8 Spring 4.3.3 Hibernate 5.0.10 ( JPA engine in Wildfly 10.1.0 ) Envers 5.0.10

So the upgrade was to go to the setting

Wildfly 15.0 Java 11 Spring 5.1.3 Hibernate 5.3.7 ( JPA engine in Wildfly 15 )

Just doing this switch and som minor code changes (very minor) all is well, the application starts and I can login with no problem, i.e. I can read and map to entities with no problem. But on update to database under @Transaction we have a very big issue that seems to be related to session being closed to early ( simlar to Hibernate bug HHH-11570 same discussion ). The update seems to go well, it is when Hibernate needs to start an a session for lazy load entity the session is closed an Hibernate throws an exception. Please let me know if this is a bug? I tried to deploy the original non upgraded Java 8 war to the server but the problem is exactly the same so this is a good argument to say that the problem is Hibernate or Wildfly. I really need to upgrade the system. Let me know if you need more stacktrace, code or configuration.

And some configurations of Spring are

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages="se.eaktiebok.repository")
public class JpaConfiguration {
    @Bean
    public DataSource dataSource() throws NamingException{
        Context ctx = new InitialContext();
        DataSource dataSource = (DataSource)ctx.lookup("java:/eaktiebok");
        return dataSource;
    }   

@Bean
public PlatformTransactionManager transactionManager() throws NamingException{
    JtaTransactionManager tm = new JtaTransactionManager();
    tm.afterPropertiesSet();
    return tm;
}

@Bean
public SharedEntityManagerBean entityManager() throws NamingException{
    SharedEntityManagerBean entityManager = new SharedEntityManagerBean();
    entityManager.setEntityManagerFactory(this.entityManagerFactory());
    return entityManager;
}   

@Bean 
EntityManagerFactory entityManagerFactory() throws IllegalArgumentException, NamingException{
    org.springframework.jndi.JndiObjectFactoryBean jndiObjectFactoryBean = new org.springframework.jndi.JndiObjectFactoryBean();
    jndiObjectFactoryBean.setJndiName("java:app/JPADBFactory");
    jndiObjectFactoryBean.setLookupOnStartup(true);
    jndiObjectFactoryBean.setExpectedType(EntityManagerFactory.class);
    jndiObjectFactoryBean.afterPropertiesSet(); 
    return (EntityManagerFactory) jndiObjectFactoryBean.getObject();
}

}

AuthUser entity

@Entity
@Table(name=“auth_user”)
@Audited(withModifiedFlag=true)
public class AuthUser implements Serializable {
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer iduser;

....

@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="idclient", insertable=false, updatable = false)
private AuthClient authClient;
}

The wildfly datasource is defined in standalone.xml as

    <datasource jndi-name="java:/eaktiebok" pool-name="eaktiebok">
        <connection-url>jdbc:mysql://xxxxxxxxxxxxxxxxx:3306/eaktiebokdump?useSSL=false</connection-url>
        <driver-class>com.mysql.jdbc.Driver</driver-class>
        <driver>mysql</driver>
        <security>
            <user-name>xxxxxxx</user-name>
            <password>xxxxxxx</password>
        </security>
        <validation>
            <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker"/>
            <background-validation>true</background-validation>
            <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter"/>
        </validation>
    </datasource>

persistence.xml

<?xml version="1.0" encoding="UTF-8" ?>
<persistence-unit name="jpaEabMysqlUnit" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/eaktiebok</jta-data-source>
    <properties>
        <property name="hibernate.jdbc.use_streams_for_binary" value="true"/>
        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
        <property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
        <property name="org.hibernate.envers.store_data_at_delete" value="false"/>
        <property name="hibernate.generate_statistics" value="false"/>
        <property name="jboss.entity.manager.jndi.name" value="java:app/JPADB"/>
        <property name="jboss.entity.manager.factory.jndi.name" value="java:app/JPADBFactory"/>
    </properties>
</persistence-unit>

And finally a little part of console with some stacktrace

09:05:39,320 DEBUG [org.springframework.transaction.jta.JtaTransactionManager.handleExistingTransaction] (default task-9) Participating in existing transaction
09:05:39,320 DEBUG [org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager] (default task-9) Closing JPA EntityManager
09:05:39,321 DEBUG [org.springframework.transaction.jta.JtaTransactionManager.processCommit] (default task-9) Initiating transaction commit
09:05:39,321 DEBUG [org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes] (default task-9) Processing flush-time cascades
09:05:39,321 DEBUG [org.hibernate.event.internal.AbstractFlushingEventListener.prepareCollectionFlushes] (default task-9) Dirty checking collections


Caused by: org.hibernate.LazyInitializationException: could not initialize proxy [se.eaktiebok.jpa.auth.AuthClient#1] - the owning Session was closed
    at org.hibernate@5.3.7.Final//org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:172)
    at org.hibernate@5.3.7.Final//org.hibernate.proxy.AbstractLazyInitializer.getIdentifier(AbstractLazyInitializer.java:89)
    at org.hibernate@5.3.7.Final//org.hibernate.envers.internal.entities.mapper.id.SingleIdMapper.mapToMapFromEntity(SingleIdMapper.java:125)
    at org.hibernate@5.3.7.Final//org.hibernate.envers.internal.entities.mapper.relation.ToOneIdMapper.mapToMapFromEntity(ToOneIdMapper.java:55)
    at org.hibernate@5.3.7.Final//org.hibernate.envers.internal.entities.mapper.MultiPropertyMapper.map(MultiPropertyMapper.java:90)
    at org.hibernate@5.3.7.Final//org.hibernate.envers.internal.synchronization.work.ModWorkUnit.<init>(ModWorkUnit.java:43)
    at org.hibernate@5.3.7.Final//org.hibernate.envers.event.spi.EnversPostUpdateEventListenerImpl.onPostUpdate(EnversPostUpdateEventListenerImpl.java:46)
    at org.hibernate@5.3.7.Final//org.hibernate.action.internal.EntityUpdateAction.postUpdate(EntityUpdateAction.java:268)
    at org.hibernate@5.3.7.Final//org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:215)
    at org.hibernate@5.3.7.Final//org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
    at org.hibernate@5.3.7.Final//org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
    at org.hibernate@5.3.7.Final//org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
    at org.hibernate@5.3.7.Final//org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
    at org.hibernate@5.3.7.Final//org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454)
    ... 131 more

Complete business function that starts transaction

@Override
@Transactional
public UserBean updateIntoUser(UserBean userBean, UserBean authenticatedUser) throws AuthUserException {
    Assert.notNull(userBean, "userBean must not be null");
    Assert.notNull(authenticatedUser, "authenticatedUser must not be null");

    // If identity is set, check so no other user has it
    if(userBean.getIdentity()!=null) {
        UserBean ub = findAuthUserByIdentity(userBean.getIdentity());
        if(ub!=null) {
            if(!ub.getIduser().equals(userBean.getIduser())) {
                throw new AuthUserException("Contact/Company taken by iduser "+ub.getIduser(), AuthUserExceptionCause.contactTaken);
            }
        }

        OwnerEntityBean<?> o = companyDao.findOwnerEntityBean(userBean.getIdentity());
        UserEntity ue = null;
        if(o!=null) {
            ue = new UserEntity();
            ue.setAddressBean(o.getAddress());
            ue.setEntityType(o.getEntityType());
            ue.setIdentityNumber(o.getIdentityNumber());
            ue.setName(o.getName());
        }
        userBean.setUserEntity(ue);

    }
    // If username changed check so it is free
    if(!authenticatedUser.getUsername().equals(userBean.getUsername())) {
        AuthUser user = userRepo.findUserByUsername(userBean.getUsername());
        if(user!=null&&!user.getIduser().equals(userBean.getIduser())) {
            throw new AuthUserException("Username already exists "+userBean.toString(), AuthUserExceptionCause.nonUniqueUsername);
        }
    }

    // update AuthUser 
    userDao.updateIntoUser(userBean);

    // Load AuthUser with contact and address

    return userBean;
} // end function updateIntoUser
  • can you share the code where AuthClient object getting invoked from AuthUser object. I would also need where you have put in the @Transactional – Ankur Dec 27 '18 at 08:56
  • This issue generally takes place when your AuthUser object is no longer part of session/transaction, and you are trying to get the value of AuthClient object. – Ankur Dec 27 '18 at 08:58
  • It is clear that the AuthUser is not part of the session any more. The problem is that this code, no changes, works perfectly on Wildfly 10.1. I added the business function in my question above. – Tim Mickelson Dec 27 '18 at 09:30
  • I looked for you solution, but could not find any related to environment changes. Although I did came across a solution, that do requires a minor code change. Maybe that helps. https://stackoverflow.com/questions/50446544/wildfly-how-to-enable-transactions-to-enable-lazy-loading – Ankur Dec 28 '18 at 05:33
  • The issue is resolved, this has been recognized as a bug and is resolved by Hibernate, there is a pull request and should be part of Hibernate 5.4.1. See Jira issue 13191 - https://hibernate.atlassian.net/browse/HHH-13191 – Tim Mickelson Jan 10 '19 at 19:32
  • Workaround for earlier version Hibernate, add hibernate.jpa.compliance.proxy=false – Tim Mickelson Jan 10 '19 at 19:34

0 Answers0