Java Spring、Wildfly、Hibernate-所属会话已关闭
几年来,我们已经有了一个功能齐全的web解决方案投入生产。关键技术是 Wildfly 10.1.0 爪哇8 春季4.3.3 Hibernate 5.0.10(Wildfly 10.1.0中的JPA引擎) Envers 5.0.10 因此,升级要转到设置 Wildfly 15.0 爪哇11 弹簧5.1.3 Hibernate 5.3.7(Wildfly 15中的JPA引擎) 只要做这个切换和som小的代码更改(非常小)都很好,应用程序启动,我可以毫无问题地登录,也就是说,我可以毫无问题地读取和映射到实体。但在@Transaction下更新数据库时,我们遇到了一个非常大的问题,似乎与会话提前关闭有关(simlar对Hibernate bug HHH-11570进行了相同的讨论)。更新似乎进展顺利,当Hibernate需要为延迟加载实体启动会话时,会话关闭,Hibernate抛出异常。 请让我知道这是否是一个错误?我试图将原始的未升级的Java8WAR部署到服务器上,但问题完全相同,因此这是一个很好的论据,可以说问题是Hibernate或Wildfly。我真的需要升级系统。如果您需要更多stacktrace、代码或配置,请告诉我 弹簧的一些配置如下:Java Spring、Wildfly、Hibernate-所属会话已关闭,java,spring,hibernate,jpa,wildfly,Java,Spring,Hibernate,Jpa,Wildfly,几年来,我们已经有了一个功能齐全的web解决方案投入生产。关键技术是 Wildfly 10.1.0 爪哇8 春季4.3.3 Hibernate 5.0.10(Wildfly 10.1.0中的JPA引擎) Envers 5.0.10 因此,升级要转到设置 Wildfly 15.0 爪哇11 弹簧5.1.3 Hibernate 5.3.7(Wildfly 15中的JPA引擎) 只要做这个切换和som小的代码更改(非常小)都很好,应用程序启动,我可以毫无问题地登录,也就是说,我可以毫无问题地读取和映射
@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();
}
}
身份验证用户实体
@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;
}
wildfly数据源在standalone.xml中定义为
<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>
jdbc:mysql://xxxxxxxxxxxxxxxxx:3306/eaktiebokdump?useSSL=false
com.mysql.jdbc.Driver
mysql
xxxxxxx
xxxxxxx
真的
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>
org.hibernate.ejb.HibernatePersistence
java:/eaktiebok
最后是控制台的一小部分和一些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
09:05:39320调试[org.springframework.transaction.jta.JtaTransactionManager.handleExistingTransaction](默认任务-9)参与现有事务
09:05:39320调试[org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager](默认任务-9)关闭jpa EntityManager
09:05:39321调试[org.springframework.transaction.jta.JtaTransactionManager.processCommit](默认任务-9)启动事务提交
09:05:39321调试[org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes](默认任务-9)处理刷新时间级联
09:05:39321调试[org.hibernate.event.internal.AbstractFlushingEventListener.prepareCollectionFlushes](默认任务-9)脏检查集合
原因:org.hibernate.LazyInitializationException:无法初始化代理[se.eaktiebok.jpa.auth.AuthClient#1]-所属会话已关闭
在org。hibernate@5.3.7.Final//org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:172)
在org。hibernate@5.3.7.Final//org.hibernate.proxy.AbstractLazyInitializer.getIdentifier(AbstractLazyInitializer.java:89)
在org。hibernate@5.3.7.Final//org.hibernate.envers.internal.entities.mapper.id.SingleIdMapper.maptompfromentity(SingleIdMapper.java:125)
在org。hibernate@5.3.7.Final//org.hibernate.envers.internal.entities.mapper.relation.ToOneIdMapper.mapToMapFromEntity(ToOneIdMapper.java:55)
在org。hibernate@5.3.7.Final//org.hibernate.envers.internal.entities.mapper.MultiPropertyMapper.map(MultiPropertyMapper.java:90)
在org。hibernate@5.3.7.Final//org.hibernate.envers.internal.synchronization.work.ModWorkUnit.(ModWorkUnit.java:43)
在org。hibernate@5.3.7.Final//org.hibernate.envers.event.spi.EnversPostUpdateEventListenerImpl.onPostUpdate(EnversPostUpdateEventListenerImpl.java:46)
在org。hibernate@5.3.7.Final//org.hibernate.action.internal.EntityUpdateAction.postUpdate(EntityUpdateAction.java:268)
在org。hibernate@5.3.7.Final//org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:215)
在org。hibernate@5.3.7.Final//org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
在org。hibernate@5.3.7.Final//org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
在org。hibernate@5.3.7.Final//org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
在org。hibernate@5.3.7.Final//org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
在org。hibernate@5.3.7.Final//org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454)
... 131更多
完成启动事务的业务功能
@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
@覆盖
@交易的
公共UserBean updateIntoUser(UserBean UserBean,UserBean authenticatedUser)抛出AuthUserException{
notNull(userBean,“userBean不能为null”);
Assert.notNull(authenticatedUser,“authenticatedUser不能为null”);
//如果设置了标识,请选中,以便其他用户没有该标识
if(userBean.getIdentity()!=null){
UserBean ub=findAuthUserByIdentity(UserBean.getIdentity());
如果(ub!=null){
如果(!ub.getIduser().equals(userBean.getIduser())){
抛出新的AuthUserException(“由iduser获取的联系人/公司”+ub.getIduser(),AuthUserExceptionCause.contactTake);
}
}
OwnerEntityBean o=companyDao.findOwnerEntityBean(userBean.getIdentity());
用户实体ue=null;
如果(o!=null){
ue=新的UserEntity();
setAddressBean(o.getAddress());
setEntityType(o.getEntityType());
setIdentityNumber(o.getIdentityNumber());
ue.setName(o.getName());
}
setUserEntity(ue);
}
//如果用户名更改,请检查是否免费
如果(!authenticatedUser.getUsername().equals(userBean.getUsername())){
AuthUser user=userRepo.findUserByUsername(userBean.getUsername());
如果(user!=null&&!user.getIduser().equals(userBea