Merge branch 'master' of github.com:hibernate/hibernate-core
This commit is contained in:
commit
a6d19f257b
|
@ -1141,15 +1141,20 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
final CollectionPersister collectionPersister = session.getFactory().getCollectionPersister( collectionRole );
|
||||
|
||||
// try cache lookup first
|
||||
Object parent = parentsByChild.get(childEntity);
|
||||
if (parent != null) {
|
||||
if (isFoundInParent(propertyName, childEntity, persister, collectionPersister, parent)) {
|
||||
return getEntry(parent).getId();
|
||||
}
|
||||
else {
|
||||
parentsByChild.remove(childEntity); // remove wrong entry
|
||||
}
|
||||
Object parent = parentsByChild.get( childEntity );
|
||||
if ( parent != null ) {
|
||||
final EntityEntry entityEntry = ( EntityEntry ) entityEntries.get( parent );
|
||||
//there maybe more than one parent, filter by type
|
||||
if ( persister.isSubclassEntityName(entityEntry.getEntityName() )
|
||||
&& isFoundInParent( propertyName, childEntity, persister, collectionPersister, parent ) ) {
|
||||
return getEntry( parent ).getId();
|
||||
}
|
||||
else {
|
||||
parentsByChild.remove( childEntity ); // remove wrong entry
|
||||
}
|
||||
}
|
||||
|
||||
//not found in case, proceed
|
||||
// iterate all the entities currently associated with the persistence context.
|
||||
Iterator entities = IdentityMap.entries(entityEntries).iterator();
|
||||
while ( entities.hasNext() ) {
|
||||
|
@ -1257,21 +1262,28 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
// try cache lookup first
|
||||
Object parent = parentsByChild.get(childEntity);
|
||||
if (parent != null) {
|
||||
Object index = getIndexInParent(property, childEntity, persister, cp, parent);
|
||||
|
||||
if (index==null && mergeMap!=null) {
|
||||
Object unmergedInstance = mergeMap.get(parent);
|
||||
Object unmergedChild = mergeMap.get(childEntity);
|
||||
if ( unmergedInstance!=null && unmergedChild!=null ) {
|
||||
index = getIndexInParent(property, unmergedChild, persister, cp, unmergedInstance);
|
||||
final EntityEntry entityEntry = (EntityEntry) entityEntries.get(parent);
|
||||
//there maybe more than one parent, filter by type
|
||||
if ( persister.isSubclassEntityName( entityEntry.getEntityName() ) ) {
|
||||
Object index = getIndexInParent(property, childEntity, persister, cp, parent);
|
||||
|
||||
if (index==null && mergeMap!=null) {
|
||||
Object unmergedInstance = mergeMap.get(parent);
|
||||
Object unmergedChild = mergeMap.get(childEntity);
|
||||
if ( unmergedInstance!=null && unmergedChild!=null ) {
|
||||
index = getIndexInParent(property, unmergedChild, persister, cp, unmergedInstance);
|
||||
}
|
||||
}
|
||||
if (index!=null) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
if (index!=null) {
|
||||
return index;
|
||||
else {
|
||||
parentsByChild.remove(childEntity); // remove wrong entry
|
||||
}
|
||||
parentsByChild.remove(childEntity); // remove wrong entry
|
||||
}
|
||||
|
||||
|
||||
//Not found in cache, proceed
|
||||
Iterator entities = IdentityMap.entries(entityEntries).iterator();
|
||||
while ( entities.hasNext() ) {
|
||||
Map.Entry me = (Map.Entry) entities.next();
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package org.hibernate.test.annotations.engine.collection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OrderColumn;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.Cascade;
|
||||
import org.hibernate.annotations.CascadeType;
|
||||
|
||||
/**
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "co_father")
|
||||
public class Father {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public Integer getId() { return id; }
|
||||
public void setId(Integer id) { this.id = id; }
|
||||
private Integer id;
|
||||
|
||||
@OneToMany
|
||||
@OrderColumn(name = "son_arriv")
|
||||
@JoinColumn(name = "father_id", nullable = false)
|
||||
@Cascade({ CascadeType.SAVE_UPDATE })
|
||||
public List<Son> getOrderedSons() { return orderedSons; }
|
||||
public void setOrderedSons(List<Son> orderedSons) { this.orderedSons = orderedSons; }
|
||||
private List<Son> orderedSons = new ArrayList<Son>( );
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package org.hibernate.test.annotations.engine.collection;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.Cascade;
|
||||
import org.hibernate.annotations.CascadeType;
|
||||
|
||||
/**
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "co_mother")
|
||||
public class Mother {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public Integer getId() { return id; }
|
||||
public void setId(Integer id) { this.id = id; }
|
||||
private Integer id;
|
||||
|
||||
@OneToMany(mappedBy = "mother")
|
||||
@Cascade({ CascadeType.SAVE_UPDATE })
|
||||
public Set<Son> getSons() { return sons; }
|
||||
public void setSons(Set<Son> sons) { this.sons = sons; }
|
||||
private Set<Son> sons = new HashSet<Son>();
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package org.hibernate.test.annotations.engine.collection;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
@Entity
|
||||
@Table(name="co_son")
|
||||
public class Son {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public Integer getId() { return id; }
|
||||
public void setId(Integer id) { this.id = id; }
|
||||
private Integer id;
|
||||
|
||||
@ManyToOne(optional = false) @JoinColumn(name = "father_id", insertable = false, updatable = false, nullable = false)
|
||||
public Father getFather() { return father; }
|
||||
public void setFather(Father father) { this.father = father; }
|
||||
private Father father;
|
||||
|
||||
@ManyToOne
|
||||
public Mother getMother() { return mother; }
|
||||
public void setMother(Mother mother) { this.mother = mother; }
|
||||
private Mother mother;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package org.hibernate.test.annotations.engine.collection;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.test.annotations.TestCase;
|
||||
|
||||
/**
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public class UnidirCollectionWithMultipleOwnerTest extends TestCase {
|
||||
|
||||
public void testUnidirCollectionWithMultipleOwner() throws Exception {
|
||||
Session s = openSession();
|
||||
Transaction tx;
|
||||
tx = s.beginTransaction();
|
||||
Father father = new Father();
|
||||
Mother mother = new Mother();
|
||||
s.save( father );
|
||||
//s.save( mother );
|
||||
Son son = new Son();
|
||||
father.getOrderedSons().add( son );
|
||||
son.setFather( father );
|
||||
mother.getSons().add( son );
|
||||
son.setMother( mother );
|
||||
s.save( mother );
|
||||
s.save( father );
|
||||
tx.commit();
|
||||
|
||||
s.clear();
|
||||
|
||||
tx = s.beginTransaction();
|
||||
son = (Son) s.get( Son.class, son.getId() );
|
||||
s.delete( son );
|
||||
s.flush();
|
||||
father = (Father) s.get( Father.class, father.getId() );
|
||||
mother = (Mother) s.get( Mother.class, mother.getId() );
|
||||
s.delete( father );
|
||||
s.delete( mother );
|
||||
tx.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Father.class,
|
||||
Mother.class,
|
||||
Son.class
|
||||
};
|
||||
}
|
||||
}
|
|
@ -280,11 +280,11 @@ public class AuditReaderImpl implements AuditReaderImplementor {
|
|||
entity = ((HibernateProxy)entity).getHibernateLazyInitializer().getImplementation();
|
||||
}
|
||||
if(firstLevelCache.containsEntityName(primaryKey, revision, entity)) {
|
||||
// it´s on envers FLC!
|
||||
// it's on envers FLC!
|
||||
return firstLevelCache.getFromEntityNameCache(primaryKey, revision, entity);
|
||||
} else {
|
||||
throw new HibernateException(
|
||||
"Envers can´t resolve entityName for historic entity. The id, revision and entity is not on envers first level cache.");
|
||||
"Envers can't resolve entityName for historic entity. The id, revision and entity is not on envers first level cache.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -84,8 +84,7 @@ public class TimestampsRegionImpl extends BaseGeneralDataRegion implements Times
|
|||
try {
|
||||
// We ensure ASYNC semantics (JBCACHE-1175) and make sure previous
|
||||
// value is not loaded from cache store cos it's not needed.
|
||||
cacheAdapter.withFlags(FlagAdapter.FORCE_ASYNCHRONOUS,
|
||||
FlagAdapter.SKIP_CACHE_LOAD).put(key, value);
|
||||
cacheAdapter.withFlags(FlagAdapter.FORCE_ASYNCHRONOUS).put(key, value);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
} finally {
|
||||
|
|
|
@ -101,27 +101,25 @@ public interface CacheAdapter {
|
|||
Object getAllowingTimeout(Object key) throws CacheException;
|
||||
|
||||
/**
|
||||
* Performs a <code>put(Object, Object)</code> on the cache, wrapping any exception in a {@link CacheException}.
|
||||
* Performs a <code>put(Object, Object)</code> on the cache,
|
||||
* wrapping any exception in a {@link CacheException}.
|
||||
*
|
||||
* @param key key whose value will be modified
|
||||
* @param value data to store in the cache entry
|
||||
* @return the previous value associated with <tt>key</tt>, or <tt>null</tt>
|
||||
* if there was no mapping for <tt>key</tt>.
|
||||
* @throws CacheException
|
||||
*/
|
||||
Object put(Object key, Object value) throws CacheException;
|
||||
void put(Object key, Object value) throws CacheException;
|
||||
|
||||
/**
|
||||
* Performs a <code>put(Object, Object)</code> on the cache ignoring any {@link TimeoutException}
|
||||
* and wrapping any exception in a {@link CacheException}.
|
||||
* Performs a <code>put(Object, Object)</code> on the cache ignoring
|
||||
* any {@link TimeoutException} and wrapping any exception in a
|
||||
* {@link CacheException}.
|
||||
*
|
||||
* @param key key whose value will be modified
|
||||
* @param value data to store in the cache entry
|
||||
* @return the previous value associated with <tt>key</tt>, or <tt>null</tt>
|
||||
* if there was no mapping for <tt>key</tt>.
|
||||
* @throws CacheException
|
||||
*/
|
||||
Object putAllowingTimeout(Object key, Object value) throws CacheException;
|
||||
void putAllowingTimeout(Object key, Object value) throws CacheException;
|
||||
|
||||
/**
|
||||
* See {@link Cache#putForExternalRead(Object, Object)} for detailed documentation.
|
||||
|
@ -133,14 +131,13 @@ public interface CacheAdapter {
|
|||
void putForExternalRead(Object key, Object value) throws CacheException;
|
||||
|
||||
/**
|
||||
* Performs a <code>remove(Object)</code>, wrapping any exception in a {@link CacheException}.
|
||||
* Performs a <code>remove(Object)</code>, wrapping any exception in
|
||||
* a {@link CacheException}.
|
||||
*
|
||||
* @param key key to be removed
|
||||
* @return the previous value associated with <tt>key</tt>, or
|
||||
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
|
||||
* @throws CacheException
|
||||
*/
|
||||
Object remove(Object key) throws CacheException;
|
||||
void remove(Object key) throws CacheException;
|
||||
|
||||
/**
|
||||
* Evict the given key from memory.
|
||||
|
|
|
@ -94,20 +94,21 @@ public class CacheAdapterImpl implements CacheAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
public Object put(Object key, Object value) throws CacheException {
|
||||
public void put(Object key, Object value) throws CacheException {
|
||||
try {
|
||||
return cache.put(key, value);
|
||||
// No previous value interest, so apply flags that avoid remote lookups.
|
||||
getSkipRemoteGetLoadCache().put(key, value);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Object putAllowingTimeout(Object key, Object value) throws CacheException {
|
||||
public void putAllowingTimeout(Object key, Object value) throws CacheException {
|
||||
try {
|
||||
return getFailSilentCache().put(key, value);
|
||||
// No previous value interest, so apply flags that avoid remote lookups.
|
||||
getFailSilentCacheSkipRemotes().put(key, value);
|
||||
} catch (TimeoutException allowed) {
|
||||
// ignore it
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
|
@ -115,15 +116,17 @@ public class CacheAdapterImpl implements CacheAdapter {
|
|||
|
||||
public void putForExternalRead(Object key, Object value) throws CacheException {
|
||||
try {
|
||||
cache.putForExternalRead(key, value);
|
||||
// No previous value interest, so apply flags that avoid remote lookups.
|
||||
getFailSilentCacheSkipRemotes().putForExternalRead(key, value);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Object remove(Object key) throws CacheException {
|
||||
public void remove(Object key) throws CacheException {
|
||||
try {
|
||||
return cache.remove(key);
|
||||
// No previous value interest, so apply flags that avoid remote lookups.
|
||||
getSkipRemoteGetLoadCache().remove(key);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
|
@ -214,4 +217,15 @@ public class CacheAdapterImpl implements CacheAdapter {
|
|||
private Cache getFailSilentCache() {
|
||||
return cache.getAdvancedCache().withFlags(Flag.FAIL_SILENTLY);
|
||||
}
|
||||
|
||||
private Cache getSkipRemoteGetLoadCache() {
|
||||
return cache.getAdvancedCache().withFlags(
|
||||
Flag.SKIP_CACHE_LOAD, Flag.SKIP_REMOTE_LOOKUP);
|
||||
}
|
||||
|
||||
private Cache getFailSilentCacheSkipRemotes() {
|
||||
return cache.getAdvancedCache().withFlags(
|
||||
Flag.FAIL_SILENTLY, Flag.SKIP_CACHE_LOAD, Flag.SKIP_REMOTE_LOOKUP);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -48,14 +48,14 @@ public class CacheHelper {
|
|||
private CacheHelper() {
|
||||
}
|
||||
|
||||
public static void initInternalEvict(CacheAdapter cacheAdapter, AddressAdapter member) {
|
||||
public static void initInternalEvict(CacheAdapter cache, AddressAdapter member) {
|
||||
EvictAll eKey = new EvictAll(member == null ? NoAddress.INSTANCE : member);
|
||||
cacheAdapter.withFlags(FlagAdapter.CACHE_MODE_LOCAL, FlagAdapter.SKIP_CACHE_LOAD).put(eKey, Internal.INIT);
|
||||
cache.withFlags(FlagAdapter.CACHE_MODE_LOCAL).put(eKey, Internal.INIT);
|
||||
}
|
||||
|
||||
public static void sendEvictAllNotification(CacheAdapter cacheAdapter, AddressAdapter member) {
|
||||
public static void sendEvictAllNotification(CacheAdapter cache, AddressAdapter member) {
|
||||
EvictAll eKey = new EvictAll(member == null ? NoAddress.INSTANCE : member);
|
||||
cacheAdapter.withFlags(FlagAdapter.SKIP_CACHE_LOAD).put(eKey, Internal.EVICT);
|
||||
cache.put(eKey, Internal.EVICT);
|
||||
}
|
||||
|
||||
public static boolean isEvictAllNotification(Object key) {
|
||||
|
|
|
@ -4,4 +4,5 @@ dependencies {
|
|||
compile( project( ':hibernate-core' ) )
|
||||
compile( [group: 'proxool', name: 'proxool', version: '0.8.3'] )
|
||||
testCompile( project(':hibernate-core').sourceSets.test.classes )
|
||||
testRuntime( libraries.h2 )
|
||||
}
|
||||
|
|
|
@ -202,7 +202,12 @@ public class ProxoolConnectionProvider implements ConnectionProvider {
|
|||
|
||||
// We have created the pool ourselves, so shut it down
|
||||
try {
|
||||
ProxoolFacade.shutdown(0);
|
||||
if ( ProxoolFacade.getAliases().length == 1 ) {
|
||||
ProxoolFacade.shutdown( 0 );
|
||||
}
|
||||
else {
|
||||
ProxoolFacade.removeConnectionPool(proxoolAlias.substring(PROXOOL_JDBC_STEM.length()));
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
// If you're closing down the ConnectionProvider chances are an
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010, Red Hat, Inc. and/or its affiliates 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.service.jdbc.connections.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.logicalcobwebs.proxool.ProxoolFacade;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Test to verify connection pools are closed, and that only the managed one is closed.
|
||||
* @author Sanne Grinovero
|
||||
*/
|
||||
public class ProxoolConnectionProviderTest extends TestCase {
|
||||
|
||||
public void testPoolsClosed() {
|
||||
assertDefinedPools(); // zero-length-vararg used as parameter
|
||||
|
||||
ProxoolConnectionProvider providerOne = new ProxoolConnectionProvider();
|
||||
providerOne.configure( getPoolConfigurarion( "pool-one" ) );
|
||||
assertDefinedPools( "pool-one" );
|
||||
|
||||
ProxoolConnectionProvider providerTwo = new ProxoolConnectionProvider();
|
||||
providerTwo.configure( getPoolConfigurarion( "pool-two" ) );
|
||||
assertDefinedPools( "pool-one", "pool-two" );
|
||||
|
||||
providerOne.close();
|
||||
assertDefinedPools( "pool-two" );
|
||||
|
||||
providerTwo.close();
|
||||
assertDefinedPools();
|
||||
}
|
||||
|
||||
private void assertDefinedPools(String... expectedPoolNames) {
|
||||
List<String> aliases = Arrays.asList( ProxoolFacade.getAliases() );
|
||||
assertEquals( expectedPoolNames.length, aliases.size() );
|
||||
for (String poolName : expectedPoolNames) {
|
||||
assertTrue( "pool named " + poolName + " missing", aliases.contains( poolName ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pool name
|
||||
* @return his configuration - see src/tests/resources for matches
|
||||
*/
|
||||
private Properties getPoolConfigurarion(String poolName) {
|
||||
Properties cfg = new Properties();
|
||||
cfg.setProperty( Environment.PROXOOL_POOL_ALIAS, poolName );
|
||||
cfg.setProperty( Environment.PROXOOL_PROPERTIES, poolName + ".properties" );
|
||||
return cfg;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
jdbc-0.proxool.alias=pool-one
|
||||
jdbc-0.proxool.driver-url=jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE
|
||||
jdbc-0.proxool.driver-class=org.h2.Driver
|
||||
jdbc-0.user=sa
|
||||
jdbc-0.password=
|
||||
jdbc-0.proxool.maximum-connection-count=2
|
||||
jdbc-0.proxool.house-keeping-test-sql=select CURRENT_DATE
|
|
@ -0,0 +1,7 @@
|
|||
jdbc-0.proxool.alias=pool-two
|
||||
jdbc-0.proxool.driver-url=jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE
|
||||
jdbc-0.proxool.driver-class=org.h2.Driver
|
||||
jdbc-0.user=sa
|
||||
jdbc-0.password=
|
||||
jdbc-0.proxool.maximum-connection-count=2
|
||||
jdbc-0.proxool.house-keeping-test-sql=select CURRENT_DATE
|
Loading…
Reference in New Issue