HHH-10770 JCache provider updates
* Steer away from EntryProcessor * Add tests
This commit is contained in:
parent
a872885a43
commit
2ddefd615b
|
@ -12,6 +12,7 @@ import org.jboss.logging.annotations.MessageLogger;
|
|||
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
|
||||
import static org.jboss.logging.Logger.Level.ERROR;
|
||||
import static org.jboss.logging.Logger.Level.WARN;
|
||||
|
||||
/**
|
||||
|
@ -36,4 +37,12 @@ public interface JCacheMessageLogger extends CoreMessageLogger {
|
|||
id = NAMESPACE + 2
|
||||
)
|
||||
void attemptToRestopAlreadyStoppedJCacheProvider();
|
||||
|
||||
@LogMessage(level = ERROR)
|
||||
@Message(
|
||||
value = "Cache: %s Key: %s Lockable: %s. A soft-locked cache entry was missing. This is either"
|
||||
+ " out of balance lock/unlock sequences, or an eagerly evicting cache.",
|
||||
id = NAMESPACE + 3
|
||||
)
|
||||
void missingLock(JCacheRegion region, Object key, Object value);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.jboss.logging.Logger;
|
|||
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.jcache.time.Timestamper;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
|
@ -187,11 +188,11 @@ public class JCacheRegionFactory implements RegionFactory {
|
|||
}
|
||||
|
||||
static long nextTS() {
|
||||
return System.currentTimeMillis() / 100;
|
||||
return Timestamper.next();
|
||||
}
|
||||
|
||||
static int timeOut() {
|
||||
return (int) (TimeUnit.SECONDS.toMillis(60) / 100);
|
||||
return (int) TimeUnit.SECONDS.toMillis( 60 ) * Timestamper.ONE_MS;
|
||||
}
|
||||
|
||||
private String getProp(Properties properties, String prop) {
|
||||
|
|
|
@ -9,7 +9,6 @@ package org.hibernate.cache.jcache;
|
|||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
import javax.cache.Cache;
|
||||
import javax.cache.processor.EntryProcessor;
|
||||
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
|
@ -33,17 +32,19 @@ public class JCacheTransactionalDataRegion extends JCacheRegion implements Trans
|
|||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAware() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheDataDescription getCacheDataDescription() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
protected void throwIfAccessTypeUnsupported(AccessType accessType) {
|
||||
if ( supportedAccessTypes().contains( accessType ) ) {
|
||||
throw new UnsupportedOperationException( "This doesn't JCacheTransactionalDataRegion doesn't support " + accessType );
|
||||
if ( !supportedAccessTypes().contains( accessType ) ) {
|
||||
throw new UnsupportedOperationException( "JCacheTransactionalDataRegion doesn't support " + accessType );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,12 +68,15 @@ public class JCacheTransactionalDataRegion extends JCacheRegion implements Trans
|
|||
cache.put( key, value );
|
||||
}
|
||||
|
||||
public boolean putIfAbsent(Object key, Object value) {
|
||||
return cache.putIfAbsent( key, value );
|
||||
}
|
||||
|
||||
public boolean replace(Object key, Object expected, Object value) {
|
||||
return cache.replace( key, expected, value );
|
||||
}
|
||||
|
||||
public SessionFactoryOptions getSessionFactoryOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public <T> T invoke(Object key, EntryProcessor<Object, Object, T> entryProcessor, Object... args) {
|
||||
return cache.invoke( key, entryProcessor, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,23 +11,29 @@ import java.io.Serializable;
|
|||
import java.util.Comparator;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import javax.cache.processor.EntryProcessor;
|
||||
import javax.cache.processor.EntryProcessorException;
|
||||
import javax.cache.processor.MutableEntry;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.jcache.JCacheMessageLogger;
|
||||
import org.hibernate.cache.jcache.JCacheTransactionalDataRegion;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Alex Snaps
|
||||
*/
|
||||
public class AbstractReadWriteRegionAccessStrategy<R extends JCacheTransactionalDataRegion> {
|
||||
abstract class AbstractReadWriteRegionAccessStrategy<R extends JCacheTransactionalDataRegion> {
|
||||
|
||||
private static final JCacheMessageLogger LOG = Logger.getMessageLogger(
|
||||
JCacheMessageLogger.class,
|
||||
AbstractReadWriteRegionAccessStrategy.class.getName()
|
||||
);
|
||||
|
||||
protected final R region;
|
||||
protected final Comparator versionComparator;
|
||||
private final UUID uuid = UUID.randomUUID();
|
||||
private final AtomicLong nextLockId = new AtomicLong();
|
||||
private final AtomicLong nextItemId = new AtomicLong();
|
||||
|
||||
public AbstractReadWriteRegionAccessStrategy(R region) {
|
||||
this.versionComparator = region.getCacheDataDescription().getVersionComparator();
|
||||
|
@ -51,26 +57,29 @@ public class AbstractReadWriteRegionAccessStrategy<R extends JCacheTransactional
|
|||
}
|
||||
|
||||
public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||
return region.invoke(
|
||||
key, new EntryProcessor<Object, Object, Boolean>() {
|
||||
@Override
|
||||
public Boolean process(MutableEntry<Object, Object> entry, Object... args)
|
||||
throws EntryProcessorException {
|
||||
final Lockable item = (Lockable) entry.getValue();
|
||||
final boolean writeable = item == null || item.isWriteable(
|
||||
(Long) args[1],
|
||||
args[2],
|
||||
versionComparator
|
||||
);
|
||||
if ( writeable ) {
|
||||
entry.setValue( new Item( args[0], args[2], region.nextTimestamp() ) );
|
||||
while (true) {
|
||||
Lockable item = (Lockable) region.get( key );
|
||||
|
||||
if (item == null) {
|
||||
/*
|
||||
* If the item is null due a softlock being evicted... then this
|
||||
* is wrong, the in-doubt soft-lock could get replaced with the
|
||||
* old value. All that can be done from a JCache perspective is
|
||||
* to log a warning.
|
||||
*/
|
||||
if (region.putIfAbsent( key, new Item( value, version, txTimestamp, nextItemId() ))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (item.isWriteable( txTimestamp, version, versionComparator )) {
|
||||
if (region.replace( key, item, new Item( value, version, txTimestamp, nextItemId() ))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}, value, txTimestamp, version);
|
||||
}
|
||||
|
||||
public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
|
@ -79,49 +88,47 @@ public class AbstractReadWriteRegionAccessStrategy<R extends JCacheTransactional
|
|||
}
|
||||
|
||||
public SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) throws CacheException {
|
||||
return region.invoke(
|
||||
key, new EntryProcessor<Object, Object, SoftLock>() {
|
||||
@Override
|
||||
public SoftLock process(MutableEntry<Object, Object> entry, Object... args)
|
||||
throws EntryProcessorException {
|
||||
final Lockable item = (Lockable) entry.getValue();
|
||||
final long timeout = region.nextTimestamp() + region.getTimeout();
|
||||
final Lock lock = ( item == null ) ? new Lock(
|
||||
timeout,
|
||||
(UUID) args[0],
|
||||
(Long) args[1],
|
||||
args[2]
|
||||
)
|
||||
: item.lock( timeout, (UUID) args[0], (Long) args[1] );
|
||||
entry.setValue( lock );
|
||||
long timeout = region.nextTimestamp() + region.getTimeout();
|
||||
while (true) {
|
||||
Lockable item = (Lockable) region.get( key );
|
||||
|
||||
if ( item == null ) {
|
||||
/*
|
||||
* What happens here if a previous soft-lock was evicted to make
|
||||
* this null.
|
||||
*/
|
||||
Lock lock = new Lock(timeout, uuid, nextLockId(), version);
|
||||
if (region.putIfAbsent( key, lock )) {
|
||||
return lock;
|
||||
}
|
||||
}, uuid, nextLockId(), version
|
||||
);
|
||||
}
|
||||
else {
|
||||
Lock lock = item.lock( timeout, uuid, nextLockId() );
|
||||
if (region.replace(key, item, lock)) {
|
||||
return lock;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
region.invoke(
|
||||
key, new EntryProcessor<Object, Object, Void>() {
|
||||
@Override
|
||||
public Void process(MutableEntry<Object, Object> entry, Object... args)
|
||||
throws EntryProcessorException {
|
||||
final Lockable item = (Lockable) entry.getValue();
|
||||
while (true) {
|
||||
Lockable item = (Lockable) region.get( key );
|
||||
|
||||
if ( (item != null) && item.isUnlockable( (SoftLock) args[0] ) ) {
|
||||
( (Lock) item ).unlock( region.nextTimestamp() );
|
||||
entry.setValue( item );
|
||||
if (item != null && item.isUnlockable( lock )) {
|
||||
if (region.replace(key, item, ((Lock) item ).unlock(region.nextTimestamp()))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
entry.setValue( null );
|
||||
handleMissingLock( key, item );
|
||||
return;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, lock);
|
||||
}
|
||||
|
||||
public void remove(SharedSessionContractImplementor session, Object key) throws CacheException {
|
||||
region.remove( key );
|
||||
//this access strategy is asynchronous
|
||||
}
|
||||
|
||||
public void removeAll() throws CacheException {
|
||||
|
@ -141,13 +148,25 @@ public class AbstractReadWriteRegionAccessStrategy<R extends JCacheTransactional
|
|||
}
|
||||
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
throw new UnsupportedOperationException( "JCache doesn't support region locking" );
|
||||
region.clear();
|
||||
}
|
||||
|
||||
private long nextLockId() {
|
||||
return nextLockId.getAndIncrement();
|
||||
}
|
||||
|
||||
protected long nextItemId() {
|
||||
return nextItemId.getAndIncrement();
|
||||
}
|
||||
|
||||
protected void handleMissingLock(Object key, Lockable lock) {
|
||||
LOG.missingLock( region, key, lock );
|
||||
long ts = region.nextTimestamp() + region.getTimeout();
|
||||
// create new lock that times out immediately
|
||||
Lock newLock = new Lock( ts, uuid, nextLockId.getAndIncrement(), null ).unlock( ts );
|
||||
region.put( key, newLock );
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface type implemented by all wrapper objects in the cache.
|
||||
*/
|
||||
|
@ -189,14 +208,16 @@ public class AbstractReadWriteRegionAccessStrategy<R extends JCacheTransactional
|
|||
private final Object value;
|
||||
private final Object version;
|
||||
private final long timestamp;
|
||||
private final long itemId;
|
||||
|
||||
/**
|
||||
* Creates an unlocked item wrapping the given value with a version and creation timestamp.
|
||||
*/
|
||||
Item(Object value, Object version, long timestamp) {
|
||||
Item(Object value, Object version, long timestamp, long itemId) {
|
||||
this.value = value;
|
||||
this.version = version;
|
||||
this.timestamp = timestamp;
|
||||
this.itemId = itemId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -224,6 +245,29 @@ public class AbstractReadWriteRegionAccessStrategy<R extends JCacheTransactional
|
|||
public Lock lock(long timeout, UUID uuid, long lockId) {
|
||||
return new Lock( timeout, uuid, lockId, version );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
else if (obj instanceof Item) {
|
||||
return itemId == ((Item) obj).itemId;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Long.hashCode( itemId );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value.toString() + " version: " + version;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -236,19 +280,28 @@ public class AbstractReadWriteRegionAccessStrategy<R extends JCacheTransactional
|
|||
private final long lockId;
|
||||
private final Object version;
|
||||
|
||||
private long timeout;
|
||||
private boolean concurrent;
|
||||
private int multiplicity = 1;
|
||||
private long unlockTimestamp;
|
||||
private final long timeout;
|
||||
private final boolean concurrent;
|
||||
private final int multiplicity;
|
||||
private final long unlockTimestamp;
|
||||
|
||||
/**
|
||||
* Creates a locked item with the given identifiers and object version.
|
||||
*/
|
||||
public Lock(long timeout, UUID sourceUuid, long lockId, Object version) {
|
||||
this.timeout = timeout;
|
||||
this(timeout, sourceUuid, lockId, version, 0, 1, false);
|
||||
}
|
||||
|
||||
private Lock(long timeout, UUID sourceUuid, long lockId, Object version,
|
||||
long unlockTimestamp, int multiplicity, boolean concurrent) {
|
||||
this.sourceUuid = sourceUuid;
|
||||
this.lockId = lockId;
|
||||
this.version = version;
|
||||
this.sourceUuid = sourceUuid;
|
||||
|
||||
this.timeout = timeout;
|
||||
this.unlockTimestamp = unlockTimestamp;
|
||||
this.multiplicity = multiplicity;
|
||||
this.concurrent = concurrent;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -279,7 +332,15 @@ public class AbstractReadWriteRegionAccessStrategy<R extends JCacheTransactional
|
|||
|
||||
@Override
|
||||
public boolean isUnlockable(SoftLock lock) {
|
||||
return equals( lock );
|
||||
if ( lock == this ) {
|
||||
return true;
|
||||
}
|
||||
else if ( lock instanceof Lock ) {
|
||||
return (lockId == ((Lock) lock).lockId) && sourceUuid.equals(((Lock) lock).sourceUuid);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -289,7 +350,8 @@ public class AbstractReadWriteRegionAccessStrategy<R extends JCacheTransactional
|
|||
return true;
|
||||
}
|
||||
else if ( o instanceof Lock ) {
|
||||
return ( lockId == ( (Lock) o ).lockId ) && sourceUuid.equals( ( (Lock) o ).sourceUuid );
|
||||
return (lockId == ((Lock)o ).lockId) && sourceUuid.equals( ( (Lock) o ).sourceUuid )
|
||||
&& (multiplicity == ((Lock) o).multiplicity);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
|
@ -299,11 +361,7 @@ public class AbstractReadWriteRegionAccessStrategy<R extends JCacheTransactional
|
|||
@Override
|
||||
public int hashCode() {
|
||||
final int hash = ( sourceUuid != null ? sourceUuid.hashCode() : 0 );
|
||||
int temp = (int) lockId;
|
||||
for ( int i = 1; i < Long.SIZE / Integer.SIZE; i++ ) {
|
||||
temp ^= ( lockId >>> ( i * Integer.SIZE ) );
|
||||
}
|
||||
return hash + temp;
|
||||
return hash ^ Long.hashCode( lockId );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -315,18 +373,22 @@ public class AbstractReadWriteRegionAccessStrategy<R extends JCacheTransactional
|
|||
|
||||
@Override
|
||||
public Lock lock(long timeout, UUID uuid, long lockId) {
|
||||
concurrent = true;
|
||||
multiplicity++;
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
return new Lock( timeout, this.sourceUuid, this.lockId, this.version,
|
||||
0, this.multiplicity + 1, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks this Lock, and timestamps the unlock event.
|
||||
*/
|
||||
public void unlock(long timestamp) {
|
||||
if ( --multiplicity == 0 ) {
|
||||
unlockTimestamp = timestamp;
|
||||
public Lock unlock(long timestamp) {
|
||||
if (multiplicity == 1) {
|
||||
return new Lock(timeout, sourceUuid, lockId, version,
|
||||
timestamp, 0, concurrent );
|
||||
|
||||
}
|
||||
else {
|
||||
return new Lock(timeout, sourceUuid, lockId, version,
|
||||
0, multiplicity - 1, concurrent );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,17 +68,17 @@ abstract class JCacheRegionAccessStrategy<R extends JCacheTransactionalDataRegio
|
|||
|
||||
@Override
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
// no op
|
||||
evictAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SharedSessionContractImplementor session, Object key) throws CacheException {
|
||||
region.remove( key );
|
||||
// jcache only supports asynchronous access strategies
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll() throws CacheException {
|
||||
region.clear();
|
||||
evictAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
|
||||
package org.hibernate.cache.jcache.access;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.jcache.JCacheCollectionRegion;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
|
||||
/**
|
||||
|
@ -34,4 +36,9 @@ public class NonStrictCollectionRegionAccessStrategy
|
|||
return DefaultCacheKeysFactory.getCollectionId( cacheKey );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SharedSessionContractImplementor session, Object key) throws CacheException {
|
||||
evict( key );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -60,4 +60,9 @@ public class NonStrictEntityRegionAccessStrategy extends JCacheRegionAccessStrat
|
|||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.getEntityId( cacheKey );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SharedSessionContractImplementor session, Object key) throws CacheException {
|
||||
evict( key );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.cache.jcache.access;
|
||||
|
||||
import javax.cache.processor.EntryProcessor;
|
||||
import javax.cache.processor.EntryProcessorException;
|
||||
import javax.cache.processor.MutableEntry;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.jcache.JCacheEntityRegion;
|
||||
|
@ -38,21 +34,7 @@ public class ReadWriteEntityRegionAccessStrategy
|
|||
|
||||
@Override
|
||||
public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
return region.invoke(
|
||||
key, new EntryProcessor<Object, Object, Boolean>() {
|
||||
@Override
|
||||
public Boolean process(MutableEntry<Object, Object> entry, Object... args)
|
||||
throws EntryProcessorException {
|
||||
if ( !entry.exists() ) {
|
||||
entry.setValue( new Item( args[0], args[1], (Long) args[2] ) );
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}, value, version, region.nextTimestamp()
|
||||
);
|
||||
return region.putIfAbsent( key, new Item(value, version, region.nextTimestamp(), nextItemId() ));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -64,33 +46,28 @@ public class ReadWriteEntityRegionAccessStrategy
|
|||
@Override
|
||||
public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
return region.invoke(
|
||||
key, new EntryProcessor<Object, Object, Boolean>() {
|
||||
@Override
|
||||
public Boolean process(MutableEntry<Object, Object> entry, Object... args)
|
||||
throws EntryProcessorException {
|
||||
final Lockable item = (Lockable) entry.getValue();
|
||||
while (true) {
|
||||
Lockable item = (Lockable) region.get( key );
|
||||
|
||||
if ( item != null && item.isUnlockable( (SoftLock) args[3] ) ) {
|
||||
final Lock lockItem = (Lock) item;
|
||||
if ( item != null && item.isUnlockable( lock ) ) {
|
||||
Lock lockItem = (Lock) item;
|
||||
if ( lockItem.wasLockedConcurrently() ) {
|
||||
lockItem.unlock( (Long) args[1] );
|
||||
entry.setValue( lockItem );
|
||||
if (region.replace( key, lockItem, lockItem.unlock( region.nextTimestamp() ))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
entry.setValue( new Item( args[0], args[1], (Long) args[4] ) );
|
||||
if (region.replace( key, lockItem, new Item(value, currentVersion, region.nextTimestamp(), nextItemId() ))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
entry.setValue( null );
|
||||
handleMissingLock( key, item );
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}, value, currentVersion, previousVersion, lock, region.nextTimestamp()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,10 +7,6 @@
|
|||
|
||||
package org.hibernate.cache.jcache.access;
|
||||
|
||||
import javax.cache.processor.EntryProcessor;
|
||||
import javax.cache.processor.EntryProcessorException;
|
||||
import javax.cache.processor.MutableEntry;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.jcache.JCacheNaturalIdRegion;
|
||||
|
@ -37,21 +33,7 @@ public class ReadWriteNaturalIdRegionAccessStrategy
|
|||
|
||||
@Override
|
||||
public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException {
|
||||
return region.invoke(
|
||||
key, new EntryProcessor<Object, Object, Boolean>() {
|
||||
@Override
|
||||
public Boolean process(MutableEntry<Object, Object> entry, Object... args)
|
||||
throws EntryProcessorException {
|
||||
if ( !entry.exists() ) {
|
||||
entry.setValue( new Item( args[0], null, (Long) args[1] ) );
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}, value, region.nextTimestamp()
|
||||
);
|
||||
return region.putIfAbsent( key, new Item( value, null, region.nextTimestamp(), nextItemId() ));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,33 +45,28 @@ public class ReadWriteNaturalIdRegionAccessStrategy
|
|||
@Override
|
||||
public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, SoftLock lock)
|
||||
throws CacheException {
|
||||
return region.invoke(
|
||||
key, new EntryProcessor<Object, Object, Boolean>() {
|
||||
@Override
|
||||
public Boolean process(MutableEntry<Object, Object> entry, Object... args)
|
||||
throws EntryProcessorException {
|
||||
final Lockable item = (Lockable) entry.getValue();
|
||||
while (true) {
|
||||
Lockable item = (Lockable) region.get( key );
|
||||
|
||||
if ( item != null && item.isUnlockable( (SoftLock) args[1] ) ) {
|
||||
if ( item != null && item.isUnlockable( lock ) ) {
|
||||
final Lock lockItem = (Lock) item;
|
||||
if ( lockItem.wasLockedConcurrently() ) {
|
||||
lockItem.unlock( region.nextTimestamp() );
|
||||
entry.setValue( lockItem );
|
||||
if (region.replace( key, lockItem, lockItem.unlock( region.nextTimestamp() ) )) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
entry.setValue( new Item( args[0], null, (Long) args[2] ) );
|
||||
if (region.replace( key, lockItem, new Item(value, null, region.nextTimestamp(), nextItemId() ))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
entry.setValue( null );
|
||||
handleMissingLock( key, item );
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}, value, lock, region.nextTimestamp()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
41
hibernate-jcache/src/main/java/org/hibernate/cache/jcache/time/Timestamper.java
vendored
Normal file
41
hibernate-jcache/src/main/java/org/hibernate/cache/jcache/time/Timestamper.java
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.cache.jcache.time;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Generates increasing identifiers (in a single VM only). Not valid across multiple VMs. Identifiers are not
|
||||
* necessarily strictly increasing, but usually are.
|
||||
* <p/>
|
||||
* Core while loop implemented by Alex Snaps - EHCache project - under ASL 2.0
|
||||
*
|
||||
* @author Hibernate team
|
||||
* @author Alex Snaps
|
||||
*/
|
||||
public final class Timestamper {
|
||||
private static final int BIN_DIGITS = 12;
|
||||
public static final short ONE_MS = 1 << BIN_DIGITS;
|
||||
private static final AtomicLong VALUE = new AtomicLong();
|
||||
|
||||
public static long next() {
|
||||
while ( true ) {
|
||||
long base = System.currentTimeMillis() << BIN_DIGITS;
|
||||
long maxValue = base + ONE_MS - 1;
|
||||
|
||||
for ( long current = VALUE.get(), update = Math.max( base, current + 1 ); update < maxValue;
|
||||
current = VALUE.get(), update = Math.max( base, current + 1 ) ) {
|
||||
if ( VALUE.compareAndSet( current, update ) ) {
|
||||
return update;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Timestamper() {
|
||||
}
|
||||
}
|
32
hibernate-jcache/src/test/java/org/hibernate/cache/jcache/access/ItemValueExtractor.java
vendored
Normal file
32
hibernate-jcache/src/test/java/org/hibernate/cache/jcache/access/ItemValueExtractor.java
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.cache.jcache.access;
|
||||
|
||||
import org.hibernate.cache.jcache.JCacheTransactionalDataRegion;
|
||||
|
||||
|
||||
/**
|
||||
* @author Alex Snaps
|
||||
*/
|
||||
public class ItemValueExtractor extends AbstractReadWriteRegionAccessStrategy<JCacheTransactionalDataRegion> {
|
||||
|
||||
|
||||
/**
|
||||
* Creates a read/write cache access strategy around the given cache region.
|
||||
*/
|
||||
public ItemValueExtractor(JCacheTransactionalDataRegion region) {
|
||||
super(region);
|
||||
}
|
||||
|
||||
|
||||
public static <T> T getValue(final Object entry) {
|
||||
if(!(entry instanceof Item)) {
|
||||
throw new IllegalArgumentException("Entry needs to be of type " + Item.class.getName());
|
||||
}
|
||||
return (T)((Item)entry).getValue();
|
||||
}
|
||||
}
|
248
hibernate-jcache/src/test/java/org/hibernate/test/cache/HibernateCacheTest.java
vendored
Normal file
248
hibernate-jcache/src/test/java/org/hibernate/test/cache/HibernateCacheTest.java
vendored
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.cache;
|
||||
|
||||
import org.hibernate.cache.jcache.access.ItemValueExtractor;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.stat.QueryStatistics;
|
||||
import org.hibernate.stat.SecondLevelCacheStatistics;
|
||||
import org.hibernate.stat.Statistics;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.hibernate.test.domain.Event;
|
||||
import org.hibernate.test.domain.EventManager;
|
||||
import org.hibernate.test.domain.Item;
|
||||
import org.hibernate.test.domain.Person;
|
||||
import org.hibernate.test.domain.PhoneNumber;
|
||||
import org.hibernate.test.domain.VersionedItem;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author Chris Dennis
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
public class HibernateCacheTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
private static final String REGION_PREFIX = "hibernate.test.";
|
||||
|
||||
public HibernateCacheTest() {
|
||||
System.setProperty( "derby.system.home", "target/derby" );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void addSettings(Map settings) {
|
||||
super.addSettings( settings );
|
||||
settings.put( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.configure( "hibernate-config/hibernate.cfg.xml" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryCacheInvalidation() throws Exception {
|
||||
Session s = sessionFactory().openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
Item i = new Item();
|
||||
i.setName( "widget" );
|
||||
i.setDescription( "A really top-quality, full-featured widget." );
|
||||
s.persist( i );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
SecondLevelCacheStatistics slcs = sessionFactory()
|
||||
.getStatistics()
|
||||
.getSecondLevelCacheStatistics( REGION_PREFIX + Item.class.getName() );
|
||||
|
||||
assertThat( slcs.getPutCount(), equalTo( 1L ) );
|
||||
assertThat( slcs.getEntries().size(), equalTo( 1 ) );
|
||||
|
||||
s = sessionFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
i = (Item) s.get( Item.class, i.getId() );
|
||||
|
||||
assertThat( slcs.getHitCount(), equalTo( 1L ) );
|
||||
assertThat( slcs.getMissCount(), equalTo( 0L ) );
|
||||
|
||||
i.setDescription( "A bog standard item" );
|
||||
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
assertThat( slcs.getPutCount(), equalTo( 2L ) );
|
||||
|
||||
Object entry = slcs.getEntries().get( i.getId() );
|
||||
Map map;
|
||||
if ( entry instanceof Map ) {
|
||||
map = (Map) entry;
|
||||
}
|
||||
else {
|
||||
map = ItemValueExtractor.getValue( entry );
|
||||
}
|
||||
assertThat( (String) map.get( "description" ), equalTo( "A bog standard item" ) );
|
||||
assertThat( (String) map.get( "name" ), equalTo( "widget" ) );
|
||||
|
||||
// cleanup
|
||||
s = sessionFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
s.delete( i );
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptySecondLevelCacheEntry() throws Exception {
|
||||
sessionFactory().getCache().evictEntityRegion( Item.class.getName() );
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
stats.clear();
|
||||
SecondLevelCacheStatistics statistics = stats.getSecondLevelCacheStatistics( REGION_PREFIX + Item.class.getName() );
|
||||
Map cacheEntries = statistics.getEntries();
|
||||
assertThat( cacheEntries.size(), equalTo( 0 ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStaleWritesLeaveCacheConsistent() {
|
||||
Session s = sessionFactory().openSession();
|
||||
Transaction txn = s.beginTransaction();
|
||||
VersionedItem item = new VersionedItem();
|
||||
item.setName( "steve" );
|
||||
item.setDescription( "steve's item" );
|
||||
s.save( item );
|
||||
txn.commit();
|
||||
s.close();
|
||||
|
||||
Long initialVersion = item.getVersion();
|
||||
|
||||
// manually revert the version property
|
||||
item.setVersion( item.getVersion() - 1 );
|
||||
|
||||
try {
|
||||
s = sessionFactory().openSession();
|
||||
txn = s.beginTransaction();
|
||||
s.update( item );
|
||||
txn.commit();
|
||||
s.close();
|
||||
fail( "expected stale write to fail" );
|
||||
}
|
||||
catch ( Throwable expected ) {
|
||||
// expected behavior here
|
||||
if ( txn != null ) {
|
||||
try {
|
||||
txn.rollback();
|
||||
}
|
||||
catch ( Throwable ignore ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if ( s != null && s.isOpen() ) {
|
||||
try {
|
||||
s.close();
|
||||
}
|
||||
catch ( Throwable ignore ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check the version value in the cache...
|
||||
SecondLevelCacheStatistics slcs = sessionFactory().getStatistics()
|
||||
.getSecondLevelCacheStatistics( REGION_PREFIX + VersionedItem.class.getName() );
|
||||
assertNotNull(slcs);
|
||||
final Map entries = slcs.getEntries();
|
||||
Object entry = entries.get( item.getId() );
|
||||
Long cachedVersionValue;
|
||||
if ( entry instanceof SoftLock ) {
|
||||
//FIXME don't know what to test here
|
||||
//cachedVersionValue = new Long( ( (ReadWriteCache.Lock) entry).getUnlockTimestamp() );
|
||||
}
|
||||
else {
|
||||
cachedVersionValue = (Long) ( (Map) entry ).get( "_version" );
|
||||
assertThat( initialVersion, equalTo( cachedVersionValue ) );
|
||||
}
|
||||
|
||||
|
||||
// cleanup
|
||||
s = sessionFactory().openSession();
|
||||
txn = s.beginTransaction();
|
||||
item = (VersionedItem) s.load( VersionedItem.class, item.getId() );
|
||||
s.delete( item );
|
||||
txn.commit();
|
||||
s.close();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGeneralUsage() {
|
||||
EventManager mgr = new EventManager( sessionFactory() );
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
|
||||
// create 3 persons Steve, Orion, Tim
|
||||
Person stevePerson = new Person();
|
||||
stevePerson.setFirstname( "Steve" );
|
||||
stevePerson.setLastname( "Harris" );
|
||||
Long steveId = mgr.createAndStorePerson( stevePerson );
|
||||
mgr.addEmailToPerson( steveId, "steve@tc.com" );
|
||||
mgr.addEmailToPerson( steveId, "sharrif@tc.com" );
|
||||
mgr.addTalismanToPerson( steveId, "rabbit foot" );
|
||||
mgr.addTalismanToPerson( steveId, "john de conqueroo" );
|
||||
|
||||
PhoneNumber p1 = new PhoneNumber();
|
||||
p1.setNumberType( "Office" );
|
||||
p1.setPhone( 111111 );
|
||||
mgr.addPhoneNumberToPerson( steveId, p1 );
|
||||
|
||||
PhoneNumber p2 = new PhoneNumber();
|
||||
p2.setNumberType( "Home" );
|
||||
p2.setPhone( 222222 );
|
||||
mgr.addPhoneNumberToPerson( steveId, p2 );
|
||||
|
||||
Person orionPerson = new Person();
|
||||
orionPerson.setFirstname( "Orion" );
|
||||
orionPerson.setLastname( "Letizi" );
|
||||
Long orionId = mgr.createAndStorePerson( orionPerson );
|
||||
mgr.addEmailToPerson( orionId, "orion@tc.com" );
|
||||
mgr.addTalismanToPerson( orionId, "voodoo doll" );
|
||||
|
||||
Long timId = mgr.createAndStorePerson( "Tim", "Teck" );
|
||||
mgr.addEmailToPerson( timId, "teck@tc.com" );
|
||||
mgr.addTalismanToPerson( timId, "magic decoder ring" );
|
||||
|
||||
Long engMeetingId = mgr.createAndStoreEvent( "Eng Meeting", stevePerson, new Date() );
|
||||
mgr.addPersonToEvent( steveId, engMeetingId );
|
||||
mgr.addPersonToEvent( orionId, engMeetingId );
|
||||
mgr.addPersonToEvent( timId, engMeetingId );
|
||||
|
||||
Long docMeetingId = mgr.createAndStoreEvent( "Doc Meeting", orionPerson, new Date() );
|
||||
mgr.addPersonToEvent( steveId, docMeetingId );
|
||||
mgr.addPersonToEvent( orionId, docMeetingId );
|
||||
|
||||
for ( Event event : (List<Event>) mgr.listEvents() ) {
|
||||
mgr.listEmailsOfEvent( event.getId() );
|
||||
}
|
||||
|
||||
QueryStatistics queryStats = stats.getQueryStatistics( "from Event" );
|
||||
assertThat( "Cache Miss Count", queryStats.getCacheMissCount(), equalTo( 1L ) );
|
||||
assertThat( "Cache Hit Count", queryStats.getCacheHitCount(), equalTo( 0L ) );
|
||||
assertThat( "Cache Put Count", queryStats.getCachePutCount(), equalTo( 1L ) );
|
||||
}
|
||||
}
|
277
hibernate-jcache/src/test/java/org/hibernate/test/cache/jcache/functional/InsertedDataTest.java
vendored
Normal file
277
hibernate-jcache/src/test/java/org/hibernate/test/cache/jcache/functional/InsertedDataTest.java
vendored
Normal file
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.cache.jcache.functional;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
/**
|
||||
* Tests for handling of data just inserted during a transaction being read from the database
|
||||
* and placed into cache. Initially these cases went through putFromRead which causes problems because it
|
||||
* loses the context of that data having just been read.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class InsertedDataTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] {CacheableItem.class};
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void addSettings(Map settings) {
|
||||
super.addSettings( settings );
|
||||
settings.put( AvailableSettings.CACHE_REGION_PREFIX, "" );
|
||||
settings.put( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.configure( "hibernate-config/hibernate.cfg.xml" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsert() {
|
||||
sessionFactory().getCache().evictEntityRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
CacheableItem item = new CacheableItem( "data" );
|
||||
s.save( item );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||
assertEquals( 1, cacheMap.size() );
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
s.createQuery( "delete CacheableItem" ).executeUpdate();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertWithRollback() {
|
||||
sessionFactory().getCache().evictEntityRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
CacheableItem item = new CacheableItem( "data" );
|
||||
s.save( item );
|
||||
s.flush();
|
||||
s.getTransaction().rollback();
|
||||
s.close();
|
||||
|
||||
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||
assertEquals( 0, cacheMap.size() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertThenUpdate() {
|
||||
sessionFactory().getCache().evictEntityRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
CacheableItem item = new CacheableItem( "data" );
|
||||
s.save( item );
|
||||
s.flush();
|
||||
item.setName( "new data" );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||
assertEquals( 1, cacheMap.size() );
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
s.createQuery( "delete CacheableItem" ).executeUpdate();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertThenUpdateThenRollback() {
|
||||
sessionFactory().getCache().evictEntityRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
CacheableItem item = new CacheableItem( "data" );
|
||||
s.save( item );
|
||||
s.flush();
|
||||
item.setName( "new data" );
|
||||
s.getTransaction().rollback();
|
||||
s.close();
|
||||
|
||||
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||
assertEquals( 0, cacheMap.size() );
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
s.createQuery( "delete CacheableItem" ).executeUpdate();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertWithRefresh() {
|
||||
sessionFactory().getCache().evictEntityRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
CacheableItem item = new CacheableItem( "data" );
|
||||
s.save( item );
|
||||
s.flush();
|
||||
s.refresh( item );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||
assertEquals( 1, cacheMap.size() );
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
s.createQuery( "delete CacheableItem" ).executeUpdate();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertWithRefreshThenRollback() {
|
||||
sessionFactory().getCache().evictEntityRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
CacheableItem item = new CacheableItem( "data" );
|
||||
s.save( item );
|
||||
s.flush();
|
||||
s.refresh( item );
|
||||
s.getTransaction().rollback();
|
||||
s.close();
|
||||
|
||||
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||
assertEquals( 1, cacheMap.size() );
|
||||
Object lock = cacheMap.values().iterator().next();
|
||||
assertEquals( "org.hibernate.cache.jcache.access.AbstractReadWriteRegionAccessStrategy$Lock", lock.getClass().getName() );
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (CacheableItem) s.get( CacheableItem.class, item.getId() );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
assertNull( "it should be null", item );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertWithClear() {
|
||||
sessionFactory().getCache().evictEntityRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
CacheableItem item = new CacheableItem( "data" );
|
||||
s.save( item );
|
||||
s.flush();
|
||||
s.clear();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||
assertEquals( 1, cacheMap.size() );
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
s.createQuery( "delete CacheableItem" ).executeUpdate();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertWithClearThenRollback() {
|
||||
sessionFactory().getCache().evictEntityRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
CacheableItem item = new CacheableItem( "data" );
|
||||
s.save( item );
|
||||
s.flush();
|
||||
s.clear();
|
||||
item = (CacheableItem) s.get( CacheableItem.class, item.getId() );
|
||||
s.getTransaction().rollback();
|
||||
s.close();
|
||||
|
||||
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||
assertEquals( 0, cacheMap.size() );
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (CacheableItem) s.get( CacheableItem.class, item.getId() );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
assertNull( "it should be null", item );
|
||||
}
|
||||
|
||||
@Entity(name = "CacheableItem")
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item")
|
||||
public static class CacheableItem {
|
||||
private Long id;
|
||||
private String name;
|
||||
|
||||
public CacheableItem() {
|
||||
}
|
||||
|
||||
public CacheableItem(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "increment")
|
||||
@GenericGenerator(name = "increment", strategy = "increment")
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.cache.jcache.functional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Zhenlei Huang
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH-10649")
|
||||
public class RefreshUpdatedDataTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
ReadWriteCacheableItem.class,
|
||||
ReadWriteVersionedCacheableItem.class,
|
||||
NonStrictReadWriteCacheableItem.class,
|
||||
NonStrictReadWriteVersionedCacheableItem.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void addSettings(Map settings) {
|
||||
super.addSettings( settings );
|
||||
settings.put( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.configure( "hibernate-config/hibernate.cfg.xml" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAndFlushThenRefresh() {
|
||||
// prepare data
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
final String BEFORE = "before";
|
||||
|
||||
ReadWriteCacheableItem readWriteCacheableItem = new ReadWriteCacheableItem( BEFORE );
|
||||
readWriteCacheableItem.getTags().add( "Hibernate" );
|
||||
readWriteCacheableItem.getTags().add( "ORM" );
|
||||
s.persist( readWriteCacheableItem );
|
||||
|
||||
ReadWriteVersionedCacheableItem readWriteVersionedCacheableItem = new ReadWriteVersionedCacheableItem( BEFORE );
|
||||
readWriteVersionedCacheableItem.getTags().add( "Hibernate" );
|
||||
readWriteVersionedCacheableItem.getTags().add( "ORM" );
|
||||
s.persist( readWriteVersionedCacheableItem );
|
||||
|
||||
NonStrictReadWriteCacheableItem nonStrictReadWriteCacheableItem = new NonStrictReadWriteCacheableItem( BEFORE );
|
||||
nonStrictReadWriteCacheableItem.getTags().add( "Hibernate" );
|
||||
nonStrictReadWriteCacheableItem.getTags().add( "ORM" );
|
||||
s.persist( nonStrictReadWriteCacheableItem );
|
||||
|
||||
NonStrictReadWriteVersionedCacheableItem nonStrictReadWriteVersionedCacheableItem = new NonStrictReadWriteVersionedCacheableItem( BEFORE );
|
||||
nonStrictReadWriteVersionedCacheableItem.getTags().add( "Hibernate" );
|
||||
nonStrictReadWriteVersionedCacheableItem.getTags().add( "ORM" );
|
||||
s.persist( nonStrictReadWriteVersionedCacheableItem );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Session s1 = openSession();
|
||||
s1.beginTransaction();
|
||||
|
||||
final String AFTER = "after";
|
||||
|
||||
ReadWriteCacheableItem readWriteCacheableItem1 = s1.get( ReadWriteCacheableItem.class, readWriteCacheableItem.getId() );
|
||||
readWriteCacheableItem1.setName( AFTER );
|
||||
readWriteCacheableItem1.getTags().remove("ORM");
|
||||
|
||||
ReadWriteVersionedCacheableItem readWriteVersionedCacheableItem1 = s1.get( ReadWriteVersionedCacheableItem.class, readWriteVersionedCacheableItem.getId() );
|
||||
readWriteVersionedCacheableItem1.setName( AFTER );
|
||||
readWriteVersionedCacheableItem1.getTags().remove("ORM");
|
||||
|
||||
NonStrictReadWriteCacheableItem nonStrictReadWriteCacheableItem1 = s1.get( NonStrictReadWriteCacheableItem.class, nonStrictReadWriteCacheableItem.getId() );
|
||||
nonStrictReadWriteCacheableItem1.setName( AFTER );
|
||||
nonStrictReadWriteCacheableItem1.getTags().remove("ORM");
|
||||
|
||||
NonStrictReadWriteVersionedCacheableItem nonStrictReadWriteVersionedCacheableItem1 = s1.get( NonStrictReadWriteVersionedCacheableItem.class, nonStrictReadWriteVersionedCacheableItem.getId() );
|
||||
nonStrictReadWriteVersionedCacheableItem1.setName( AFTER );
|
||||
nonStrictReadWriteVersionedCacheableItem1.getTags().remove("ORM");
|
||||
|
||||
s1.flush();
|
||||
s1.refresh( readWriteCacheableItem1 );
|
||||
s1.refresh( readWriteVersionedCacheableItem1 );
|
||||
s1.refresh( nonStrictReadWriteCacheableItem1 );
|
||||
s1.refresh( nonStrictReadWriteVersionedCacheableItem1 );
|
||||
|
||||
assertEquals( AFTER, readWriteCacheableItem1.getName() );
|
||||
assertEquals( 1, readWriteCacheableItem1.getTags().size() );
|
||||
assertEquals( AFTER, readWriteVersionedCacheableItem1.getName() );
|
||||
assertEquals( 1, readWriteVersionedCacheableItem1.getTags().size() );
|
||||
assertEquals( AFTER, nonStrictReadWriteCacheableItem1.getName() );
|
||||
assertEquals( 1, nonStrictReadWriteCacheableItem1.getTags().size() );
|
||||
assertEquals( AFTER, nonStrictReadWriteVersionedCacheableItem1.getName() );
|
||||
assertEquals( 1, nonStrictReadWriteVersionedCacheableItem1.getTags().size() );
|
||||
|
||||
// open another session
|
||||
Session s2 = sessionFactory().openSession();
|
||||
try {
|
||||
s2.beginTransaction();
|
||||
ReadWriteCacheableItem readWriteCacheableItem2 = s2.get( ReadWriteCacheableItem.class, readWriteCacheableItem.getId() );
|
||||
ReadWriteVersionedCacheableItem readWriteVersionedCacheableItem2 = s2.get( ReadWriteVersionedCacheableItem.class, readWriteVersionedCacheableItem.getId() );
|
||||
NonStrictReadWriteCacheableItem nonStrictReadWriteCacheableItem2 = s2.get( NonStrictReadWriteCacheableItem.class, nonStrictReadWriteCacheableItem.getId() );
|
||||
NonStrictReadWriteVersionedCacheableItem nonStrictReadWriteVersionedCacheableItem2 = s2.get( NonStrictReadWriteVersionedCacheableItem.class, nonStrictReadWriteVersionedCacheableItem.getId() );
|
||||
|
||||
assertEquals( BEFORE, readWriteCacheableItem2.getName() );
|
||||
assertEquals( 2, readWriteCacheableItem2.getTags().size() );
|
||||
assertEquals( BEFORE, readWriteVersionedCacheableItem2.getName() );
|
||||
assertEquals( 2, readWriteVersionedCacheableItem2.getTags().size() );
|
||||
|
||||
//READ_UNCOMMITTED because there is no locking to prevent collections from being cached in the first Session
|
||||
|
||||
assertEquals( BEFORE, nonStrictReadWriteCacheableItem2.getName() );
|
||||
assertEquals( 1, nonStrictReadWriteCacheableItem2.getTags().size());
|
||||
assertEquals( BEFORE, nonStrictReadWriteVersionedCacheableItem2.getName() );
|
||||
assertEquals( 1, nonStrictReadWriteVersionedCacheableItem2.getTags().size() );
|
||||
|
||||
s2.getTransaction().commit();
|
||||
}
|
||||
finally {
|
||||
if ( s2.getTransaction().getStatus().canRollback() ) {
|
||||
s2.getTransaction().rollback();
|
||||
}
|
||||
s2.close();
|
||||
}
|
||||
|
||||
s1.getTransaction().rollback();
|
||||
s1.close();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
s.delete( readWriteCacheableItem );
|
||||
s.delete( readWriteVersionedCacheableItem );
|
||||
s.delete( nonStrictReadWriteCacheableItem );
|
||||
s.delete( nonStrictReadWriteVersionedCacheableItem );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Entity(name = "ReadWriteCacheableItem")
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item")
|
||||
public static class ReadWriteCacheableItem {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||
@ElementCollection
|
||||
private List<String> tags = new ArrayList<>();
|
||||
|
||||
public ReadWriteCacheableItem() {
|
||||
}
|
||||
|
||||
public ReadWriteCacheableItem(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getTags() {
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "ReadWriteVersionedCacheableItem")
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item")
|
||||
public static class ReadWriteVersionedCacheableItem {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||
@ElementCollection
|
||||
private List<String> tags = new ArrayList<>();
|
||||
|
||||
@Version
|
||||
private int version;
|
||||
|
||||
public ReadWriteVersionedCacheableItem() {
|
||||
}
|
||||
|
||||
public ReadWriteVersionedCacheableItem(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getTags() {
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "NonStrictReadWriteCacheableItem")
|
||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "item")
|
||||
public static class NonStrictReadWriteCacheableItem {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
|
||||
@ElementCollection
|
||||
private List<String> tags = new ArrayList<>();
|
||||
|
||||
public NonStrictReadWriteCacheableItem() {
|
||||
}
|
||||
|
||||
public NonStrictReadWriteCacheableItem(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getTags() {
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "NonStrictReadWriteVersionedCacheableItem")
|
||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "item")
|
||||
public static class NonStrictReadWriteVersionedCacheableItem {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
|
||||
@ElementCollection
|
||||
private List<String> tags = new ArrayList<>();
|
||||
|
||||
@Version
|
||||
private int version;
|
||||
|
||||
public NonStrictReadWriteVersionedCacheableItem() {
|
||||
}
|
||||
|
||||
public NonStrictReadWriteVersionedCacheableItem(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getTags() {
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
package org.hibernate.test.domain;
|
||||
|
||||
public class Account {
|
||||
|
||||
private Long id;
|
||||
private Person person;
|
||||
|
||||
public Account() {
|
||||
//
|
||||
}
|
||||
|
||||
public Person getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(Person person) {
|
||||
this.person = person;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Event {
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
private Date date;
|
||||
private Set participants = new HashSet();
|
||||
private Person organizer;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public void setOrganizer(Person organizer) {
|
||||
this.organizer = organizer;
|
||||
}
|
||||
|
||||
public Person getOrganizer() {
|
||||
return organizer;
|
||||
}
|
||||
|
||||
public Set getParticipants() {
|
||||
return participants;
|
||||
}
|
||||
|
||||
public void setParticipants(Set participants) {
|
||||
this.participants = participants;
|
||||
}
|
||||
|
||||
public void addParticipant(Person person) {
|
||||
participants.add(person);
|
||||
person.getEvents().add(this);
|
||||
}
|
||||
|
||||
public void removeParticipant(Person person) {
|
||||
participants.remove(person);
|
||||
person.getEvents().remove(this);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getTitle() + ": " + getDate();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.domain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
public class EventManager {
|
||||
|
||||
private final SessionFactory sessionFactory;
|
||||
|
||||
public EventManager(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
public List listEmailsOfEvent(Long eventId) {
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
session.beginTransaction();
|
||||
|
||||
List emailList = new ArrayList();
|
||||
Event event = (Event)session.load(Event.class, eventId);
|
||||
for (Iterator it = event.getParticipants().iterator(); it.hasNext(); ) {
|
||||
Person person = (Person)it.next();
|
||||
emailList.addAll(person.getEmailAddresses());
|
||||
}
|
||||
|
||||
session.getTransaction().commit();
|
||||
return emailList;
|
||||
}
|
||||
|
||||
public Long createAndStoreEvent(String title, Person organizer, Date theDate) {
|
||||
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
|
||||
session.beginTransaction();
|
||||
|
||||
Event theEvent = new Event();
|
||||
theEvent.setTitle(title);
|
||||
theEvent.setDate(theDate);
|
||||
theEvent.setOrganizer(organizer);
|
||||
|
||||
Long eventId = (Long)session.save(theEvent);
|
||||
|
||||
session.getTransaction().commit();
|
||||
return eventId;
|
||||
}
|
||||
|
||||
public Long createAndStorePerson(String firstName, String lastName) {
|
||||
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
|
||||
session.beginTransaction();
|
||||
|
||||
Person person = new Person();
|
||||
person.setFirstname(firstName);
|
||||
person.setLastname(lastName);
|
||||
|
||||
Long personId = (Long)session.save(person);
|
||||
|
||||
session.getTransaction().commit();
|
||||
return personId;
|
||||
}
|
||||
|
||||
public Long createAndStorePerson(Person person) {
|
||||
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
|
||||
session.beginTransaction();
|
||||
|
||||
Long personId = (Long)session.save(person);
|
||||
|
||||
session.getTransaction().commit();
|
||||
return personId;
|
||||
}
|
||||
|
||||
public List listEvents() {
|
||||
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
|
||||
session.beginTransaction();
|
||||
|
||||
List result = session.createQuery("from Event").setCacheable(true).list();
|
||||
|
||||
session.getTransaction().commit();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call setEntity() on a cacheable query - see FORGE-265
|
||||
*/
|
||||
public List listEventsOfOrganizer(Person organizer) {
|
||||
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
|
||||
session.beginTransaction();
|
||||
|
||||
Query query = session.createQuery("from Event ev where ev.organizer = :organizer");
|
||||
|
||||
query.setCacheable(true);
|
||||
query.setEntity("organizer", organizer);
|
||||
List result = query.list();
|
||||
|
||||
session.getTransaction().commit();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a Criteria query - see FORGE-247
|
||||
*/
|
||||
public List listEventsWithCriteria() {
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
|
||||
session.beginTransaction();
|
||||
|
||||
List result = session.createCriteria(Event.class)
|
||||
.setCacheable(true)
|
||||
.list();
|
||||
|
||||
session.getTransaction().commit();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void addPersonToEvent(Long personId, Long eventId) {
|
||||
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
session.beginTransaction();
|
||||
|
||||
Person aPerson = (Person)session.load(Person.class, personId);
|
||||
Event anEvent = (Event)session.load(Event.class, eventId);
|
||||
|
||||
aPerson.getEvents().add(anEvent);
|
||||
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
|
||||
public Long addPersonToAccount(Long personId, Account account) {
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
session.beginTransaction();
|
||||
|
||||
Person aPerson = (Person)session.load(Person.class, personId);
|
||||
account.setPerson(aPerson);
|
||||
|
||||
Long accountId = (Long)session.save(account);
|
||||
|
||||
session.getTransaction().commit();
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public Account getAccount(Long accountId) {
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
session.beginTransaction();
|
||||
|
||||
Account account = (Account)session.load(Account.class, accountId);
|
||||
|
||||
session.getTransaction().commit();
|
||||
return account;
|
||||
}
|
||||
|
||||
public void addEmailToPerson(Long personId, String emailAddress) {
|
||||
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
session.beginTransaction();
|
||||
|
||||
Person aPerson = (Person)session.load(Person.class, personId);
|
||||
|
||||
// The getEmailAddresses() might trigger a lazy load of the collection
|
||||
aPerson.getEmailAddresses().add(emailAddress);
|
||||
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
|
||||
public void addPhoneNumberToPerson(Long personId, PhoneNumber pN) {
|
||||
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
session.beginTransaction();
|
||||
|
||||
Person aPerson = (Person)session.load(Person.class, personId);
|
||||
pN.setPersonId(personId.longValue());
|
||||
aPerson.getPhoneNumbers().add(pN);
|
||||
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
|
||||
public void addTalismanToPerson(Long personId, String talisman) {
|
||||
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
session.beginTransaction();
|
||||
|
||||
Person aPerson = (Person)session.load(Person.class, personId);
|
||||
aPerson.addTalisman(talisman);
|
||||
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
|
||||
public Long createHolidayCalendar() {
|
||||
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
session.beginTransaction();
|
||||
|
||||
// delete all existing calendars
|
||||
List calendars = session.createQuery("from HolidayCalendar").setCacheable(true).list();
|
||||
for (ListIterator li = calendars.listIterator(); li.hasNext(); ) {
|
||||
session.delete(li.next());
|
||||
}
|
||||
|
||||
HolidayCalendar calendar = new HolidayCalendar();
|
||||
calendar.init();
|
||||
|
||||
Long calendarId = (Long)session.save(calendar);
|
||||
|
||||
session.getTransaction().commit();
|
||||
return calendarId;
|
||||
}
|
||||
|
||||
public HolidayCalendar getHolidayCalendar() {
|
||||
Session session = sessionFactory.getCurrentSession();
|
||||
|
||||
session.beginTransaction();
|
||||
|
||||
List calendars = session.createQuery("from HolidayCalendar").setCacheable(true).list();
|
||||
|
||||
session.getTransaction().commit();
|
||||
|
||||
return calendars.isEmpty() ? null : (HolidayCalendar)calendars.get(0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.domain;
|
||||
|
||||
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class HolidayCalendar {
|
||||
|
||||
|
||||
private Long id;
|
||||
// Date -> String
|
||||
private Map holidays = new HashMap();
|
||||
|
||||
public HolidayCalendar init() {
|
||||
DateFormat df = new SimpleDateFormat("yyyy.MM.dd");
|
||||
try {
|
||||
holidays.clear();
|
||||
holidays.put(df.parse("2009.01.01"), "New Year's Day");
|
||||
holidays.put(df.parse("2009.02.14"), "Valentine's Day");
|
||||
holidays.put(df.parse("2009.11.11"), "Armistice Day");
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map getHolidays() {
|
||||
return holidays;
|
||||
}
|
||||
|
||||
protected void setHolidays(Map holidays) {
|
||||
this.holidays = holidays;
|
||||
}
|
||||
|
||||
public void addHoliday(Date d, String name) {
|
||||
holidays.put(d, name);
|
||||
}
|
||||
|
||||
public String getHoliday(Date d) {
|
||||
return (String)holidays.get(d);
|
||||
}
|
||||
|
||||
public boolean isHoliday(Date d) {
|
||||
return holidays.containsKey(d);
|
||||
}
|
||||
|
||||
protected Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
protected void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.domain;
|
||||
|
||||
public class Item {
|
||||
private Long id;
|
||||
private String name;
|
||||
private String description;
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
package org.hibernate.test.domain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class Person {
|
||||
|
||||
private Long id;
|
||||
private int age;
|
||||
private String firstname;
|
||||
private String lastname;
|
||||
private List events = new ArrayList(); // list semantics, e.g., indexed
|
||||
private Set emailAddresses = new HashSet();
|
||||
private Set phoneNumbers = new HashSet();
|
||||
private List talismans = new ArrayList(); // a Bag of good-luck charms.
|
||||
|
||||
public Person() {
|
||||
//
|
||||
}
|
||||
|
||||
public List getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
protected void setEvents(List events) {
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
public void addToEvent(Event event) {
|
||||
this.getEvents().add(event);
|
||||
event.getParticipants().add(this);
|
||||
}
|
||||
|
||||
public void removeFromEvent(Event event) {
|
||||
this.getEvents().remove(event);
|
||||
event.getParticipants().remove(this);
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
}
|
||||
|
||||
public void setFirstname(String firstname) {
|
||||
this.firstname = firstname;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getLastname() {
|
||||
return lastname;
|
||||
}
|
||||
|
||||
public void setLastname(String lastname) {
|
||||
this.lastname = lastname;
|
||||
}
|
||||
|
||||
public Set getEmailAddresses() {
|
||||
return emailAddresses;
|
||||
}
|
||||
|
||||
public void setEmailAddresses(Set emailAddresses) {
|
||||
this.emailAddresses = emailAddresses;
|
||||
}
|
||||
|
||||
public Set getPhoneNumbers() {
|
||||
return phoneNumbers;
|
||||
}
|
||||
|
||||
public void setPhoneNumbers(Set phoneNumbers) {
|
||||
this.phoneNumbers = phoneNumbers;
|
||||
}
|
||||
|
||||
public void addTalisman(String name) {
|
||||
talismans.add(name);
|
||||
}
|
||||
|
||||
public List getTalismans() {
|
||||
return talismans;
|
||||
}
|
||||
|
||||
public void setTalismans(List talismans) {
|
||||
this.talismans = talismans;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getFirstname() + " " + getLastname();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
package org.hibernate.test.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* PhoneNumber
|
||||
*/
|
||||
public class PhoneNumber implements Serializable {
|
||||
private long personId = 0;
|
||||
private String numberType = "home";
|
||||
private long phone = 0;
|
||||
|
||||
public long getPersonId() {
|
||||
return personId;
|
||||
}
|
||||
|
||||
public void setPersonId(long personId) {
|
||||
this.personId = personId;
|
||||
}
|
||||
|
||||
public String getNumberType() {
|
||||
return numberType;
|
||||
}
|
||||
|
||||
public void setNumberType(String numberType) {
|
||||
this.numberType = numberType;
|
||||
}
|
||||
|
||||
public long getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(long phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result
|
||||
+ ((numberType == null) ? 0 : numberType.hashCode());
|
||||
result = prime * result + (int)(personId ^ (personId >>> 32));
|
||||
result = prime * result + (int)(phone ^ (phone >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final PhoneNumber other = (PhoneNumber)obj;
|
||||
if (numberType == null) {
|
||||
if (other.numberType != null)
|
||||
return false;
|
||||
} else if (!numberType.equals(other.numberType))
|
||||
return false;
|
||||
if (personId != other.personId)
|
||||
return false;
|
||||
if (phone != other.phone)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return numberType + ":" + phone;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.domain;
|
||||
|
||||
public class UuidItem {
|
||||
private String id;
|
||||
private String name;
|
||||
private String description;
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.domain;
|
||||
|
||||
public class VersionedItem extends Item {
|
||||
private Long version;
|
||||
|
||||
public Long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(Long version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping>
|
||||
|
||||
<class name="org.hibernate.test.domain.Account" table="ACCOUNT" lazy="false">
|
||||
<id name="id" column="ACCOUNT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
|
||||
<many-to-one name="person" class="org.hibernate.test.domain.Person" cascade="save-update,lock"
|
||||
column="person_id"
|
||||
unique="true"
|
||||
not-null="true"/>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping>
|
||||
|
||||
<class name="org.hibernate.test.domain.Event" table="EVENTS">
|
||||
<cache usage="read-write"/>
|
||||
<id name="id" column="EVENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="date" type="timestamp" column="EVENT_DATE"/>
|
||||
<property name="title"/>
|
||||
<many-to-one name="organizer" column="EVENT_ORGANIZER" class="org.hibernate.test.domain.Person"/>
|
||||
|
||||
<set name="participants" table="PERSON_EVENT" lazy="false"
|
||||
inverse="true" cascade="lock">
|
||||
<cache usage="read-write"/>
|
||||
<key column="EVENT_ID"/>
|
||||
<many-to-many column="PERSON_ID"
|
||||
class="org.hibernate.test.domain.Person"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping>
|
||||
|
||||
<class name="org.hibernate.test.domain.HolidayCalendar" table="CALENDAR" lazy="false">
|
||||
<id name="id" column="CALENDAR_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
|
||||
<map name="holidays" table="CALENDAR_HOLIDAYS" lazy="false">
|
||||
<key column="CALENDAR_ID"/>
|
||||
<map-key column="hol_date" type="date"/>
|
||||
<element column="hol_name" type="string"/>
|
||||
</map>
|
||||
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping package="org.hibernate.test.domain">
|
||||
|
||||
|
||||
<class name="Item" table="Items">
|
||||
<cache usage="read-write"/>
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true"/>
|
||||
<property name="description" not-null="true"/>
|
||||
</class>
|
||||
|
||||
<class name="VersionedItem" table="VersionedItems">
|
||||
<cache usage="read-write"/>
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<version name="version" type="long"/>
|
||||
<property name="name" not-null="true"/>
|
||||
<property name="description" not-null="true"/>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping>
|
||||
|
||||
<class name="org.hibernate.test.domain.Person" table="PERSON" lazy="true">
|
||||
<id name="id" column="PERSON_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="age"/>
|
||||
<property name="firstname"/>
|
||||
<property name="lastname"/>
|
||||
|
||||
<list name="events" table="PERSON_EVENT" lazy="true">
|
||||
<key column="PERSON_ID"/>
|
||||
<list-index column="EVENT_ORDER"/>
|
||||
<many-to-many column="EVENT_ID" class="org.hibernate.test.domain.Event"/>
|
||||
</list>
|
||||
|
||||
<bag name="talismans" table="PERSON_TALISMAN" lazy="true">
|
||||
<key column="PERSON_ID"/>
|
||||
<element type="string" column="TALISMAN_NAME"/>
|
||||
</bag>
|
||||
|
||||
<set name="emailAddresses" table="PERSON_EMAIL_ADDR" lazy="true">
|
||||
<key column="PERSON_ID"/>
|
||||
<element type="string" column="EMAIL_ADDR"/>
|
||||
</set>
|
||||
|
||||
<set name="phoneNumbers" cascade="all" lazy="true">
|
||||
<key column="PERSON_ID"/>
|
||||
<one-to-many class="org.hibernate.test.domain.PhoneNumber"/>
|
||||
</set>
|
||||
|
||||
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping>
|
||||
|
||||
<class name="org.hibernate.test.domain.PhoneNumber" table="PHONE_NUMBERS">
|
||||
<composite-id>
|
||||
<key-property column="PERSON_ID" name="personId" type="java.lang.Long"/>
|
||||
<key-property column="NUMBER_TYPE" name="numberType" type="java.lang.String"/>
|
||||
</composite-id>
|
||||
|
||||
<property name="phone" type="java.lang.Long">
|
||||
<column name="PHONE" precision="22" scale="0"/>
|
||||
</property>
|
||||
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
<!DOCTYPE hibernate-configuration PUBLIC
|
||||
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
|
||||
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
|
||||
|
||||
<hibernate-configuration>
|
||||
|
||||
<session-factory>
|
||||
|
||||
<!-- Database connection settings -->
|
||||
<!-- <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
|
||||
<property name="connection.url">jdbc:hsqldb:hsql://localhost/TestDB</property> -->
|
||||
|
||||
<property name="connection.driver_class">org.h2.Driver</property>
|
||||
<property name="connection.url">jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE</property>
|
||||
<property name="connection.username">sa</property>
|
||||
<property name="connection.password"></property>
|
||||
|
||||
<!-- JDBC connection pool (use the built-in) -->
|
||||
<property name="connection.pool_size">1</property>
|
||||
|
||||
<!-- SQL dialect -->
|
||||
<property name="dialect">
|
||||
org.hibernate.dialect.H2Dialect
|
||||
</property>
|
||||
|
||||
<!-- Enable Hibernate's automatic session context management -->
|
||||
<property name="current_session_context_class">thread</property>
|
||||
|
||||
<property name="cache.use_query_cache">true</property>
|
||||
<property name="cache.use_second_level_cache">true</property>
|
||||
<property name="cache.use_structured_entries">true</property>
|
||||
<property name="cache.region.factory_class">org.hibernate.cache.jcache.JCacheRegionFactory</property>
|
||||
<property name="net.sf.ehcache.configurationResourceName">/hibernate-config/ehcache.xml</property>
|
||||
<!-- Echo all executed SQL to stdout -->
|
||||
<property name="show_sql">true</property>
|
||||
|
||||
<mapping resource="hibernate-config/domain/Event.hbm.xml"/>
|
||||
<mapping resource="hibernate-config/domain/Person.hbm.xml"/>
|
||||
<mapping resource="hibernate-config/domain/PhoneNumber.hbm.xml"/>
|
||||
<mapping resource="hibernate-config/domain/Account.hbm.xml"/>
|
||||
<mapping resource="hibernate-config/domain/HolidayCalendar.hbm.xml"/>
|
||||
|
||||
<mapping resource="hibernate-config/domain/Item.hbm.xml"/>
|
||||
|
||||
</session-factory>
|
||||
|
||||
</hibernate-configuration>
|
|
@ -0,0 +1,17 @@
|
|||
#
|
||||
# Hibernate, Relational Persistence for Idiomatic Java
|
||||
#
|
||||
# License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
# See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
#
|
||||
hibernate.dialect @db.dialect@
|
||||
hibernate.connection.driver_class @jdbc.driver@
|
||||
hibernate.connection.url @jdbc.url@
|
||||
hibernate.connection.username @jdbc.user@
|
||||
hibernate.connection.password @jdbc.pass@
|
||||
|
||||
hibernate.connection.pool_size 5
|
||||
|
||||
hibernate.cache.region_prefix hibernate.test
|
||||
|
||||
hibernate.service.allow_crawling=false
|
|
@ -0,0 +1,17 @@
|
|||
#
|
||||
# Hibernate, Relational Persistence for Idiomatic Java
|
||||
#
|
||||
# License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
# See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
#
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.Target=System.out
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
|
||||
|
||||
log4j.rootLogger=info, stdout
|
||||
|
||||
log4j.logger.org.hibernate.test=info
|
||||
|
||||
# SQL Logging - HHH-6833
|
||||
log4j.logger.org.hibernate.SQL=debug
|
Loading…
Reference in New Issue