HHH-7971 - Enabling ENABLE_LAZY_LOAD_NO_TRANS results in trying to remove elements in collections

This commit is contained in:
Steve Ebersole 2014-03-21 12:06:04 -05:00
parent 30205607ef
commit 6f342358db
6 changed files with 246 additions and 43 deletions

View File

@ -35,6 +35,7 @@ import java.util.ListIterator;
import javax.naming.NamingException;
import org.hibernate.AssertionFailure;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.LazyInitializationException;
import org.hibernate.Session;
@ -81,7 +82,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
private Serializable storedSnapshot;
private String sessionFactoryUuid;
private boolean specjLazyLoad;
private boolean allowLoadOutsideTransaction;
/**
* Not called by Hibernate, but used by non-JDK serialization,
@ -205,7 +206,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
boolean isJTA = false;
if ( session == null ) {
if ( specjLazyLoad ) {
if ( allowLoadOutsideTransaction ) {
session = openTemporarySessionForLoading();
isTempSession = true;
}
@ -214,7 +215,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
}
else if ( !session.isOpen() ) {
if ( specjLazyLoad ) {
if ( allowLoadOutsideTransaction ) {
originalSession = session;
session = openTemporarySessionForLoading();
isTempSession = true;
@ -224,7 +225,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
}
else if ( !session.isConnected() ) {
if ( specjLazyLoad ) {
if ( allowLoadOutsideTransaction ) {
originalSession = session;
session = openTemporarySessionForLoading();
isTempSession = true;
@ -235,8 +236,6 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
if ( isTempSession ) {
// TODO: On the next major release, add an
// 'isJTA' or 'getTransactionFactory' method to Session.
isJTA = session.getTransactionCoordinator()
.getTransactionContext().getTransactionEnvironment()
.getTransactionFactory()
@ -250,7 +249,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
// multiple transactions.
( (Session) session ).beginTransaction();
}
session.getPersistenceContext().addUninitializedDetachedCollection(
session.getFactory().getCollectionPersister( getRole() ),
this
@ -284,7 +283,10 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
final SessionFactoryImplementor sf = (SessionFactoryImplementor)
SessionFactoryRegistry.INSTANCE.getSessionFactory( sessionFactoryUuid );
return (SessionImplementor) sf.openSession();
final SessionImplementor session = (SessionImplementor) sf.openSession();
session.getPersistenceContext().setDefaultReadOnly( true );
session.setFlushMode( FlushMode.MANUAL );
return session;
}
protected Boolean readIndexExistence(final Object index) {
@ -593,7 +595,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
@Override
public final boolean unsetSession(SessionImplementor currentSession) {
prepareForPossibleSpecialSpecjInitialization();
prepareForPossibleLoadingOutsideTransaction();
if ( currentSession == this.session ) {
this.session = null;
return true;
@ -603,11 +605,11 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
}
protected void prepareForPossibleSpecialSpecjInitialization() {
protected void prepareForPossibleLoadingOutsideTransaction() {
if ( session != null ) {
specjLazyLoad = session.getFactory().getSettings().isInitializeLazyStateOutsideTransactionsEnabled();
allowLoadOutsideTransaction = session.getFactory().getSettings().isInitializeLazyStateOutsideTransactionsEnabled();
if ( specjLazyLoad && sessionFactoryUuid == null ) {
if ( allowLoadOutsideTransaction && sessionFactoryUuid == null ) {
try {
sessionFactoryUuid = (String) session.getFactory().getReference().get( "uuid" ).getContent();
}

View File

@ -26,6 +26,7 @@ package org.hibernate.proxy;
import java.io.Serializable;
import javax.naming.NamingException;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.LazyInitializationException;
import org.hibernate.Session;
@ -59,7 +60,7 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
private Boolean readOnlyBeforeAttachedToSession;
private String sessionFactoryUuid;
private boolean specjLazyLoad;
private boolean allowLoadOutsideTransaction;
/**
* For serialization from the non-pojo initializers (HHH-3309)
@ -148,7 +149,7 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
@Override
public final void unsetSession() {
prepareForPossibleSpecialSpecjInitialization();
prepareForPossibleLoadingOutsideTransaction();
session = null;
readOnly = false;
readOnlyBeforeAttachedToSession = null;
@ -157,8 +158,8 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
@Override
public final void initialize() throws HibernateException {
if ( !initialized ) {
if ( specjLazyLoad ) {
specialSpecjInitialization();
if ( allowLoadOutsideTransaction ) {
permissiveInitialization();
}
else if ( session == null ) {
throw new LazyInitializationException( "could not initialize proxy - no Session" );
@ -180,7 +181,7 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
}
}
protected void specialSpecjInitialization() {
protected void permissiveInitialization() {
if ( session == null ) {
//we have a detached collection thats set to null, reattach
if ( sessionFactoryUuid == null ) {
@ -190,9 +191,9 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
SessionFactoryImplementor sf = (SessionFactoryImplementor)
SessionFactoryRegistry.INSTANCE.getSessionFactory( sessionFactoryUuid );
SessionImplementor session = (SessionImplementor) sf.openSession();
// TODO: On the next major release, add an
// 'isJTA' or 'getTransactionFactory' method to Session.
session.getPersistenceContext().setDefaultReadOnly( true );
session.setFlushMode( FlushMode.MANUAL );
boolean isJTA = session.getTransactionCoordinator()
.getTransactionContext().getTransactionEnvironment()
.getTransactionFactory()
@ -240,11 +241,11 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
}
}
protected void prepareForPossibleSpecialSpecjInitialization() {
protected void prepareForPossibleLoadingOutsideTransaction() {
if ( session != null ) {
specjLazyLoad = session.getFactory().getSettings().isInitializeLazyStateOutsideTransactionsEnabled();
allowLoadOutsideTransaction = session.getFactory().getSettings().isInitializeLazyStateOutsideTransactionsEnabled();
if ( specjLazyLoad && sessionFactoryUuid == null ) {
if ( allowLoadOutsideTransaction && sessionFactoryUuid == null ) {
try {
sessionFactoryUuid = (String) session.getFactory().getReference().get( "uuid" ).getContent();
}

View File

@ -1,3 +1,26 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.lazyload;
import javax.persistence.CascadeType;

View File

@ -0,0 +1,123 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.lazyload;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.transaction.internal.jta.JtaTransactionFactory;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.jta.TestingJtaBootstrap;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
/**
* @author Oleksander Dukhno
*/
public class JtaLazyLoadingTest
extends BaseCoreFunctionalTestCase {
private static final int CHILDREN_SIZE = 3;
private Long parentID;
private Long lastChildID;
protected void configure(Configuration cfg) {
super.configure( cfg );
cfg.setProperty( Environment.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
TestingJtaBootstrap.prepare( cfg.getProperties() );
cfg.setProperty( Environment.TRANSACTION_STRATEGY, JtaTransactionFactory.class.getName() );
}
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Parent.class,
Child.class
};
}
protected void prepareTest()
throws Exception {
Session s = openSession();
s.beginTransaction();
Parent p = new Parent();
for ( int i = 0; i < CHILDREN_SIZE; i++ ) {
final Child child = p.makeChild();
s.persist( child );
lastChildID = child.getId();
}
s.persist( p );
parentID = p.getId();
s.getTransaction().commit();
s.clear();
s.close();
}
@Test
@TestForIssue(jiraKey = "HHH-7971")
public void testLazyCollectionLoadingAfterEndTransaction() {
Session s = openSession();
s.beginTransaction();
Parent loadedParent = (Parent) s.load( Parent.class, parentID );
s.getTransaction().commit();
s.close();
assertFalse( Hibernate.isInitialized( loadedParent.getChildren() ) );
int i = 0;
for ( Child child : loadedParent.getChildren() ) {
i++;
assertNotNull( child );
}
assertEquals( CHILDREN_SIZE, i );
s = openSession();
s.beginTransaction();
Child loadedChild = (Child) s.load( Child.class, lastChildID );
s.getTransaction().commit();
s.close();
Parent p = loadedChild.getParent();
int j = 0;
for ( Child child : p.getChildren() ) {
j++;
assertNotNull( child );
}
assertEquals( CHILDREN_SIZE, j );
}
}

View File

@ -1,18 +1,43 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.lazyload;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
/**
* @author Oleksander Dukhno
@ -27,8 +52,10 @@ public class LazyLoadingTest
protected void configure(Configuration cfg) {
super.configure( cfg );
cfg.setProperty( Environment.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false" );
}
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Parent.class,
@ -41,15 +68,12 @@ public class LazyLoadingTest
Session s = openSession();
s.beginTransaction();
List<Child> children = new ArrayList<Child>();
for ( int i = 0; i < CHILDREN_SIZE; i++ ) {
Child c = new Child();
s.persist( c );
lastChildID = c.getId();
children.add( c );
}
Parent p = new Parent();
p.setChildren( children );
for ( int i = 0; i < CHILDREN_SIZE; i++ ) {
final Child child = p.makeChild();
s.persist( child );
lastChildID = child.getId();
}
s.persist( p );
parentID = p.getId();
@ -63,12 +87,14 @@ public class LazyLoadingTest
public void testLazyCollectionLoadingAfterEndTransaction() {
Session s = openSession();
s.beginTransaction();
Parent loadedPatent = (Parent) s.load( Parent.class, parentID );
Parent loadedParent = (Parent) s.load( Parent.class, parentID );
s.getTransaction().commit();
s.close();
assertFalse( Hibernate.isInitialized( loadedParent.getChildren() ) );
int i = 0;
for ( Child child : loadedPatent.getChildren() ) {
for ( Child child : loadedParent.getChildren() ) {
i++;
assertNotNull( child );
}

View File

@ -1,5 +1,30 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.lazyload;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
@ -7,8 +32,6 @@ import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.ArrayList;
import java.util.List;
/**
* @author Oleksander Dukhno
@ -36,8 +59,13 @@ public class Parent {
public void setChildren(List<Child> children) {
this.children = children;
for ( Child c : children ) {
c.setParent( this );
}
}
Child makeChild() {
final Child c = new Child();
c.setParent( this );
this.children.add( c );
return c;
}
}