Hibernate SVN: r14770 - in search/trunk/src: test/org/hibernate/search/test/reader/functionality and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: sannegrinovero
Date: 2008-06-16 11:43:48 -0400 (Mon, 16 Jun 2008)
New Revision: 14770
Added:
search/trunk/src/test/org/hibernate/search/test/reader/functionality/FilterOnDirectoryTest.java
Modified:
search/trunk/src/java/org/hibernate/search/reader/SharingBufferReaderProvider.java
search/trunk/src/test/org/hibernate/search/test/reader/functionality/SharingBufferIndexProviderTest.java
search/trunk/src/test/org/hibernate/search/test/reader/functionality/TestableSharingBufferReaderProvider.java
search/trunk/src/test/org/hibernate/search/test/reader/performance/ReaderPerformance.java
Log:
HSEARCH-212 : a new ReaderProvider
Modified: search/trunk/src/java/org/hibernate/search/reader/SharingBufferReaderProvider.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/reader/SharingBufferReaderProvider.java 2008-06-16 15:08:45 UTC (rev 14769)
+++ search/trunk/src/java/org/hibernate/search/reader/SharingBufferReaderProvider.java 2008-06-16 15:43:48 UTC (rev 14770)
@@ -1,17 +1,19 @@
package org.hibernate.search.reader;
-import static org.hibernate.search.reader.ReaderProviderHelper.buildMultiReader;
-import static org.hibernate.search.reader.ReaderProviderHelper.clean;
-
import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.MultiReader;
+import org.hibernate.annotations.common.AssertionFailure;
import org.hibernate.search.SearchException;
import org.hibernate.search.engine.SearchFactoryImplementor;
import org.hibernate.search.store.DirectoryProvider;
@@ -19,182 +21,209 @@
import org.slf4j.LoggerFactory;
/**
+ * As does SharedReaderProvider this also shares IndexReaders as long as they are "current";
+ * main difference with SharedReaderProvider is the way to update the Readers when needed:
+ * this uses IndexReader.reopen() which should improve performance on larger indexes
+ * as it shares buffers with previous IndexReader generation for the segments which didn't change.
+ * Current drawbacks are: need of Lucene > 2.3.0 and less mature (experimental).
+ *
* @author Sanne Grinovero
*/
public class SharingBufferReaderProvider implements ReaderProvider {
- //contains last updated Reader; protected by lockOnOpenLatest.
- private volatile ReaderUsagePair current;
+ /**
+ * contains all Readers (most current per DP and all unclosed old)
+ */
+ //TODO ConcurrentHashMap's constructor could benefit from some hints as arguments.
+ protected final Map<IndexReader,ReaderUsagePair> allReaders = new ConcurrentHashMap<IndexReader,ReaderUsagePair>( 100 );
- private final Lock lockOnOpenLatest = new ReentrantLock();
+ /**
+ * contains last updated Reader; protected by lockOnOpenLatest (in the values)
+ */
+ protected Map<DirectoryProvider,PerDirectoryLatestReader> currentReaders;
- //contains all older Readers:
- protected final Map<IndexReader,ReaderUsagePair> oldReaders = new ConcurrentHashMap<IndexReader,ReaderUsagePair>();
-
- private final Logger log = LoggerFactory.getLogger ( SharingBufferReaderProvider.class );
+ private final Logger log = LoggerFactory.getLogger( SharingBufferReaderProvider.class );
- public void closeReader(IndexReader reader) {
- if ( reader == current.reader ) {
- boolean closeit;
- lockOnOpenLatest.lock();
- try {
- if ( reader == current.reader ){
- current.usageCounter.getAndDecrement();
- closeit = false;
- }
- else {
- closeit = true;
- }
- }
- finally {
- lockOnOpenLatest.unlock();
- }
- if ( closeit ) {
- closeOldReader( reader );
- }
+ public void closeReader(IndexReader multiReader) {
+ if ( multiReader == null ) return;
+ IndexReader[] readers;
+ if ( multiReader instanceof MultiReader ) {
+ readers = (IndexReader[]) ReaderProviderHelper.getSubReadersFromMultiReader( (MultiReader) multiReader );
}
else {
- closeOldReader( reader );
+ throw new AssertionFailure( "Everything should be wrapped in a MultiReader" );
}
- printState();
+ log.trace( "Closing MultiReader: {}", multiReader );
+ for ( IndexReader reader : readers ) {
+ ReaderUsagePair container = allReaders.get( reader );
+ container.close();//virtual
+ }
+ log.trace( "IndexReader closed." );
}
- private void closeOldReader(IndexReader reader) {
- try {
- ReaderUsagePair pair = oldReaders.get( reader );
- boolean closed = pair.close(); //also testing "assert pair!=null";
- if ( closed ) {
- //not longer needed, so remove references:
- oldReaders.remove( reader );
- log.trace( "IndexReader closed." );
+ public void initialize(Properties props, SearchFactoryImplementor searchFactoryImplementor) {
+ Map<DirectoryProvider,PerDirectoryLatestReader> map = new HashMap<DirectoryProvider,PerDirectoryLatestReader>();
+ Set<DirectoryProvider> providers = searchFactoryImplementor.getLockableDirectoryProviders().keySet();
+ for ( DirectoryProvider provider : providers ) {
+ try {
+ map.put( provider, new PerDirectoryLatestReader( provider ) );
+ } catch (IOException e) {
+ throw new SearchException( "Unable to open Lucene IndexReader", e );
}
- else {
- log.trace( "Closing of IndexReader skipped: still being used." );
- }
}
- catch (IOException e) {
- log.warn( "Unable to close Lucene IndexReader", e );
- //remove references anyway:
- oldReaders.remove( reader );
- }
+ //FIXME I'm not convinced this non-final fields are safe without locks, but I may be wrong.
+ currentReaders = Collections.unmodifiableMap( map );
}
- public void initialize(Properties props, SearchFactoryImplementor searchFactoryImplementor) {
- //FIXME initialize currentReaderContainer here instead of lazy
- }
-
public IndexReader openReader(DirectoryProvider... directoryProviders) {
boolean trace = log.isTraceEnabled();
- if ( trace ) log.trace( "Opening IndexReader for directoryProviders: {}", directoryProviders );
- IndexReader toReturn;
- lockOnOpenLatest.lock();
- try {
- if ( current == null ) { //FIXME move this case to initialize
- current = initialReaderOpening( directoryProviders );
- log.trace( "IndexReader initialized." );
+ int length = directoryProviders.length;
+ IndexReader[] readers = new IndexReader[length];
+ if ( trace ) log.trace( "Opening IndexReader for directoryProviders: {}", length );
+ for (int index = 0; index < length; index++) {
+ DirectoryProvider directoryProvider = directoryProviders[index];
+ if ( trace ) log.trace( "Opening IndexReader from {}", directoryProvider.getDirectory() );
+ PerDirectoryLatestReader directoryLatestReader = currentReaders.get( directoryProvider );
+ readers[index] = directoryLatestReader.refreshAndGet();
+ }
+ // don't use ReaderProviderHelper.buildMultiReader as we need our own cleanup.
+ if ( length == 0 ) {
+ return null;
+ }
+ else {
+ try {
+ return new CacheableMultiReader( readers );
}
- else {
- reopenIndexreader();
+ catch (Exception e) {
+ //Lucene 2.2 used to throw IOExceptions here
+ for ( IndexReader ir : readers ) {
+ ReaderUsagePair readerUsagePair = allReaders.get( ir );
+ readerUsagePair.close();
+ }
+ throw new SearchException( "Unable to open a MultiReader", e );
}
- toReturn = current.reader; //choose reader before unlock
- } finally {
- lockOnOpenLatest.unlock();
}
- printState();
- return toReturn;
}
- private void reopenIndexreader() {
- // we own the lock
- IndexReader before = current.reader;
- IndexReader updatedReader;
- try {
- updatedReader = before.reopen();
- } catch (IOException e) {
- throw new SearchException( "Unable to reopen IndexReader", e );
+ //overridable method for testability:
+ protected IndexReader readerFactory(DirectoryProvider provider) throws IOException {
+ return IndexReader.open( provider.getDirectory() );
+ }
+
+ /**
+ * Container for the couple IndexReader,UsageCounter.
+ */
+ protected final class ReaderUsagePair {
+
+ public final IndexReader reader;
+ /**
+ * When reaching 0 (always test on change) the reader should be really
+ * closed and then discarded.
+ * Starts at 2 because:
+ * first usage token is artificial: means "current" is not to be closed (+1)
+ * additionally when creating it will be used (+1)
+ */
+ protected final AtomicInteger usageCounter = new AtomicInteger( 2 );
+
+ ReaderUsagePair(IndexReader r) {
+ reader = r;
}
- if ( before == updatedReader ) {
- current.incrementUseCounter();
- }
- else { //store the old one for close() functionality.
- int useCount = current.usageCounter.get();
- if ( useCount != 0 ) {
- oldReaders.put( before, current );
- }
- else {
- //or close it if nobody uses.
+
+ /**
+ * closes the IndexReader if no other resource is using it;
+ * in this case the reference to this container will also be removed.
+ */
+ public void close() {
+ int refCount = usageCounter.decrementAndGet();
+ if ( refCount==0 ) {
+ //TODO I've been experimenting with the idea of an async-close: didn't appear to have an interesting benefit,
+ //so discarded the code. should try with bigger indexes to see if the effect gets more impressive.
+ ReaderUsagePair removed = allReaders.remove( reader );//remove ourself
try {
- current.reader.close();
+ reader.close();
} catch (IOException e) {
log.warn( "Unable to close Lucene IndexReader", e );
}
+ assert removed != null;
}
- current = new ReaderUsagePair( updatedReader );
- }
- }
-
- public final void printState(){
- if ( log.isTraceEnabled())
- log.trace( "Current "+ current + " older:" + oldReaders.values() );
- }
-
- private ReaderUsagePair initialReaderOpening(DirectoryProvider[] directoryProviders) {
- // we own the lock
- final int length = directoryProviders.length;
- IndexReader[] readers = new IndexReader[length];
- try {
- for (int index = 0; index < length; index++) {
- readers[index] = IndexReader.open( directoryProviders[index].getDirectory() );
+ else if ( refCount<0 ) {
+ //doesn't happen with current code, could help spotting future bugs?
+ throw new AssertionFailure( "Closing an IndexReader for which you didn't own a lock-token, or somebody else which didn't own closed already." );
}
}
- catch (IOException e) {
- //TODO more contextual info
- clean( new SearchException( "Unable to open one of the Lucene indexes", e ), readers );
+
+ public String toString(){
+ return "Reader:" + this.hashCode() + " ref.count=" + usageCounter.get();
}
- IndexReader iR = readerFactory( length, readers );
- return new ReaderUsagePair( iR );
+
}
- //overridable method for testability:
- protected IndexReader readerFactory(int length, IndexReader[] readers) {
- return buildMultiReader( length, readers );
- }
-
- protected static class ReaderUsagePair {
- protected final IndexReader reader;
- protected final AtomicInteger usageCounter;
+ /**
+ * An instance for each DirectoryProvider,
+ * establishing the association between "current" ReaderUsagePair
+ * for a DirectoryProvider and it's lock.
+ */
+ protected final class PerDirectoryLatestReader {
- ReaderUsagePair(IndexReader r) {
- reader = r;
- usageCounter = new AtomicInteger( 1 );
- }
+ /**
+ * Reference to the most current IndexReader for a DirectoryProvider;
+ * guarded by lockOnReplaceCurrent;
+ */
+ public ReaderUsagePair current; //guarded by lockOnReplaceCurrent
+ private final Lock lockOnReplaceCurrent = new ReentrantLock();
- void incrementUseCounter() {
- usageCounter.incrementAndGet();
+ /**
+ * @param provider The DirectoryProvider for which we manage the IndexReader.
+ * @throws IOException when the index initialization fails.
+ */
+ public PerDirectoryLatestReader(DirectoryProvider provider) throws IOException {
+ IndexReader reader = readerFactory( provider );
+ ReaderUsagePair initialPair = new ReaderUsagePair( reader );
+ initialPair.usageCounter.set( 1 );//a token to mark as active (preventing real close).
+ lockOnReplaceCurrent.lock();//no harm, just ensuring safe publishing.
+ current = initialPair;
+ lockOnReplaceCurrent.unlock();
+ allReaders.put( reader, initialPair );
}
-
- public int getUsageCount(){
- return usageCounter.get();
- }
/**
- * @return true when really closing the underlying IndexReader
- * @throws IOException
+ * Gets an updated IndexReader for the current DirectoryProvider;
+ * the index status will be checked.
+ * @return the current IndexReader if it's in sync with underlying index, a new one otherwise.
*/
- private boolean close() throws IOException {
- int count = usageCounter.decrementAndGet();
- if ( count == 0 ) {
- reader.close();
- return true;
+ public IndexReader refreshAndGet() {
+ ReaderUsagePair previousCurrent;
+ IndexReader updatedReader;
+ lockOnReplaceCurrent.lock();
+ try {
+ IndexReader beforeUpdateReader = current.reader;
+ try {
+ updatedReader = beforeUpdateReader.reopen();
+ } catch (IOException e) {
+ throw new SearchException( "Unable to reopen IndexReader", e );
+ }
+ if ( beforeUpdateReader == updatedReader ) {
+ previousCurrent = null;
+ current.usageCounter.incrementAndGet();
+ }
+ else {
+ ReaderUsagePair newPair = new ReaderUsagePair( updatedReader );
+ //no need to increment usageCounter in newPair, as it is constructed with correct number 2.
+ assert newPair.usageCounter.get() == 2;
+ previousCurrent = current;
+ current = newPair;
+ allReaders.put( updatedReader, newPair );//unfortunately still needs lock
+ }
+ } finally {
+ lockOnReplaceCurrent.unlock();
}
- assert count >= 0;
- return false;
+ // doesn't need lock:
+ if ( previousCurrent != null ) {
+ previousCurrent.close();// release a token as it's not the current any more.
+ }
+ return updatedReader;
}
- public String toString(){
- return "Reader:"+this.hashCode()+" count="+usageCounter.get();
- }
-
}
-
+
}
Added: search/trunk/src/test/org/hibernate/search/test/reader/functionality/FilterOnDirectoryTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/functionality/FilterOnDirectoryTest.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/reader/functionality/FilterOnDirectoryTest.java 2008-06-16 15:43:48 UTC (rev 14770)
@@ -0,0 +1,70 @@
+package org.hibernate.search.test.reader.functionality;
+
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.search.Environment;
+import org.hibernate.search.FullTextQuery;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.Search;
+import org.hibernate.search.reader.SharingBufferReaderProvider;
+import org.hibernate.search.test.SearchTestCase;
+import org.hibernate.search.test.reader.Detective;
+import org.hibernate.search.test.reader.Suspect;
+
+public class FilterOnDirectoryTest extends SearchTestCase {
+
+ public void testFilteredClasses() throws Exception {
+ createDoeFamily();
+ FullTextSession fts = Search.createFullTextSession( openSession() );
+ Transaction tx = fts.beginTransaction();
+ Query q = new TermQuery( new Term( "name", "doe" ) );
+
+ assertEquals( 2, fts.createFullTextQuery( q ).getResultSize() );
+ assertEquals( 2, fts.createFullTextQuery( q, Detective.class, Suspect.class ).getResultSize() );
+
+ FullTextQuery detectiveQuery = fts.createFullTextQuery( q, Detective.class );
+ assertEquals( 1, detectiveQuery.getResultSize() );
+ assertTrue( detectiveQuery.list().get(0) instanceof Detective );
+
+ FullTextQuery suspectQuery = fts.createFullTextQuery( q, Suspect.class );
+ assertEquals( 1, suspectQuery.getResultSize() );
+ assertTrue( suspectQuery.list().get(0) instanceof Suspect );
+
+ assertEquals( 2, fts.createFullTextQuery( q ).getResultSize() );
+ assertEquals( 2, fts.createFullTextQuery( q, Detective.class, Suspect.class ).getResultSize() );
+
+ tx.commit();
+ fts.close();
+ }
+
+ private void createDoeFamily() {
+ Session s = openSession( );
+ Transaction tx = s.beginTransaction();
+ Detective detective = new Detective();
+ detective.setName( "John Doe" );
+ s.persist( detective );
+ Suspect suspect = new Suspect();
+ suspect.setName( "Jane Doe" );
+ s.persist( suspect );
+ tx.commit();
+ s.close();
+ }
+
+ protected void configure(org.hibernate.cfg.Configuration cfg) {
+ super.configure( cfg );
+ cfg.setProperty( Environment.ANALYZER_CLASS, StandardAnalyzer.class.getName() );
+ cfg.setProperty( Environment.READER_STRATEGY, SharingBufferReaderProvider.class.getName() );
+ }
+
+ protected Class[] getMappings() {
+ return new Class[] {
+ Detective.class,
+ Suspect.class
+ };
+ }
+
+}
Modified: search/trunk/src/test/org/hibernate/search/test/reader/functionality/SharingBufferIndexProviderTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/functionality/SharingBufferIndexProviderTest.java 2008-06-16 15:08:45 UTC (rev 14769)
+++ search/trunk/src/test/org/hibernate/search/test/reader/functionality/SharingBufferIndexProviderTest.java 2008-06-16 15:43:48 UTC (rev 14770)
@@ -1,12 +1,18 @@
package org.hibernate.search.test.reader.functionality;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.lucene.index.IndexReader;
+import org.hibernate.search.store.DirectoryProvider;
import org.hibernate.search.test.reader.functionality.TestableSharingBufferReaderProvider.MockIndexReader;
+import org.hibernate.search.test.reader.functionality.TestableSharingBufferReaderProvider.TestManipulatorPerDP;
import junit.framework.TestCase;
@@ -21,24 +27,27 @@
private final Runnable changeTask = new ChangeTask();
private final AtomicInteger countDoneSearches = new AtomicInteger();
private final AtomicInteger countDoneIndexmods = new AtomicInteger();
- private static final int SEARCHES_NUM = 5000;
+ private static final int SEARCHES_NUM = 50000;
+ private static final Random random = new Random();
public void testStressingMock() throws InterruptedException {
+ readerProvider.initialize(null, null);
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool( 200 );//much chaos
for ( int i = 0; i < SEARCHES_NUM; i++ ) {
executor.execute( makeTask( i ) );
}
executor.shutdown();
startSignal.countDown();
- executor.awaitTermination( 15, TimeUnit.SECONDS );
- assertTrue( "memory leak: holding a reference to some unused IndexReader", readerProvider.isMapEmpty() );
- MockIndexReader openReader = readerProvider.fakeOpenReader();
+ executor.awaitTermination( 500, TimeUnit.SECONDS );
+ assertTrue( "memory leak: holding a reference to some unused IndexReader", readerProvider.areAllOldReferencesGone() );
for ( MockIndexReader reader : readerProvider.getCreatedIndexReaders() ) {
- if ( reader != openReader ) {
+ if ( readerProvider.isReaderCurrent( reader ) ) {
+ assertTrue( "the most current reader should be open", ! reader.isClosed() );
+ }
+ else {
assertTrue( "an IndexReader is still open", reader.isClosed() );
}
}
- assertTrue( "the most current reader should be open", ! openReader.isClosed() );
assertEquals( SEARCHES_NUM, countDoneSearches.get() );
assertEquals( SEARCHES_NUM/10, countDoneIndexmods.get() );
}
@@ -52,6 +61,18 @@
}
}
+ private DirectoryProvider[] getRandomEvailableDPs() {
+ int arraySize = random.nextInt( readerProvider.manipulators.size() - 1 ) + 1;
+ DirectoryProvider[] array = new DirectoryProvider[arraySize];
+ List<DirectoryProvider> availableDPs = new ArrayList<DirectoryProvider>( readerProvider.manipulators.keySet() );
+ for (int i=0; i<arraySize; i++){
+ int chosenDpIndex = random.nextInt( availableDPs.size() );
+ array[i] = availableDPs.get( chosenDpIndex );
+ availableDPs.remove( array[i] );
+ }
+ return array;
+ }
+
private class SearchTask implements Runnable {
public void run() {
try {
@@ -60,7 +81,7 @@
//manage termination:
return;
}
- MockIndexReader fakeOpenReader = readerProvider.fakeOpenReader();
+ IndexReader fakeOpenReader = readerProvider.openReader( getRandomEvailableDPs() );
Thread.yield();
readerProvider.closeReader( fakeOpenReader );
countDoneSearches.incrementAndGet();
@@ -71,7 +92,11 @@
public void run() {
super.run();
Thread.yield();
- readerProvider.setToDirtyState();
+ DirectoryProvider[] randomEvailableDPs = getRandomEvailableDPs();
+ for ( DirectoryProvider dp : randomEvailableDPs ) {
+ TestManipulatorPerDP testManipulatorPerDP = readerProvider.manipulators.get( dp );
+ testManipulatorPerDP.setIndexChanged();
+ }
countDoneIndexmods.incrementAndGet();
}
}
Modified: search/trunk/src/test/org/hibernate/search/test/reader/functionality/TestableSharingBufferReaderProvider.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/functionality/TestableSharingBufferReaderProvider.java 2008-06-16 15:08:45 UTC (rev 14769)
+++ search/trunk/src/test/org/hibernate/search/test/reader/functionality/TestableSharingBufferReaderProvider.java 2008-06-16 15:43:48 UTC (rev 14770)
@@ -2,69 +2,129 @@
import java.io.IOException;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Properties;
import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.FieldSelector;
import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.MultiReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.index.TermEnum;
import org.apache.lucene.index.TermFreqVector;
import org.apache.lucene.index.TermPositions;
import org.apache.lucene.index.TermVectorMapper;
+import org.hibernate.search.SearchException;
+import org.hibernate.search.engine.SearchFactoryImplementor;
+import org.hibernate.search.reader.ReaderProviderHelper;
import org.hibernate.search.reader.SharingBufferReaderProvider;
import org.hibernate.search.store.DirectoryProvider;
+import org.hibernate.search.store.RAMDirectoryProvider;
/**
* @author Sanne Grinovero
*/
public class TestableSharingBufferReaderProvider extends SharingBufferReaderProvider {
- private final AtomicBoolean isIndexReaderCurrent = new AtomicBoolean( false );//starts at true, see MockIndexReader contructor
- private final AtomicBoolean factoryCalled = new AtomicBoolean( false );
+ private static final int NUM_DIRECTORY_PROVIDERS = 4;
private final Vector<MockIndexReader> createdReadersHistory = new Vector<MockIndexReader>( 500 );
- private final MockIndexReader firstIndexReader = new MockIndexReader();
+ final Map<DirectoryProvider,TestManipulatorPerDP> manipulators = new ConcurrentHashMap<DirectoryProvider,TestManipulatorPerDP>();
+ public TestableSharingBufferReaderProvider() {
+ for (int i=0; i<NUM_DIRECTORY_PROVIDERS; i++) {
+ TestManipulatorPerDP tm = new TestManipulatorPerDP( i );
+ manipulators.put( tm.dp, tm );
+ }
+ }
+
+ public static class TestManipulatorPerDP {
+ private final AtomicBoolean isIndexReaderCurrent = new AtomicBoolean( false );//starts at true, see MockIndexReader contructor
+ private final AtomicBoolean isReaderCreated = new AtomicBoolean( false );
+ private final DirectoryProvider dp = new RAMDirectoryProvider();
+
+ public TestManipulatorPerDP( int seed ) {
+ dp.initialize( "dp" + seed, null, null );
+ dp.start();
+ }
+
+ public void setIndexChanged() {
+ isIndexReaderCurrent.set( false );
+ }
+
+ }
+
+ public boolean isReaderCurrent(MockIndexReader reader) {
+ //avoid usage of allReaders or test would be useless
+ for (PerDirectoryLatestReader latest : super.currentReaders.values() ) {
+ IndexReader latestReader = latest.current.reader;
+ if ( latestReader == reader) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
- protected IndexReader readerFactory(int length, IndexReader[] readers) {
- if ( factoryCalled.compareAndSet( false, true) ) {
- return firstIndexReader;
+ protected IndexReader readerFactory(DirectoryProvider provider) {
+ TestManipulatorPerDP manipulatorPerDP = manipulators.get( provider );
+ if ( ! manipulatorPerDP.isReaderCreated.compareAndSet( false, true ) ) {
+ throw new IllegalStateException( "IndexReader1 created twice" );
}
else {
- throw new IllegalStateException( "factory for reader called more than once" );
+ return new MockIndexReader( manipulatorPerDP.isIndexReaderCurrent );
}
}
- public void setToDirtyState() {
- isIndexReaderCurrent.set( false );
+ @Override
+ public void initialize(Properties props, SearchFactoryImplementor searchFactoryImplementor) {
+ Map<DirectoryProvider,PerDirectoryLatestReader> map = new HashMap<DirectoryProvider,PerDirectoryLatestReader>();
+ try {
+ for ( DirectoryProvider dp : manipulators.keySet() ) {
+ map.put( dp, new PerDirectoryLatestReader( dp ) );
+ }
+ } catch (IOException e) {
+ throw new SearchException( "Unable to open Lucene IndexReader", e );
+ }
+ currentReaders = Collections.unmodifiableMap( map );
}
- public boolean isMapEmpty(){
- return super.oldReaders.isEmpty();
+ public boolean areAllOldReferencesGone() {
+ int numReferencesReaders = super.allReaders.size();
+ int numExpectedActiveReaders = manipulators.size();
+ return numReferencesReaders == numExpectedActiveReaders;
}
public List<MockIndexReader> getCreatedIndexReaders(){
return createdReadersHistory;
}
- public MockIndexReader fakeOpenReader() {
-// System.out.println( "tracking "+oldReaders.size() + " old readers." );
- return (MockIndexReader) super.openReader( new DirectoryProvider[0] );
+ public MockIndexReader getCurrentMockReaderPerDP(DirectoryProvider dp) {
+ IndexReader[] indexReaders = ReaderProviderHelper.getSubReadersFromMultiReader( (MultiReader) super.openReader( new DirectoryProvider[]{ dp } ) );
+ if ( indexReaders.length != 1 ){
+ throw new IllegalStateException( "Expecting one reader" );
+ }
+ return (MockIndexReader) indexReaders[0];
}
public class MockIndexReader extends IndexReader {
private final AtomicBoolean closed = new AtomicBoolean( false );
private final AtomicBoolean hasAlreadyBeenReOpened = new AtomicBoolean( false );
+ private final AtomicBoolean isIndexReaderCurrent;
- MockIndexReader(){
- createdReadersHistory.add( this );
+ MockIndexReader(AtomicBoolean isIndexReaderCurrent) {
+ this.isIndexReaderCurrent = isIndexReaderCurrent;
if ( ! isIndexReaderCurrent.compareAndSet(false, true) ) {
throw new IllegalStateException( "Unnecessarily reopened" );
}
+ createdReadersHistory.add( this );
}
public final boolean isClosed() {
@@ -73,11 +133,11 @@
@Override
protected void doClose() throws IOException {
- boolean okToClose = closed.compareAndSet(false, true);
+ boolean okToClose = closed.compareAndSet( false, true );
if ( ! okToClose ) {
throw new IllegalStateException( "Attempt to close a closed IndexReader" );
}
- if ( ! hasAlreadyBeenReOpened.get() ){
+ if ( ! hasAlreadyBeenReOpened.get() ) {
throw new IllegalStateException( "Attempt to close the most current IndexReader" );
}
}
@@ -89,7 +149,7 @@
}
else {
if ( hasAlreadyBeenReOpened.compareAndSet( false, true) ) {
- return new MockIndexReader();
+ return new MockIndexReader( isIndexReaderCurrent );
}
else
throw new IllegalStateException( "Attempt to reopen an old IndexReader more than once" );
@@ -153,7 +213,7 @@
@Override
public boolean hasDeletions() {
- throw new UnsupportedOperationException();
+ return false;//just something to make MultiReader constructor happy
}
@Override
@@ -163,7 +223,7 @@
@Override
public int maxDoc() {
- throw new UnsupportedOperationException();
+ return 10;//just something to make MultiReader constructor happy
}
@Override
Modified: search/trunk/src/test/org/hibernate/search/test/reader/performance/ReaderPerformance.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/performance/ReaderPerformance.java 2008-06-16 15:08:45 UTC (rev 14769)
+++ search/trunk/src/test/org/hibernate/search/test/reader/performance/ReaderPerformance.java 2008-06-16 15:43:48 UTC (rev 14770)
@@ -31,11 +31,11 @@
//more iterations for more reliable measures:
private static final int TOTAL_WORK_BATCHES = 1000;
//the next 3 define the kind of workload mix to test on:
- private static final int SEARCHERS_PER_BATCH = 20;
+ private static final int SEARCHERS_PER_BATCH = 10;
private static final int UPDATES_PER_BATCH = 2;
private static final int INSERTIONS_PER_BATCH = 1;
- private static final int WORKER_THREADS = 20;
+ private static final int WORKER_THREADS = 30;
protected void setUp() throws Exception {
baseIndexDir.mkdir();
@@ -78,7 +78,7 @@
// FileHelper.delete( baseIndexDir );
}
- protected final void configure(org.hibernate.cfg.Configuration cfg) {
+ protected void configure(org.hibernate.cfg.Configuration cfg) {
super.configure( cfg );
cfg.setProperty( "hibernate.search.default.directory_provider", FSDirectoryProvider.class.getName() );
cfg.setProperty( "hibernate.search.default.indexBase", baseIndexDir.getAbsolutePath() );
@@ -89,8 +89,8 @@
protected abstract String getReaderStrategyName();
- //this test is disabled as it is very slow (and you should read the resulting numbers)
- public final void no_testPerformance() throws InterruptedException{
+ //this test is disabled as it is very slow (and someone should read the output)
+ public final void disabled_testPerformance() throws InterruptedException{
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool( WORKER_THREADS );
CountDownLatch startSignal = new CountDownLatch(1);
InsertActivity insertionTask = new InsertActivity( getSessions(), startSignal );
16 years, 7 months
Hibernate SVN: r14769 - search/trunk/src/java/org/hibernate/search/reader.
by hibernate-commits@lists.jboss.org
Author: sannegrinovero
Date: 2008-06-16 11:08:45 -0400 (Mon, 16 Jun 2008)
New Revision: 14769
Modified:
search/trunk/src/java/org/hibernate/search/reader/ReaderProviderHelper.java
search/trunk/src/java/org/hibernate/search/reader/SharedReaderProvider.java
Log:
moved IndexReader extraction from SharedReaderProvider to ReaderProviderHelper.getSubReadersFromMultiReader
Modified: search/trunk/src/java/org/hibernate/search/reader/ReaderProviderHelper.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/reader/ReaderProviderHelper.java 2008-06-15 14:39:42 UTC (rev 14768)
+++ search/trunk/src/java/org/hibernate/search/reader/ReaderProviderHelper.java 2008-06-16 15:08:45 UTC (rev 14769)
@@ -2,10 +2,12 @@
package org.hibernate.search.reader;
import java.io.IOException;
+import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.MultiReader;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MultiSearcher;
import org.apache.lucene.search.Searchable;
@@ -15,6 +17,28 @@
* @author Emmanuel Bernard
*/
public abstract class ReaderProviderHelper {
+
+ private static final Field subReadersField = getSubReadersField();
+
+ private static Field getSubReadersField() {
+ try {
+ Field field = MultiReader.class.getDeclaredField( "subReaders" );
+ if ( ! field.isAccessible() ) field.setAccessible( true );
+ return field;
+ }
+ catch (NoSuchFieldException e) {
+ throw new SearchException( "Incompatible version of Lucene: MultiReader.subReaders not available", e );
+ }
+ }
+
+ public static IndexReader[] getSubReadersFromMultiReader(MultiReader parentReader) {
+ try {
+ return (IndexReader[]) subReadersField.get( parentReader );
+ } catch (IllegalAccessException e) {
+ throw new SearchException( "Incompatible version of Lucene: MultiReader.subReaders not accessible", e );
+ }
+ }
+
@SuppressWarnings( { "ThrowableInstanceNeverThrown" } )
public static IndexReader buildMultiReader(int length, IndexReader[] readers) {
if ( length == 0 ) {
Modified: search/trunk/src/java/org/hibernate/search/reader/SharedReaderProvider.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/reader/SharedReaderProvider.java 2008-06-15 14:39:42 UTC (rev 14768)
+++ search/trunk/src/java/org/hibernate/search/reader/SharedReaderProvider.java 2008-06-16 15:08:45 UTC (rev 14769)
@@ -2,7 +2,6 @@
package org.hibernate.search.reader;
import java.io.IOException;
-import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -28,7 +27,6 @@
* @author Emmanuel Bernard
*/
public class SharedReaderProvider implements ReaderProvider {
- private static Field subReadersField;
private final Logger log = LoggerFactory.getLogger ( SharedReaderProvider.class );
/**
* nonfair lock. Need to be acquired on indexReader acquisition or release (semaphore)
@@ -151,7 +149,7 @@
if ( outOfDateReader != null ) {
ReaderData readerData = searchIndexReaderSemaphores.get( outOfDateReader );
if ( readerData == null ) {
- closeOutOfDateReader = false; //already removed by another prevous thread
+ closeOutOfDateReader = false; //already removed by another previous thread
}
else if ( readerData.semaphore == 0 ) {
searchIndexReaderSemaphores.remove( outOfDateReader );
@@ -211,12 +209,7 @@
IndexReader[] readers;
//TODO should it be CacheableMultiReader? Probably no
if ( reader instanceof MultiReader ) {
- try {
- readers = (IndexReader[]) subReadersField.get( reader );
- }
- catch (IllegalAccessException e) {
- throw new SearchException( "Incompatible version of Lucene: MultiReader.subReaders not accessible", e );
- }
+ readers = ReaderProviderHelper.getSubReadersFromMultiReader( (MultiReader) reader );
if ( trace ) log.trace( "Closing MultiReader: {}", reader );
}
else {
@@ -289,15 +282,6 @@
}
public void initialize(Properties props, SearchFactoryImplementor searchFactoryImplementor) {
- if ( subReadersField == null ) {
- try {
- subReadersField = MultiReader.class.getDeclaredField( "subReaders" );
- if ( !subReadersField.isAccessible() ) subReadersField.setAccessible( true );
- }
- catch (NoSuchFieldException e) {
- throw new SearchException( "Incompatible version of Lucene: MultiReader.subReaders not accessible", e );
- }
- }
Set<DirectoryProvider> providers = searchFactoryImplementor.getLockableDirectoryProviders().keySet();
perDirectoryProviderManipulationLocks = new HashMap<DirectoryProvider, Lock>( providers.size() );
for (DirectoryProvider dp : providers) {
16 years, 7 months
Hibernate SVN: r14768 - core/tags/v326/doc/reference/ko/modules.
by hibernate-commits@lists.jboss.org
Author: jdkim528
Date: 2008-06-15 10:39:42 -0400 (Sun, 15 Jun 2008)
New Revision: 14768
Modified:
core/tags/v326/doc/reference/ko/modules/basic_mapping.xml
core/tags/v326/doc/reference/ko/modules/batch.xml
core/tags/v326/doc/reference/ko/modules/filters.xml
core/tags/v326/doc/reference/ko/modules/persistent_classes.xml
core/tags/v326/doc/reference/ko/modules/query_hql.xml
core/tags/v326/doc/reference/ko/modules/query_sql.xml
core/tags/v326/doc/reference/ko/modules/tutorial.xml
Log:
updated!
Modified: core/tags/v326/doc/reference/ko/modules/basic_mapping.xml
===================================================================
--- core/tags/v326/doc/reference/ko/modules/basic_mapping.xml 2008-06-15 14:36:50 UTC (rev 14767)
+++ core/tags/v326/doc/reference/ko/modules/basic_mapping.xml 2008-06-15 14:39:42 UTC (rev 14768)
@@ -1,7 +1,7 @@
<chapter id="mapping">
<title>기본 O/R 매핑</title>
- <sect1 id="mapping-declaration" revision="1">
+ <sect1 id="mapping-declaration" revision="2">
<title>매핑 선언</title>
<para>
@@ -26,22 +26,22 @@
<hibernate-mapping package="eg">
- <class name="Cat"
+ <class name="Cat"
table="cats"
discriminator-value="C">
-
+
<id name="id">
<generator class="native"/>
</id>
- <discriminator column="subclass"
+ <discriminator column="subclass"
type="character"/>
<property name="weight"/>
<property name="birthdate"
- type="date"
- not-null="true"
+ type="date"
+ not-null="true"
update="false"/>
<property name="color"
@@ -50,7 +50,7 @@
update="false"/>
<property name="sex"
- not-null="true"
+ not-null="true"
update="false"/>
<property name="litterId"
@@ -71,7 +71,7 @@
<subclass name="DomesticCat"
discriminator-value="D">
- <property name="name"
+ <property name="name"
type="string"/>
</subclass>
@@ -85,9 +85,9 @@
</hibernate-mapping>]]></programlisting>
<para>
- 우리는 이제 매핑 문서의 내용을 논의할 것이다. 우리는 Hibernate에 의해 실행 시에 사용되는 문서 요소들과
- 속성들 만을 설명할 것이다. 매핑 문서는 또한 스키마 내보내기 도구에 의해 내보내진 데이터베이스 스키마에
- 영향을 주는 어떤 특별한 옵션 속성들과 요소들을 포함한다. (예를 들어 <literal>not-null</literal> 속성.)
+ 우리는 이제 매핑 문서의 내용을 논의할 것이다. 우리는 Hibernate에 의해 실행 시에 사용되는 문서 요소들과
+ 속성들 만을 설명할 것이다. 매핑 문서는 또한 스키마 내보내기 도구에 의해 내보내진 데이터베이스 스키마에
+ 영향을 주는 어떤 특별한 옵션 속성들과 요소들을 포함한다. (예를 들어 <literal>not-null</literal> 속성.)
</para>
@@ -148,8 +148,8 @@
&types;
</hibernate-mapping>]]></programlisting>
<para>
- 여기서 <literal>types.xml</literal>은 <literal>your.domain</literal> 패키지 내에 있는 리소스이고
- 맞춤형 <xref linkend="mapping-types-custom">typedef</xref>를 포함한다.
+ 여기서 <literal>types.xml</literal>은 <literal>your.domain</literal> 패키지 내에 있는 리소스이고
+ 맞춤형 <xref linkend="mapping-types-custom">typedef</xref>를 포함한다.
</para>
</sect3>
</sect2>
@@ -158,11 +158,11 @@
<title>hibernate-mapping</title>
<para>
- 이 요소는 몇 개의 선택적인 속성들을 갖는다. <literal>schema</literal> 속성과 <literal>catalog</literal>
- 속성은 이 매핑 내에서 참조된 테이블들이 명명된 schema 와/또는 catalog에 속한다는 점을 지정한다. 만일 지정될 경우,
- 테이블 이름들은 주어진 schema 이름과 catalog 이름에 의해 한정(수식)될 것이다. 누락될 경우, 테이블 이름들은
- 한정되지((수식어가 붙지) 않을 것이다. <literal>default-cascade</literal> 속성은 <literal>cascade</literal>
- 속성을 지정하지 않은 프로퍼티들과 콜렉션들에 대해 전제될 <literal>cascade</literal> 스타일이 무엇인지를 지정한다.
+ 이 요소는 몇 개의 선택적인 속성들을 갖는다. <literal>schema</literal> 속성과 <literal>catalog</literal>
+ 속성은 이 매핑 내에서 참조된 테이블들이 명명된 schema 와/또는 catalog에 속한다는 점을 지정한다. 만일 지정될 경우,
+ 테이블 이름들은 주어진 schema 이름과 catalog 이름에 의해 한정(수식)될 것이다. 누락될 경우, 테이블 이름들은
+ 한정되지((수식어가 붙지) 않을 것이다. <literal>default-cascade</literal> 속성은 <literal>cascade</literal>
+ 속성을 지정하지 않은 프로퍼티들과 콜렉션들에 대해 전제될 <literal>cascade</literal> 스타일이 무엇인지를 지정한다.
<literal>auto-import</literal> 속성은 디폴트로 우리가 질의 언어 속에서 수식어가 붙지 않은(unqualified)
클래스 이름들을 사용하게 할 것이다.
</para>
@@ -250,9 +250,9 @@
<title>class</title>
<para>
- 당신은 <literal>class</literal> 요소를 사용하여 영속 클래스를 선언할 수도 있다:
+ 당신은 <literal>class</literal> 요소를 사용하여 영속 클래스를 선언할 수도 있다:
</para>
-
+
<programlistingco>
<areaspec>
<area id="class1" coords="2 55"/>
@@ -305,7 +305,7 @@
<callout arearefs="class1">
<para>
<literal>name</literal> (옵션): 영속 클래스(또는 인터페이스)의 전체 수식어가 붙은 Java 클래스 이름.
- 만일 이 속성이 누락될 경우, 매핑이 non-POJO 엔티티라고 가정된다.
+ 만일 이 속성이 누락될 경우, 매핑이 non-POJO 엔티티라고 가정된다.
</para>
</callout>
<callout arearefs="class2">
@@ -316,7 +316,7 @@
<callout arearefs="class3">
<para>
<literal>discriminator-value</literal> (옵션 - 디폴트는 클래스 이름): 다형성(polymorphic) 특징에 사용되는,
- 개별 서브 클래스들를 구별짓는 값. 허용가능한 값들은<literal>null</literal>과 <literal>not null</literal>을 포함한다.
+ 개별 서브 클래스들를 구별짓는 값. 허용가능한 값들은<literal>null</literal>과 <literal>not null</literal>을 포함한다.
</para>
</callout>
<callout arearefs="class4">
@@ -328,43 +328,43 @@
<callout arearefs="class5">
<para>
<literal>schema</literal> (옵션): 루트 <literal><hibernate-mapping></literal> 요소에 의해 지정된
- 스키마 이름을 오버라이드 시킨다.
+ 스키마 이름을 오버라이드 시킨다.
</para>
</callout>
<callout arearefs="class6">
<para>
<literal>catalog</literal> (옵션): 루트 <literal><hibernate-mapping></literal> 요소에 의해 지정된
- 카다록 이름을 오버라이드 시킨다.
+ 카다록 이름을 오버라이드 시킨다.
</para>
</callout>
<callout arearefs="class7">
<para>
<literal>proxy</literal> (옵션): lazy initializing proxy들에 사용할 인터페이스를 지정한다. 당신은 클래스
- 그 자체의 이름을 지정할 수 도 있다.
+ 그 자체의 이름을 지정할 수 도 있다.
</para>
</callout>
<callout arearefs="class8">
<para>
<literal>dynamic-update</literal> (옵션 - 디폴트는 <literal>false</literal>):
<literal>UPDATE</literal> SQL이 실행 시에 생성되고 그들 컬럼들의 값들이 변경된 그들 컬럼들 만을
- 포함할 것인지를 지정한다.
+ 포함할 것인지를 지정한다.
</para>
</callout>
<callout arearefs="class9">
<para>
<literal>dynamic-insert</literal> (옵션 - 디폴트는 <literal>false</literal>):
- 생성될 <literal>INSERT</literal>이 실행 시에 생성되고 그들 컬럼들의 값이 null이 아닌 컬럼들 만을
- 포함할 것인지를 지정한다.
+ 생성될 <literal>INSERT</literal>이 실행 시에 생성되고 그들 컬럼들의 값이 null이 아닌 컬럼들 만을
+ 포함할 것인지를 지정한다.
</para>
</callout>
<callout arearefs="class10">
<para>
<literal>select-before-update</literal> (옵션 - 디폴트는 <literal>false</literal>):
- 객체가 실제로 변경되는 것이 확실하지 않는 한, Hibernate가 SQL <literal>UPDATE</literal>를
+ 객체가 실제로 변경되는 것이 확실하지 않는 한, Hibernate가 SQL <literal>UPDATE</literal>를
<emphasis>결코</emphasis> 실행하지 않을 것임을 지정한다. 어떤 경우들에서(실제로 transient
- 객체가 <literal>update()</literal>를 사용하여 새로운 session에 연관되었을 때에만), 이것은
- 하나의 <literal>UPDATE</literal>가 실제로 필요한 경우인지 여부를 결정하기 위해 Hibernate는
- 특별한 SQL <literal>SELECT</literal>를 실행할 것임을 의미한다.
+ 객체가 <literal>update()</literal>를 사용하여 새로운 session에 연관되었을 때에만), 이것은
+ 하나의 <literal>UPDATE</literal>가 실제로 필요한 경우인지 여부를 결정하기 위해 Hibernate는
+ 특별한 SQL <literal>SELECT</literal>를 실행할 것임을 의미한다.
</para>
</callout>
<callout arearefs="class11">
@@ -387,7 +387,7 @@
<callout arearefs="class14">
<para>
<literal>batch-size</literal> (옵션 - 디폴트는 <literal>1</literal>) 식별자에 의해 이 클래스의
- 인스턴스들을 페치시키는 "배치 사이즈"를 지정한다.
+ 인스턴스들을 페치시키는 "배치 사이즈"를 지정한다.
</para>
</callout>
<callout arearefs="class15">
@@ -406,10 +406,10 @@
<para>
<literal>entity-name</literal>(옵션, 디폴트는 클래스 이름): Hibernate3는 하나의 클래스가
(잠정적으로 다른 테이블들로) 여러번 매핑되는 것을 허용해주고, Java 레벨에서 Map 또는 XML에 의해 표현
- 되는 엔티티 매핑들을 허용한다. 이들 경우들에서, 당신은 그 엔티티에 대한 명시적인 임의의 이름을 제공해야 한다.
+ 되는 엔티티 매핑들을 허용한다. 이들 경우들에서, 당신은 그 엔티티에 대한 명시적인 임의의 이름을 제공해야 한다.
<literal>entity-name</literal> (옵션): Hibernate3는 하나의 클래스가 (잠정적으로 다른 테이블들로)
- 여러 번 매핑되는 것을 허용하며, 자바 레벨에서 Map들 또는 XML에 의해 표현되는 엔티티 매핑들을 허용한다.
- 이들 경우들에서, 당신은 그 엔티티들에 대한 명시적인 임의의 이름을 제공해야 한다. 추가 정보는
+ 여러 번 매핑되는 것을 허용하며, 자바 레벨에서 Map들 또는 XML에 의해 표현되는 엔티티 매핑들을 허용한다.
+ 이들 경우들에서, 당신은 그 엔티티들에 대한 명시적인 임의의 이름을 제공해야 한다. 추가 정보는
<xref linkend="persistent-classes-dynamicmodels"/>과 <xref linkend="xml"/>을 보라.
</para>
</callout>
@@ -423,14 +423,14 @@
<para>
<literal>rowid</literal> (옵션): Hibernate는 지원되는 데이터베이스들, 예를 들어 Oracle 상에서 이른바
ROWID들을 사용할 수 있고, Hibernate는 당신이 이 옵션을 <literal>rowid</literal>로 설정하는 경우에 빠른
- 업데이트를 위한 특별한 <literal>rowid</literal> 컬럼을 사용할 수 있다. ROWID는 구현 상세이고 저장된
- 튜플(tuple)의 물리적이니 위치를 표현한다.
+ 업데이트를 위한 특별한 <literal>rowid</literal> 컬럼을 사용할 수 있다. ROWID는 구현 상세이고 저장된
+ 튜플(tuple)의 물리적이니 위치를 표현한다.
</para>
</callout>
<callout arearefs="class20">
<para>
<literal>subselect</literal> (옵션): 불변의 읽기 전용 엔티티를 데이터베이스 subselect로 매핑시킨다.
- 당신이 기본 테이블 대신에 뷰를 갖고자 원할 경우에 유용하지만, 사용을 자제하라. 추가 정보는 아래를 보라.
+ 당신이 기본 테이블 대신에 뷰를 갖고자 원할 경우에 유용하지만, 사용을 자제하라. 추가 정보는 아래를 보라.
</para>
</callout>
<callout arearefs="class21">
@@ -746,10 +746,10 @@
<term><literal>sequence-identity</literal></term>
<listitem>
<para>
- 실제 값 생성을 위해 데이터베이스 시퀀스를 활용하지만, 생성된 식별자 값을 insert 문장 실행의 부분으로서
- 실제로 반환시키기 위해 이것을 JDBC3 getGeneratedKeys와 결합시킨 특화된 시퀀스 생성 방도. 이 방도는
- JDK 1.4에 대상화된 Oracle 10g 드라이버들 상에서만 지원되는 거승로 알려져 있다. 이들 insert 문장들에
- 대한 주석들은 Oracle 드라이버들 내에 있는 버그 때문에 사용불가능하게 되어 있음을 노트하라.
+ 실제 값 생성을 위해 데이터베이스 시퀀스를 활용하지만, 생성된 식별자 값을 insert 문장 실행의 부분으로서
+ 실제로 반환시키기 위해 이것을 JDBC3 getGeneratedKeys와 결합시킨 특화된 시퀀스 생성 방도. 이 방도는
+ JDK 1.4에 대상화된 Oracle 10g 드라이버들 상에서만 지원되는 거승로 알려져 있다. 이들 insert 문장들에
+ 대한 주석들은 Oracle 드라이버들 내에 있는 버그 때문에 사용불가능하게 되어 있음을 노트하라.
</para>
</listitem>
</varlistentry>
@@ -763,7 +763,7 @@
<para>
<literal>hilo</literal>와 <literal>seqhilo</literal> 생성기들은 식별자 생성에 대한 마음에 드는 접근법인,
hi/lo 알고리즘에 대한 두 개의 대체 구현들은 제공한다. 첫 번째 구현은 다음에 이용 가능한 "hi" 값을 수용하기 위한 "특별한"
- 데이터베이스 테이블을 필요로 한다. 두 번째는 (지원되는) Oracle 스타일의 시퀀스를 사용한다.
+ 데이터베이스 테이블을 필요로 한다. 두 번째는 (지원되는) Oracle 스타일의 시퀀스를 사용한다.
</para>
<programlisting><![CDATA[<id name="id" type="long" column="cat_id">
@@ -782,8 +782,8 @@
</id>]]></programlisting>
<para>
- 불행히도 당신은 Hibernate에 당신 자신의 <literal>Connection</literal>을 제공할 때 <literal>hilo</literal>를
- 사용할 수 없다. Hibernate가 JTA의 도움을 받는 커넥션들을 얻기 위해 어플리케이션 서버 데이터소스를 사용할 때 당신은
+ 불행히도 당신은 Hibernate에 당신 자신의 <literal>Connection</literal>을 제공할 때 <literal>hilo</literal>를
+ 사용할 수 없다. Hibernate가 JTA의 도움을 받는 커넥션들을 얻기 위해 어플리케이션 서버 데이터소스를 사용할 때 당신은
<literal>hibernate.transaction.manager_lookup_class</literal>를 적절하게 구성해야 한다.
</para>
</sect3>
@@ -793,17 +793,17 @@
<para>
UUID 는 다음을 포함한다: IP 주소, JVM의 시작 시간(정확히 1/4 초), 시스템 시간과 (JVM 내에서 유일한) counter 값.
Java 코드로부터 MAC 주소 또는 메모리 주소를 얻는 것은 불가능하여서, 이것은 우리가 JNI를 사용하지 않고서 행할 수 있는
- 최상의 것이다.
+ 최상의 것이다.
</para>
</sect3>
<sect3 id="mapping-declaration-id-sequences">
<title>식별 컬럼들과 시퀀스들</title>
<para>
- 식별 컬럼들을 지원하는 데이터베이스들(DB2, MySQL, Sybase, MS SQL)의 경우, 당신은 <literal>identity</literal> 키
- 생성을 사용할 수 있다. 시퀀스들을 지원하는 데이터베이스들(DB2, Oracle, PostgreSQL, Interbase, McKoi, SAP DB)의
- 경우, 당신은 <literal>sequence</literal> 스타일 키 생성을 사용할 수도 있다. 이들 방도들 모두 새로운 객체를 insert하기
- 위해 두 개의 SQL 질의들을 필요로 한다.
+ 식별 컬럼들을 지원하는 데이터베이스들(DB2, MySQL, Sybase, MS SQL)의 경우, 당신은 <literal>identity</literal> 키
+ 생성을 사용할 수 있다. 시퀀스들을 지원하는 데이터베이스들(DB2, Oracle, PostgreSQL, Interbase, McKoi, SAP DB)의
+ 경우, 당신은 <literal>sequence</literal> 스타일 키 생성을 사용할 수도 있다. 이들 방도들 모두 새로운 객체를 insert하기
+ 위해 두 개의 SQL 질의들을 필요로 한다.
</para>
<programlisting><![CDATA[<id name="id" type="long" column="person_id">
@@ -817,7 +817,7 @@
</id>]]></programlisting>
<para>
- 크로스 플랫폼 개발을 위해서, <literal>native</literal> 방도가 기준 데이터베이스들의 가용성들에 따라 <literal>identity</literal>,
+ 크로스 플랫폼 개발을 위해서, <literal>native</literal> 방도가 기준 데이터베이스들의 가용성들에 따라 <literal>identity</literal>,
<literal>sequence</literal>, <literal>hilo</literal> 방도 중에서 선택될 것이다.
</para>
</sect3>
@@ -826,15 +826,15 @@
<title>할당된 식별자들</title>
<para>
(Hibernate로 하여금 식별자들을 생성시키도록 하는 것과는 반대로) 당신이 어플리케이션으로 하여금 식별자들을 할당하도록 원할 경우,
- 당신은 <literal>assigned</literal> 생성기를 사용할 수 있다. 이 특별한 생성기는 객체의 identifier 프로퍼티에 이미 할당된
- 식별자 값을 사용할 것이다. 이 생성기(generator)는 프라이머리 키가 대용(surrogate ) 키 대신에 natural 키일 때 사용된다.
- 당신이 <literal><generator></literal> 요소를 지정하지 않을 경우에 이것이 디폴트 특징이다
+ 당신은 <literal>assigned</literal> 생성기를 사용할 수 있다. 이 특별한 생성기는 객체의 identifier 프로퍼티에 이미 할당된
+ 식별자 값을 사용할 것이다. 이 생성기(generator)는 프라이머리 키가 대용(surrogate ) 키 대신에 natural 키일 때 사용된다.
+ 당신이 <literal><generator></literal> 요소를 지정하지 않을 경우에 이것이 디폴트 특징이다
</para>
<para>
<literal>assigned</literal> 생성기(generator)를 선택하는 것은 , version 또는 timestamp 프로퍼티가 존재하지 않는 한
- 또는 당신이 <literal>Interceptor.isUnsaved()</literal>를 정의하지 않는 한, 하나의 인스턴스가 transient 또는 detached인지를
- 결정하기 위해 Hibernae로 하여금 데이터베이스에 접촉하도록 강제하는, <literal>unsaved-value="undefined"</literal>를
+ 또는 당신이 <literal>Interceptor.isUnsaved()</literal>를 정의하지 않는 한, 하나의 인스턴스가 transient 또는 detached인지를
+ 결정하기 위해 Hibernae로 하여금 데이터베이스에 접촉하도록 강제하는, <literal>unsaved-value="undefined"</literal>를
Hibernate에게 사용하도록 한다.
</para>
</sect3>
@@ -842,7 +842,7 @@
<sect3 id="mapping-declaration-id-select">
<title>트리거들에 의해 할당된 프라이머리 키들</title>
<para>
- 리거시 스키마에 대해서만(Hibernate는 트리거들을 가진 DDL을 생성시키지 않는다).
+ 리거시 스키마에 대해서만(Hibernate는 트리거들을 가진 DDL을 생성시키지 않는다).
</para>
<programlisting><![CDATA[<id name="id" type="long" column="person_id">
@@ -852,14 +852,174 @@
</id>]]></programlisting>
<para>
- 위의 예제에서, natural 키로서 클래스에 의해 <literal>socialSecurityNumber</literal>로 명명된 유일 값을 가진 프로퍼티가 존재하고,
- 트리거에 의해 그 값이 생성되는 <literal>person_id</literal>로 명명된 대용키가 존재한다.
+ 위의 예제에서, natural 키로서 클래스에 의해 <literal>socialSecurityNumber</literal>로 명명된 유일 값을 가진 프로퍼티가 존재하고,
+ 트리거에 의해 그 값이 생성되는 <literal>person_id</literal>로 명명된 대용키가 존재한다.
</para>
</sect3>
</sect2>
+ <sect2 id="mapping-declaration-id-enhanced">
+ <title>개선된 식별자 생성기들</title>
+
+ <para>
+ 릴리즈 3.2.3로 시작하면, 식별자 생성기의 두 가지 다른 측면들에 대한 재고를 설명하는 2개의 새로운 생성기들이
+ 존재한다. 첫 번째 측면은 데이터베이스 이식가능성이다; 두번째 측면은 (새로운 식별자 값에 대한 모든 요청들을
+ 데이터베이스로 질의하지 않는) 최적화이다. 이들 두 개의 새로운 생성자들은 (3.3.x 릴리즈 시작 시점에서는) 위에
+ 설명된 명명된 생성자들 중 몇몇을 대체할 예정이다. 하지만 그것들은 현재의 릴리즈 내에 포함되어 있으며 FQN에
+ 의해 참조될 수 있다.
+ </para>
+
+ <para>
+ 이들 새로운 생성기들 중 첫 번째 것은 먼저 <literal>sequence</literal> 생성기를 대체물로서 만들어지고
+ 두번째로는 (<literal>native</literal>가 (일반적으로) 어플리케이션에서 모든 이식성에 관한 난해한 이슈들을 불러일으킬 수 있는
+ 크게 다른 의미를 지닌 <literal>identity</literal>과 <literal>sequence</literal> 사이에서 선택하기 때문에)
+ <literal>native</literal> 보다 더 나은 이식성으로 만들어진 <literal>org.hibernate.id.enhanced.SequenceStyleGenerator</literal>
+ 이다. 하지만 <literal>org.hibernate.id.enhanced.SequenceStyleGenerator</literal>는 다른 방법으로 이식성을
+ 성취한다. 그것은 사용중인 dialect의 가용성에 의존하여 그것의 증가 값들을 저장하기 위해 데이터베이스 내의
+ 테이블이나 시퀀스를 사용하여 선택한다. 이것과 <literal>native</literal> 사이의 차이점은 (시퀀스들이
+ Hibernate가 그것의 테이블 기반의 생성기들로 에뮬레이트 하고자 시도하는 바와 정확하게 일치한다는 사실에서)
+ 테이블 기반의 스토리지와 시퀀스 기반의 스토리지가 정확히 같은 의미를 갖는다는 점이다. 이 생성기는 많은
+ 구성 파라미터들을 갖는다:
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>sequence_name</literal> (옵션이고, 디폴트는 <literal>hibernate_sequence</literal>):
+ 사용될 시퀀스(또는 테이블)의 이름.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>initial_value</literal> (옵션이고, 디폴트는 <literal>1</literal>): 시퀀스/테이블로부터 검색되는 초기 값.
+ 시퀀스 생성 용어로, 이것은 일반적으로 명명되는 "STARTS WITH" 절과 유사하다.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>increment_size</literal> (옵션이고, 디폴트는 <literal>1</literal>): 시퀀스/테이블에 대한 차후의
+ 호출에 의해 차이가 나게 될 값. 시퀀스 생성 용어로, 이것은 일반적으로 명명되는 "INCREMENT BY"와
+ 유사하다.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>force_table_use</literal> (옵션이고, 디폴트는 <literal>false</literal>): dialect가 시퀀스를
+ 지원할 수 있다고 할수 있는 경우조차도 역행 구조로서 테이블 사용을 강제할 수 있는가?
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>value_column</literal> (옵션이고, 디폴트는 <literal>next_val</literal>): 테이블 구조들에만
+ 적절하다! 값을 보유하는데 사용되는 테이블 상의 컬럼명
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>optimizer</literal> (옵션이고, 디폴트는 <literal>none</literal>):
+ <xref linkend="mapping-declaration-id-enhanced-optimizers"/>를 보라
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ 이들 새로운 생성기들 중 두 번째 것은 먼저 (비록 <literal>table</literal> 생성기가 실제로
+ <literal>org.hibernate.id.MultipleHiLoPerTableGenerator</literal>와 같이 훨씬 더 많이 기능할지라도)
+ <literal>table</literal> 생성기에 대한 대체물로서 그리고 두번째로 플러그 가능한 옵티마이저들의 개념을 활용하는
+ <literal>org.hibernate.id.MultipleHiLoPerTableGenerator</literal>의 재구현으로서 만들어지는
+ <literal>org.hibernate.id.enhanced.TableGenerator</literal>이다. 본질적으로 이 생성기는 여러 개의 유일하게
+ 키가 매겨진 행들을 사용하여 동시에 많은 다른 증가 값들을 보유하는 것이 가능한 테이블을 정의한다.
+ 이 생성기는 많은 구성 파라미터들을 갖는다:
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>table_name</literal> (옵션이고, 디폴트는 <literal>hibernate_sequences</literal>):
+ 사용될 테이블 이름.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>value_column_name</literal> (옵션이고, 디폴트는 <literal>next_val</literal>):
+ 시퀀스 값을 보관하는데 사용되는 테이블 상의 컬럼 이름.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>segment_column_name</literal> (옵션이고, 디폴트는 <literal>sequence_name</literal>):
+ "세그먼트 키"를 보관하는데 사용되는 테이블 상의 컬럼 이름. 이것은 어느 증가 값을 사용할 것인지를
+ 유일하게 식별하는 값이다.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>segment_value</literal> (옵션이고, 디폴트는 <literal>default</literal>):
+ 우리가 이 생성자에 대한 증가 값들을 획득하고자 원하는 세그먼트에 대한 "세그먼트 키" 값.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>segment_value_length</literal> (옵션이고, 디폴트는 <literal>255</literal>):
+ 스키마 생성에 사용된다; 이 세그먼트 키 컬럼을 생성시킬 컬럼 사이즈.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>initial_value</literal> (옵션이고, 디폴트는 <literal>1</literal>):
+ 테이블로부터 검색될 초기 값.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>increment_size</literal> (옵션이고, 디폴트는 <literal>1</literal>):
+ 테이블에 대한 차후의 호출에서 차이가 날 값.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>optimizer</literal> (옵션이고, 디폴트는 <literal></literal>):
+ <xref linkend="mapping-declaration-id-enhanced-optimizers"/>를 보라.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+
+ <sect2 id="mapping-declaration-id-enhanced-optimizers">
+ <title>식별자 생성기 최적화</title>
+ <para>
+ 데이터베이스에 값들을 저장하는 식별자 생성기들로 하여금 새로운 식별자 값을 생성시키기 위해
+ 매번의 호출마다 데이터베이스에 접속하도록 하는 것은 비효율적이다. 대신에 당신은 메모리 내에
+ 한 다발의 값들을 그룹지우고 당신이 당신의 메모리 내 값 그룹을 고갈시켰을 때에만 데이터베이스로
+ 접속하고자 개념적으로 원할 것이다. 이것은 플러그 가능한 옵티마이저들의 역할이다. 현시점에서는 오직
+ 두 개의 개선된 생성기들(<xref linkend="mapping-declaration-id-enhanced"/>) 만이 이 개념을 지원한다.
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>none</literal> (일반적으로 이것은 옵티마이저가 지정되지 않았을 경우에 디폴트이다).
+ 이것은 임의의 최적화를 수행하지 말고, 각각의 모든 요청 시에 데이터베이스를 접속할 것을
+ 말한다.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>hilo</literal>: 데이터베이스 검색 값들에 hi/lo 알고리즘을 적용시킨다. 이 옵티마이저의
+ 경우 데이터베이스로부터 검색된 값들은 순차적이게 될리라 예상된다. 이 옵티마이저에 대해
+ 데이터베이스로부터 검색된 값들은 "그룹 번호"를 가리킨다; <literal>increment_size</literal>는
+ 그룹 "hi 값"을 정의하기 위해 메모리 내에서 "그룹 번호" 만큼 곱해진다.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>pooled</literal>: <literal>hilo</literal>에 관한 논의했듯이, 이 옵티마이저들은 데이터베이스에
+ 대한 접속 횟수를 최소화 시키려고 시도한다. 하지만 여기서 우리는 메모리 내 그룹핑 알고리즘과 협력된
+ 순차 값을 저장하기 보다는 "다음 그룹"의 시작 값을 데이터베이스 구조 내로 간단하게 저장한다.
+ 여기서 <literal>increment_size</literal>는 데이터베이스로부터 들어오는 값들을 조회한다.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+
<sect2 id="mapping-declaration-compositeid" revision="3">
<title>composite-id</title>
@@ -878,7 +1038,7 @@
<para>
composite 키를 가진 테이블의 경우, 당신은 클래스의 여러 프로퍼티들을 식별자 프로퍼티들로서 매핑할 수 있다.
<literal><composite-id></literal> 요소는 자식 요소들로서 <literal><key-property></literal>
- 프로퍼티 매핑과 <literal><key-many-to-one></literal> 매핑들을 허용한다.
+ 프로퍼티 매핑과 <literal><key-many-to-one></literal> 매핑들을 허용한다.
</para>
<programlisting><![CDATA[<composite-id>
@@ -893,16 +1053,16 @@
</para>
<para>
- 불행히도, composite 식별자들에 대한 이 접근법은 영속 객체가 그것 자신의 식별자라는 점을 의미한다. 객체
- 자신 외의 다른 "핸들"이 존재하지 않는다. 당신은 당신이 composite key로 연관된 영속 상태를 <literal>load()</literal>
- 할 수 있기 이전에 영속 클래스 그 자체의 인스턴스를 초기화 하고 그것의 식별자 프로퍼티들을 군집화 시켜야 한다. 우리는
- 이 접근법을 <emphasis>embedded</emphasis> composite 식별자로 부르고, 중대한 어플리케이션들에 대해 그것을 억제시킨다.
+ 불행히도, composite 식별자들에 대한 이 접근법은 영속 객체가 그것 자신의 식별자라는 점을 의미한다. 객체
+ 자신 외의 다른 "핸들"이 존재하지 않는다. 당신은 당신이 composite key로 연관된 영속 상태를 <literal>load()</literal>
+ 할 수 있기 이전에 영속 클래스 그 자체의 인스턴스를 초기화 하고 그것의 식별자 프로퍼티들을 군집화 시켜야 한다. 우리는
+ 이 접근법을 <emphasis>embedded</emphasis> composite 식별자로 부르고, 중대한 어플리케이션들에 대해 그것을 억제시킨다.
</para>
<para>
- 두 번째 접근법은 우리가 <emphasis>mapped</emphasis> composite 식별자라고 부르는 것인데, 여기서
+ 두 번째 접근법은 우리가 <emphasis>mapped</emphasis> composite 식별자라고 부르는 것인데, 여기서
<literal><composite-id></literal> 요소 내에 명명된 여기서 식별자 프로퍼티들은 영속 클래스와 별도의 식별자 클래스
- 양자 상에 중복된다.
+ 양자 상에 중복된다.
</para>
<programlisting><![CDATA[<composite-id class="MedicareId" mapped="true">
@@ -911,42 +1071,42 @@
</composite-id>]]></programlisting>
<para>
- 이 예제에서, composite 식별자 클래스인 <literal>MedicareId</literal>와 엔티티 크래스 그 자체 양자는
+ 이 예제에서, composite 식별자 클래스인 <literal>MedicareId</literal>와 엔티티 크래스 그 자체 양자는
<literal>medicareNumber</literal>와 <literal>dependent</literal>로 명명된 프로퍼티들을 갖는다. 식별자 클래스는
<literal>equals()</literal>와 <literal>hashCode()</literal>를 오버라이드 시켜고 <literal>Serializable</literal>을
- 구현해야 한다. 이 접근법의 단점은 아주 명백한—코드 중복이다.
+ 구현해야 한다. 이 접근법의 단점은 아주 명백한—코드 중복이다.
</para>
<para>
- 다음 속성들은 매핑된 composite 식별자를 지정하는데 사용된다:
+ 다음 속성들은 매핑된 composite 식별자를 지정하는데 사용된다:
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
<literal>mapped</literal> (옵션, 디폴트는 <literal>false</literal>):
- 하나의 매핑된 composite 식별자가 사용됨을, 그리고 포함된 프로퍼티 매핑들이 엔티티 클래스와
+ 하나의 매핑된 composite 식별자가 사용됨을, 그리고 포함된 프로퍼티 매핑들이 엔티티 클래스와
composite 식별자 클래스 양자를 참조함을 나타낸다.
</para>
</listitem>
<listitem>
<para>
<literal>class</literal> (옵션, 하지만 하나의 매핑된 commposite 식별자에 대해서는 필수적임):
- 하나의 composite 식별자로서 사용되는 클래스.
+ 하나의 composite 식별자로서 사용되는 클래스.
</para>
</listitem>
</itemizedlist>
<para>
- 우리는 <xref linkend="components-compositeid"/>에서 composite 식별자가 하나의 component 클래스로서 구현되는
- 보다 편리한 접근법인 세번째 방도를 설명할 것이다. 아래에 설명되어 있는 속성들은 이 대체적인 접근법에만 적용된다:
+ 우리는 <xref linkend="components-compositeid"/>에서 composite 식별자가 하나의 component 클래스로서 구현되는
+ 보다 편리한 접근법인 세번째 방도를 설명할 것이다. 아래에 설명되어 있는 속성들은 이 대체적인 접근법에만 적용된다:
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
<literal>name</literal> (옵션, 이 접근법의 경우에는 필수임): 하나의 component
- 식별자를 소유하는 컴포넌트 타입의 프로퍼티(9장을 보라).
+ 식별자를 소유하는 컴포넌트 타입의 프로퍼티(9장을 보라).
</para>
</listitem>
<listitem>
@@ -958,13 +1118,13 @@
<listitem>
<para>
<literal>class</literal> (옵션 - 디폴트는 reflection에 의해 결정된 프로퍼티 타입):
- 하나의 composite 식별자로서 사용되는 컴포넌트 클래스(다음 절을 보라).
+ 하나의 composite 식별자로서 사용되는 컴포넌트 클래스(다음 절을 보라).
</para>
</listitem>
</itemizedlist>
<para>
- 이 세번째 접근법, <emphasis>identifier component</emphasis>은 거의 모든 어플리케이션들에 대해 우리가 권장하는 것이다.
+ 이 세번째 접근법, <emphasis>identifier component</emphasis>은 거의 모든 어플리케이션들에 대해 우리가 권장하는 것이다.
</para>
</sect2>
@@ -973,9 +1133,9 @@
<para>
<literal><discriminator></literal> 요소는 table-per-class-hierarchy(테이블 당 클래스 계층구조)
- 매핑 방도를 사용하는 다형성 영속화에 필요하고 테이블의 discriminator(판별자) 컬럼을 선언한다. discriminator 컬럼은
- 특정 행에 대해 초기화 시킬 서브 클래스가 무엇인지를 영속 계층에 알려주는 표시자 값들을 포함한다. 타입들의 제한적인 집합이
- 사용될 수 있다: <literal>string</literal>, <literal>character</literal>, <literal>integer</literal>,
+ 매핑 방도를 사용하는 다형성 영속화에 필요하고 테이블의 discriminator(판별자) 컬럼을 선언한다. discriminator 컬럼은
+ 특정 행에 대해 초기화 시킬 서브 클래스가 무엇인지를 영속 계층에 알려주는 표시자 값들을 포함한다. 타입들의 제한적인 집합이
+ 사용될 수 있다: <literal>string</literal>, <literal>character</literal>, <literal>integer</literal>,
<literal>byte</literal>, <literal>short</literal>, <literal>boolean</literal>,
<literal>yes_no</literal>, <literal>true_false</literal>.
</para>
@@ -1011,21 +1171,21 @@
<callout arearefs="discriminator3">
<para>
<literal>force</literal> (옵션 - 디폴트는 <literal>false</literal>)
- 이것은 Hibernate로 하여금 루트 클래스의 모든 인스턴스들을 검색할 때조차도 허용된 discriminator
- 값들을 지정하도록 "강제한다".
+ 이것은 Hibernate로 하여금 루트 클래스의 모든 인스턴스들을 검색할 때조차도 허용된 discriminator
+ 값들을 지정하도록 "강제한다".
</para>
</callout>
<callout arearefs="discriminator4">
<para>
<literal>insert</literal> (옵션 - 디폴트는 <literal>true</literal>)
- 당신의 discriminator 컬럼이 또한 매핑된 composite 식별자의 부분일 경우에 이것을 <literal>false</literal>로 설정하라.
+ 당신의 discriminator 컬럼이 또한 매핑된 composite 식별자의 부분일 경우에 이것을 <literal>false</literal>로 설정하라.
(Hibernate에게 SQL <literal>INSERT</literal>들 속에 그 컬럼을 포함하지 않도록 통보한다.)
</para>
</callout>
<callout arearefs="discriminator5">
<para>
<literal>formula</literal> (옵션)
- 타입이 평가 되어야 할 때 실행되는 임의의 SQL 표현식. 컨텐츠 기반의 판별을 허용해준다.
+ 타입이 평가 되어야 할 때 실행되는 임의의 SQL 표현식. 컨텐츠 기반의 판별을 허용해준다.
</para>
</callout>
</calloutlist>
@@ -1038,7 +1198,7 @@
<para>
<literal>force</literal> 속성은 테이블이 영속 클래스로 매핑되지 않는 "특별한" discriminator 값들을 가진 행들을
- 포함할 경우에(만) 유용하다. 이것은 대개 그 경우가 아닐 것이다.
+ 포함할 경우에(만) 유용하다. 이것은 대개 그 경우가 아닐 것이다.
</para>
<para>
@@ -1056,7 +1216,7 @@
<para>
<literal><version></literal> 요소는 옵션이고 테이블이 버전화된 데이터를 포함한다는 것을 나타낸다.
- 이것은 당신이 <emphasis>긴 트랜잭션(long transaction)들</emphasis>을 사용할 계획이라면 특히 유용하다
+ 이것은 당신이 <emphasis>긴 트랜잭션(long transaction)들</emphasis>을 사용할 계획이라면 특히 유용하다
(아래를 보라).
</para>
@@ -1084,7 +1244,7 @@
<callout arearefs="version1">
<para>
<literal>column</literal> (옵션 - 디폴트는 프로퍼티 명):
- 버전 번호를 가진 컬럼의 이름.
+ 버전 번호를 가진 컬럼의 이름.
</para>
</callout>
<callout arearefs="version2">
@@ -1095,7 +1255,7 @@
<callout arearefs="version3">
<para>
<literal>type</literal> (옵션 - 디폴트는 <literal>integer</literal>):
- 버전 번호의 타입.
+ 버전 번호의 타입.
</para>
</callout>
<callout arearefs="version4">
@@ -1107,14 +1267,14 @@
<callout arearefs="version5">
<para>
<literal>unsaved-value</literal> (옵션 - 디폴트는 <literal>undefined</literal>):
- 이전 세션에서 저장되었거나 로드되었던 detached 인스턴스로부터 구별지어서, 인스턴스가 새로이 초기화됨(unsaved)을
- 나타내는 version 프로퍼티 값.(<literal>undefined</literal>는 식별자 프로퍼티 값이 사용될 것임을 지정한다.)
+ 이전 세션에서 저장되었거나 로드되었던 detached 인스턴스로부터 구별지어서, 인스턴스가 새로이 초기화됨(unsaved)을
+ 나타내는 version 프로퍼티 값.(<literal>undefined</literal>는 식별자 프로퍼티 값이 사용될 것임을 지정한다.)
</para>
</callout>
<callout arearefs="version6">
<para>
<literal>generated</literal> (옵션 - 디폴트는 <literal>never</literal>):
- 이 version 프로퍼티 값이 데이터베이스에 의해 실제로 산출되는지를 지정한다.
+ 이 version 프로퍼티 값이 데이터베이스에 의해 실제로 산출되는지를 지정한다.
<xref linkend="mapping-generated">산출되는 프로퍼티들</xref>에 관한 논의를 보라.
</para>
</callout>
@@ -1122,23 +1282,23 @@
<para>
<literal>insert</literal> (옵션 - 디폴트는 <literal>true</literal>):
version 컬럼이 SQL insert 문장들 속에 포함될 것인지 여부를 지정한다.
- 데이터베이스 컬럼이 디폴트 값 <literal>0</literal>으로 정의되는 경우에만 <literal>false</literal>로
- 설정될 수 있다.
+ 데이터베이스 컬럼이 디폴트 값 <literal>0</literal>으로 정의되는 경우에만 <literal>false</literal>로
+ 설정될 수 있다.
</para>
</callout>
</calloutlist>
</programlistingco>
<para>
- 버전 번호들은 <literal>long</literal>, <literal>integer</literal>, <literal>short</literal>,
+ 버전 번호들은 <literal>long</literal>, <literal>integer</literal>, <literal>short</literal>,
<literal>timestamp</literal> 또는 <literal>calendar</literal> 타입일 수 있다.
</para>
<para>
version 또는 timestamp 프로퍼티는 detached 인스턴스에 대해 결코 null일 수가 없어서, Hibernate는
- 다른 <literal>unsaved-value</literal> 방도들이 지정되는 것에 상관없이, null version이나 timestamp를
- 가진 임의의 인스턴스를 transient로서 검출할 것이다. <emphasis>null 허용되는 version 이나 property를
- 선언하는 것은 Hibernate에서 transitive reattachment에 대한 임의의 문제들을 피하는 쉬운 방법이고,
+ 다른 <literal>unsaved-value</literal> 방도들이 지정되는 것에 상관없이, null version이나 timestamp를
+ 가진 임의의 인스턴스를 transient로서 검출할 것이다. <emphasis>null 허용되는 version 이나 property를
+ 선언하는 것은 Hibernate에서 transitive reattachment에 대한 임의의 문제들을 피하는 쉬운 방법이고,
assigned 식별자들이나 composite key들을 사용하는 사람들에게 특히 유용하다!</emphasis>
</para>
</sect2>
@@ -1147,9 +1307,9 @@
<title>timestamp (옵션)</title>
<para>
- 옵션 <literal><timestamp></literal> 요소는 테이블이 타임스탬프화 된 데이터를 포함함을 나타낸다. 이것은
- 버전화에 대한 대체물로서 고안되었다. Timestamp은 고유하게 optimistic 잠금에 대한 다소 안전한 구현이다. 하지만 때때로
- 어플리케이션은 다른 방법들로 timestamp들을 사용할 수도 있다.
+ 옵션 <literal><timestamp></literal> 요소는 테이블이 타임스탬프화 된 데이터를 포함함을 나타낸다. 이것은
+ 버전화에 대한 대체물로서 고안되었다. Timestamp은 고유하게 optimistic 잠금에 대한 다소 안전한 구현이다. 하지만 때때로
+ 어플리케이션은 다른 방법들로 timestamp들을 사용할 수도 있다.
</para>
<programlistingco>
@@ -1174,14 +1334,14 @@
<callout arearefs="timestamp1">
<para>
<literal>column</literal> (옵션 - 디폴트는 프로퍼티 명):
- 타임스탬프를 포함하는 컬럼 명.
+ 타임스탬프를 포함하는 컬럼 명.
</para>
</callout>
<callout arearefs="timestamp2">
<para>
<literal>name</literal>:
- 영속 클래스에 대해 자바 <literal>Date</literal> 또는 <literal>Timestamp</literal> 타입을
- 가진 자바빈즈 스타일의 프로퍼티 이름.
+ 영속 클래스에 대해 자바 <literal>Date</literal> 또는 <literal>Timestamp</literal> 타입을
+ 가진 자바빈즈 스타일의 프로퍼티 이름.
</para>
</callout>
<callout arearefs="timestamp3">
@@ -1193,26 +1353,26 @@
<callout arearefs="timestamp4">
<para>
<literal>unsaved-value</literal> (옵션 - 디폴트는 <literal>null</literal>):
- 이전 세션에서 저장되었거나 로드되었던 detached 인스턴스로부터 인스턴스를 구별지우는, 인스턴스가 새로이
- 초기화됨(unsaved)을 나타내는 version 프로퍼티 값.(<literal>undefined</literal>는 식별자
- 프로퍼티 값이 사용될 것임을 지정한다.)
+ 이전 세션에서 저장되었거나 로드되었던 detached 인스턴스로부터 인스턴스를 구별지우는, 인스턴스가 새로이
+ 초기화됨(unsaved)을 나타내는 version 프로퍼티 값.(<literal>undefined</literal>는 식별자
+ 프로퍼티 값이 사용될 것임을 지정한다.)
</para>
</callout>
<callout arearefs="timestamp5">
<para>
<literal>source</literal> (옵션 - 디폴트는 <literal>vm</literal>):
Hibernate는 어디서 timestamp 값을 검색할 것인가? 데이터베이스로부터인가 현재의 JVM으로부터인가?
- 데이터베이스 기반의 timestamp들은 Hibernate가 "다음 값"을 결정하기 위해 데이터베이스에 접속해야
- 하기 때문에 오버헤드를 초래하지만, 클러스터링된 환경들에서의 용도로 보다 더 안전할 것이다. 또한 모든
+ 데이터베이스 기반의 timestamp들은 Hibernate가 "다음 값"을 결정하기 위해 데이터베이스에 접속해야
+ 하기 때문에 오버헤드를 초래하지만, 클러스터링된 환경들에서의 용도로 보다 더 안전할 것이다. 또한 모든
<literal>Dialect</literal>들이 데이터베이스의 현재의 timestamp에 대한 검색을 지원하는 것으로 알려져
- 있지 않지만, 다른 <literal>Dialect</literal>들은 정밀도 결핍 때문에 잠금에 있어 사용이 안전하지 않을
- 수 있음을 노트하라(예를 들면 오라클 8).
+ 있지 않지만, 다른 <literal>Dialect</literal>들은 정밀도 결핍 때문에 잠금에 있어 사용이 안전하지 않을
+ 수 있음을 노트하라(예를 들면 오라클 8).
</para>
</callout>
<callout arearefs="timestamp6">
<para>
<literal>generated</literal> (옵션 - 디폴트는 <literal>never</literal>):
- 이 timestamp 프로퍼티 값이 데이터베이스에 의해 실제로 생성됨을 지정한다.
+ 이 timestamp 프로퍼티 값이 데이터베이스에 의해 실제로 생성됨을 지정한다.
<xref linkend="mapping-generated">산출되는 프로퍼티들</xref>에 대한 논의들 보라.
</para>
</callout>
@@ -1221,7 +1381,7 @@
<para>
<literal><timestamp></literal>는 <literal><version type="timestamp"></literal>과
- 같음을 노트하라. 그리고 <literal><timestamp use-db="true"></literal>는
+ 같음을 노트하라. 그리고 <literal><timestamp use-db="true"></literal>는
<literal><version type="dbtimestamp"></literal>과 같다
</para>
</sect2>
@@ -1280,8 +1440,8 @@
<callout arearefs="property2">
<para>
<literal>column</literal> (옵션 - 디폴트는 프로퍼티 이름):
- 매핑된 데이터베이스 테이블 컬럼의 이름. 이것은 또한 내부에 포함되는 <literal><column></literal> 요소(들)에
- 의해 지정될 수도 있다.
+ 매핑된 데이터베이스 테이블 컬럼의 이름. 이것은 또한 내부에 포함되는 <literal><column></literal> 요소(들)에
+ 의해 지정될 수도 있다.
</para>
</callout>
<callout arearefs="property3">
Modified: core/tags/v326/doc/reference/ko/modules/batch.xml
===================================================================
--- core/tags/v326/doc/reference/ko/modules/batch.xml 2008-06-15 14:36:50 UTC (rev 14767)
+++ core/tags/v326/doc/reference/ko/modules/batch.xml 2008-06-15 14:39:42 UTC (rev 14768)
@@ -26,6 +26,11 @@
<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
+ <para id="disablebatching" revision="1">
+ 당신이 <literal>identiy</literal> 식별자 생성기를 사용할 경우에 Hibernate가 JDBC 레벨에서 투명하게 insert 배치처리하는 것을 불가능하게 만든다는
+ 사실을 주목하라.
+ </para>
+
<para>
당신은 또한 second-level 캐시를 가진 상호작용이 완전하게 불가능한 프로세스 내에서 이런 종류의 작업을 행하고 싶어할 수도 있다:
</para>
Modified: core/tags/v326/doc/reference/ko/modules/filters.xml
===================================================================
--- core/tags/v326/doc/reference/ko/modules/filters.xml 2008-06-15 14:36:50 UTC (rev 14767)
+++ core/tags/v326/doc/reference/ko/modules/filters.xml 2008-06-15 14:39:42 UTC (rev 14768)
@@ -6,7 +6,7 @@
필터</emphasis>는 특정 Hibernate 세션에 대해 이용 가능하게 되거나 이용 불가능하게 될 수도 있는 전역, 명명된 파라미터화 된 필터이다.
</para>
- <sect1 id="objectstate-filters">
+ <sect1 id="objectstate-filters" revision="1">
<title>Hibernate 필터들</title>
<para>
@@ -95,8 +95,8 @@
</class>]]></programlisting>
<para>
- 그때 당신이 현재 유효한 레코드들을 항상 얻는 것을 확실히 하기 위해, employee 데이터를 검색하기 전에 세션 상에 필터를
- 간단하게 이용 가능하게 하라:
+ 그때 당신이 현재 유효한 레코드들을 항상 얻는 것을 확실히 하기 위해, employee 데이터를 검색하기 전에 세션 상에 필터를
+ 간단하게 이용 가능하게 하라:
</para>
<programlisting><![CDATA[Session session = ...;
@@ -107,16 +107,31 @@
]]></programlisting>
<para>
- 위의 HQL 에서, 심지어 비록 우리가 결과들에 대한 봉급 컨스트레인트를 명시적으로 언급만 했을지라도, 이용 가능한 필터 때문에
- 그 질의는 봉급이 백만달러 이상인 현재 채용중인 직원들만을 반환할 것이다.
+ 위의 HQL 에서, 심지어 비록 우리가 결과들에 대한 봉급 컨스트레인트를 명시적으로 언급만 했을지라도, 이용 가능한 필터 때문에
+ 그 질의는 봉급이 백만달러 이상인 현재 채용중인 직원들만을 반환할 것이다.
</para>
<para>
- 노트: 만일 당신이 outer 조인에 대해 필터들을 사용할 계획이라면 (HQL이든 로드 페칭이든) 조건 표현식의 방향을 주의하라.
- 이것을 left outer join으로 설정하는 것이 가장 안전하다; 일반적으로 오퍼레이터 뒤에 있는 컬럼 이름(들)이 뒤따르는 첫번째에
- 파라미터를 위치지워라.
+ 노트: 만일 당신이 outer 조인에 대해 필터들을 사용할 계획이라면 (HQL이든 로드 페칭이든) 조건 표현식의 방향을 주의하라.
+ 이것을 left outer join으로 설정하는 것이 가장 안전하다; 일반적으로 오퍼레이터 뒤에 있는 컬럼 이름(들)이 뒤따르는 첫번째에
+ 파라미터를 위치지워라.
</para>
+ <para>
+ 정의된 후에 필터는 그것 자신의 조건을 가지고 여러 엔티티들 그리고/또는 콜렉션들 각각에 첨부될 수도 있다.
+ 조건들이 매번 같을 때 그것은 지루할수도 있다. 따라서 <literal><filter-def/></literal>는 속성으로든
+ CDATA로든 디폴트 조건을 정의하는 것을 허용해준다:
+ </para>
+
+ <programlisting><![CDATA[<filter-def name="myFilter" condition="abc > xyz">...</filter-def>
+<filter-def name="myOtherFilter">abc=xyz</filter-def>]]></programlisting>
+
+ <para>
+ 그때 이 디폴트 조건은 필터가 조건을 지정하지 않은 어떤 것에 첨부될 때마다 사용될 것이다.
+ 이것은 당신이 그 특정한 경우에서 디폴트 조건을 오버라이드 시키는 필터의 첨부 부분으로서
+ 특정한 조건을 부여할 수 있음을 의미함을 주목하라.
+ </para>
+
</sect1>
</chapter>
Modified: core/tags/v326/doc/reference/ko/modules/persistent_classes.xml
===================================================================
--- core/tags/v326/doc/reference/ko/modules/persistent_classes.xml 2008-06-15 14:36:50 UTC (rev 14767)
+++ core/tags/v326/doc/reference/ko/modules/persistent_classes.xml 2008-06-15 14:39:42 UTC (rev 14768)
@@ -178,7 +178,7 @@
<para>
당신은 또한 non-final 클래스들 상에 <literal>public final</literal> 메소드들을 선언하는 것을 피해야 한다.
만일 당신이 <literal>public final</literal> 메소드를 가진 클래스를 사용하고자 원할 경우, 당신은
- <literal>lazy="false"</literal>를 설정함으로써 명시적으로 프락싱을 사용 불가능하도록 해야 한다.
+ <literal>lazy="false"</literal>를 설정함으로써 프락싱을 명시적으로 사용 불가능하도록 해야 한다.
</para>
</sect2>
Modified: core/tags/v326/doc/reference/ko/modules/query_hql.xml
===================================================================
--- core/tags/v326/doc/reference/ko/modules/query_hql.xml 2008-06-15 14:36:50 UTC (rev 14767)
+++ core/tags/v326/doc/reference/ko/modules/query_hql.xml 2008-06-15 14:39:42 UTC (rev 14768)
@@ -1,4 +1,4 @@
-<chapter id="queryhql">
+<chapter id="queryhql" revision="1">
<title>HQL: 하이버네이트 질의 언어(Hibernate Query Language)</title>
<para>
@@ -191,6 +191,41 @@
<programlisting><![CDATA[from Cat as cat where cat.mate.name like '%s%']]></programlisting>
</sect1>
+ <sect1 id="queryhql-identifier-property">
+ <title>식별자 프로퍼티 참조하기</title>
+
+ <para>
+ 일반적으로 말하자면, 엔티티의 식별자 프로퍼티를 참조하는 2가지 방법들이 있다:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ 엔티티가 <emphasis>id로 명명된 비-식별자 프로퍼티를 정의하고있지 않다고 가정하면</emphasis>
+ 특별한 프로퍼티 (소문자) <literal>id</literal>가 엔티티의 식별자 프로퍼티를 참조하는데 사용될 수도 있다.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 만일 엔티티가 명명된 식별자 프로퍼티를 정의할 경우, 당신은 그 프로퍼티 이름을 사용할수 있다.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ 합성 식별자 프로퍼티들에 대한 참조들은 다음 명명 규칙들을 따른다. 만일 엔티티가 id로 명명된
+ 비-식별자 프로퍼티를 갖고 있다면, 합성 식별자 프로퍼티는 그것의 정의된 명명된 프로퍼티에 의해서만
+ 참조될 수 있다; 그 밖의 경우 특별한 <literal>id</literal> 프로퍼티는 식별자 프로퍼티를 참조하는데
+ 사용될 수 있다.
+ </para>
+
+ <para>
+ 노트: 이것은 버전 3.2.2 시작 시점에서 현저하게 변경되었다. 이전 버전들에서
+ <literal>id</literal>는 그것의 실제 이름이 무엇이든 간에 상관없이 <emphasis>항상</emphasis>
+ 식별자 프로퍼티를 참조했다. 그 결정에 대한 분기점은 <literal>id</literal>로 명명된
+ 비-식별자 프로퍼티들이 Hibernate 질의들 내에서 결코 참조될 수 없다는 점이었다.
+ </para>
+ </sect1>
+
<sect1 id="queryhql-select">
<title>select 절</title>
@@ -366,7 +401,7 @@
</sect1>
- <sect1 id="queryhql-where">
+ <sect1 id="queryhql-where" revision="1">
<title>where 절</title>
<para>
@@ -420,8 +455,8 @@
where cat.mate = mate]]></programlisting>
<para>
- 특별한 프로퍼티(소문자) <literal>id</literal>는 객체의 유일 식별자를 참조하는데 사용될 수 있다.(당신은 또한 그것의 프로퍼티
- 이름을 사용할 수도 있다.)
+ 특별한 프로퍼티(소문자) <literal>id</literal>는 객체의 유일 식별자를 참조하는데 사용될 수 있다.
+ 추가정보는 <xref linkend="queryhql-identifier-property"/>를 보라.
</para>
<programlisting><![CDATA[from Cat as cat where cat.id = 123
@@ -435,7 +470,8 @@
<para>
composite identifier(합성 식별자)들의 프로퍼티들이 또한 사용될 수 있다. <literal>Person</literal>이
<literal>country</literal>와 <literal>medicareNumber</literal>로 구성된 composite identifier를 갖는다고
- 가정하자.
+ 가정하자. 다시, 식별자 프로퍼티들을 참조하는 것에 관한 추가 정보는
+ <xref linkend="queryhql-identifier-property"/>를 보라.
</para>
<programlisting><![CDATA[from bank.Person person
@@ -457,16 +493,12 @@
</para>
<programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
-
+
<para>
- 당신은 또한 컴포넌트들 또는 composite 사용자 정의 타입들의 (그리고 컴포넌트들의 컴포넌트들, 기타의) 프로퍼티들을
- 지정할 수도 있다. (컴포넌트의 프로퍼티와은 반대로) 컴포넌트 타입의 프로퍼티로 끝나는 경로-표현식을 사용하려고 결코 시도하지 말라.
- 예를 들어, 만일 <literal>store.owner</literal>가 컴포넌트 <literal>address</literal>를 가진 엔티티일 경우
+ 당신은 또한 컴포넌트들 또는 합성 사용자 타입들, 또는 컴포넌트 타입들이라 일컬어지는 프로퍼티들을 사용할수도 있다.
+ 보다 상세한 것은 <xref linkend="queryhql-components"/>를 보라.
</para>
- <programlisting><![CDATA[store.owner.address.city // okay
-store.owner.address // error!]]></programlisting>
-
<para>
"임의의" 타입은 다음 방법으로 join을 표현하는 것을 우리에게 허용해주는, 특별한 프로퍼티들 <literal>id</literal>와
<literal>class</literal>를 갖는다(여기서 <literal>AuditLog.item</literal>은 <literal><any></literal>로
@@ -778,7 +810,7 @@
</para>
</sect1>
- <sect1 id="queryhql-grouping">
+ <sect1 id="queryhql-grouping" revision="1">
<title>group by 절</title>
<para>
@@ -810,23 +842,25 @@
<programlisting><![CDATA[select cat
from Cat cat
join cat.kittens kitten
-group by cat
+group by cat.id, cat.name, cat.other, cat.properties
having avg(kitten.weight) > 100
order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
<para>
<literal>group by</literal> 절도 <literal>order by</literal> 절 어느 것도 산술 표현식들을 포함할 수 없다는 점을
- 노트하라.
+ 노트하라. 또한 Hibernate는 현재 그룹지워진 엔티티를 전개하지 않아서 만일 <literal>cat</literal>의 모든
+ 프로퍼티들이 집계되지 않을 경우에 당신은 <literal>group by cat</literal>을 작성할 수 없다는 점을 주목하라.
+ 당신은 모든 집계되지 않는 프로퍼티들을 명시적으로 리스트해야 한다.
</para>
</sect1>
- <sect1 id="queryhql-subqueries" revision="2">
+ <sect1 id="queryhql-subqueries" revision="3">
<title>서브질의들</title>
<para>
subselect들을 지원하는 데이터베이스들의 경우, Hibernate는 질의들 내에 서브질의들을 지원한다. 서브질의는 괄호로 묶여져야
- 한다(자주 SQL 집계함수 호출에 의해). 심지어 서로 상관된 서브질의들(외부 질의 내에서 alias를 참조하는 서브질의들)이 허용된다.
+ 한다(자주 SQL 집계함수 호출에 의해). 심지어 서로 상관된 서브질의들(외부 질의 내에서 alias를 참조하는 서브질의들)이 허용된다.
</para>
<programlisting><![CDATA[from Cat as fatcat
@@ -853,40 +887,14 @@
from Cat as cat]]></programlisting>
<para>
- select 리스트 내에 있는 하나 이상의 표현식을 가진 서브질의들의 경우에 당신은 tuple 생성자를 사용할 수 있다:
- </para>
-
- <para>
- select 목록 내에 하나 이상의 표현식을 가진 서브질의들의 경우, 당신은 튜플(tuple) 구조를 사용할 수 있다:
- </para>
-
- <programlisting><![CDATA[from Cat as cat
-where not ( cat.name, cat.color ) in (
- select cat.name, cat.color from DomesticCat cat
-)]]></programlisting>
-
- <para>
HQL 서브질의들이 select 절 또는 where 절 내에서만 일어날 수 있음을 노트하라.
</para>
-
- <para>
- (Oracle 또는 HSQL이 아닌) 몇몇 데이터베이스들 상에서, 당신은 다른 컨텍스트들 내에서, 예를 들면 component들이나 composite
- 사용자 타입들을 질의할 때 tuple 생성자들을 사용할 수 있음을 노트하라:
- </para>
-
- <programlisting><![CDATA[from Person where name = ('Gavin', 'A', 'King')]]></programlisting>
<para>
- 이것을 더 풀어쓰면 다음과 동일하다:
+ 서브질의들이 또한 <literal>row value constructor</literal> 구문을 활용할 수 있음을 주목하라.
+ 보다 상세한 것은 <xref linkend="queryhql-tuple"/>을 보라.
</para>
- <programlisting><![CDATA[from Person where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')]]></programlisting>
-
- <para>
- 당신이 이런 종류의 것을 행하는 것을 원하지 않을 수 있는 두 가지 좋은 이유들이 존재한다: 첫 번째로 데이터베이스 플랫폼들 사이에 완전하게
- 이식성이 없다; 두 번째로 그 질의는 이제 매핑 문서 속에 있는 프로퍼티들의 순서에 의존한다.
- </para>
-
</sect1>
<sect1 id="queryhql-examples">
@@ -1097,5 +1105,77 @@
</sect1>
+ <sect1 id="queryhql-components">
+ <title>컴포넌트</title>
+
+ <para>
+ 컴포넌트들은 단지 간단한 값 타입들이 HQL 질의들 내에 사용될 수 있는 모든 방식으로 사용될 수도 있다.
+ 그것들은 <literal>select</literal> 절 내에 나타날 수 있다:
+ </para>
+
+ <programlisting><![CDATA[select p.name from from Person p]]></programlisting>
+ <programlisting><![CDATA[select p.name.first from from Person p]]></programlisting>
+
+ <para>
+ 여기서 Person의 name 프로퍼티는 하나의 컴포넌트이다. 컴포넌트들은 또한 <literal>where</literal> 절
+ 내에 사용될 수 있다:
+ </para>
+
+ <programlisting><![CDATA[from from Person p where p.name = :name]]></programlisting>
+ <programlisting><![CDATA[from from Person p where p.name.first = :firstName]]></programlisting>
+
+ <para>
+ 컴포넌트들은 또한 <literal>order by</literal> 절 내에 사용될 수 있다:
+ </para>
+
+ <programlisting><![CDATA[from from Person p order by p.name]]></programlisting>
+ <programlisting><![CDATA[from from Person p order by p.name.first]]></programlisting>
+
+ <para>
+ 컴포넌트들에 대한 또 다른 공통된 사용은 <xref linkend="queryhql-tuple">행 값 생성자들</xref> 내에서이다.
+ </para>
+ </sect1>
+
+ <sect1 id="queryhql-tuple">
+ <title>행 값 생성자 구문</title>
+
+ <para>
+ 비록 기반 데이터베이스가 행 값 생성자 개념을 지원하지 않을 수도 있을지라도, HQL은
+ (때때로 <literal>tuple</literal> 구문이라 불리는) ANSI SQL <literal>행 값 생성자</literal> 구문 사용을
+ 지원한다. 여기서 우리는 일반적으로 전형저그올 컴포넌트들과 연관된, 다중 값 비교를 언급하고 있다:
+ </para>
+
+ <programlisting><![CDATA[from Person p where p.name.first='John' and p.name.last='Jingleheimer-Schmidt']]></programlisting>
+
+ <para>
+ 비록 약간 장황할지라도, 그것은 유효한 구문이다. 이것을 약간 더 간결하게 만들고
+ <literal>행 값 생성자</literal> 구문을 사용하는 것이 좋다:
+ </para>
+
+ <programlisting><![CDATA[from Person p where p.name=('John', 'Jingleheimer-Schmidt')]]></programlisting>
+
+ <para>
+ 또한 이것을 <literal>select</literal> 절 내에 지정하는 것이 유용할 수 있다:
+ </para>
+
+ <programlisting><![CDATA[select p.name from from Person p]]></programlisting>
+
+ <para>
+ <literal>행 값 생성자</literal> 구문 사용이 유익할 수 있는 또 다른 시점은 다중 값들에 대해
+ 비교될 필요가 있는 서브질의들을 사용할 때이다:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+where not ( cat.name, cat.color ) in (
+ select cat.name, cat.color from DomesticCat cat
+)]]></programlisting>
+
+ <para>
+ 만일 당신이 이 구문을 사용하고자 원할 경우인지를 결정할 때 고려할 한 가지는 그 질의가
+ 메타데이터 내에 있는 컴포넌트 서브-프로퍼티들의 순서에 의존하게 될 것이라는 점이다.
+ </para>
+
+ </sect1>
+
</chapter>
Modified: core/tags/v326/doc/reference/ko/modules/query_sql.xml
===================================================================
--- core/tags/v326/doc/reference/ko/modules/query_sql.xml 2008-06-15 14:36:50 UTC (rev 14767)
+++ core/tags/v326/doc/reference/ko/modules/query_sql.xml 2008-06-15 14:39:42 UTC (rev 14768)
@@ -143,10 +143,12 @@
.addJoin("cat.dogs");
]]></programlisting>
- <p>이 단계에서 우리는 Hibernate에서 native 질의들을 사용가능하도록 만들기 위해
- sql 질의들을 강화시키지는 것을 시작하지 않고서도 native 질의들로서 가능한 것의 한계에
+ <para>
+ 이 단계에서 우리는 Hibernate에서 native 질의들을 사용가능하도록 만들기 위해
+ sql 질의들을 강화시키지는 것을 시작하지 않고서도 native 질의들로서 가능한 것의 한계에
도달하고 있다; 문제점들은 동일한 타입의 여러 엔티티들을 반환할 때 또는 디폴트 alias/column
- 이름들이 충분하지 않을 때 발생하기 시작한다.</p>
+ 이름들이 충분하지 않을 때 발생하기 시작한다.
+ </para>
</sect2>
<sect2>
Modified: core/tags/v326/doc/reference/ko/modules/tutorial.xml
===================================================================
--- core/tags/v326/doc/reference/ko/modules/tutorial.xml 2008-06-15 14:36:50 UTC (rev 14767)
+++ core/tags/v326/doc/reference/ko/modules/tutorial.xml 2008-06-15 14:39:42 UTC (rev 14768)
@@ -562,7 +562,7 @@
</sect2>
- <sect2 id="tutorial-firstapp-workingpersistence" revision="4">
+ <sect2 id="tutorial-firstapp-workingpersistence" revision="5">
<title>객체 로딩과 객체 저장</title>
<para>
@@ -625,26 +625,45 @@
<literal>sessionFactory.getCurrentSession()</literal>은 무엇을 행하는가? 먼저
당신은 당신이 (<literal>HibernateUtil</literal> 덕분에 쉽게) <literal>SessionFactory</literal>을
당신이 소유하고 있다면, 원하는 만큼 어디서든 여러번 그것을 호출할 수 있다.
- <literal>getCurrentSession()</literal> 메소드는 항상 "현재의" 작업 단위를 반환한다. 우리가
- <literal>hibernate.cfg.xml</literal> 내에서 이 매커니즘에 대한 구성 옵션을 "thread"로 전환시켰음을 기억하는가?
- 그러므로 현재 작업 단위의 영역은 우리의 어플리케이션을 실행시키는 현재의 Java 쓰레드이다. 하지만 이것은
- 전부가 진실은 아니다. 그것이 처음으로 필요로 되고, <literal>getCurrentSession()</literal>을 첫번째로
- 호출할 때 <literal>Session</literal>이 시작된다. 그때 현째의 쓰레드에 대해 Hibernate에 의해 바인드 된다.
- 트랜잭션이 종료될 때 커밋 되거나 롤백되고, Hibernate는 또한 쓰레드로부터 <literal>Session</literal>을
- 바인드 해제시키고 당신을 위해 그것을 닫는다. 만일 당신이 <literal>getCurrentSession()</literal>을 다시
- 호출한다면, 당신은 새로운 <literal>Session</literal>을 얻고 새로운 작업단위를 시작할 수 있다. 이
- <emphasis>thread-bound</emphasis> 프로그래밍 모형은 Hibernate를 사용하는 가장 대중적인 방법이다.
+ <literal>getCurrentSession()</literal> 메소드는 항상 "현재의" 작업 단위를 반환한다.
+ <literal>hibernate.cfg.xml</literal>에서 우리가 이 메커니즘에 대한 구성 옵션을 "thread"로 전환시켰음을 기억하는가?
+ 그러므로 현재 작업 단위는 우리의 어플리케이션을 실행시키는 현재의 Java 쓰레드에 묶여 있다. 하지만
+ 이것은 전체 그림이 아니며, 작업 단위가 시작되고 그것이 끝낸 때 당신은 또한 영역(scope)을 고려해야 한다.
</para>
<para>
- 트랜잭션 핸들링과 경계구분에 대한 추가 정보는 <xref linkend="transactions"/>을 살펴보라.
- 우리는 또한 앞의 예제에서 임의의 오류 처리와 롤백을 생략했다.
+ 처름으로 필요할 때, <literal>getCurrentSession()</literal>에 대한 첫번째 호출이 이루어질 때,
+ <literal>Session</literal>이 시작된다. 그때 그것은 Hibernate에 의해 현재 쓰레드에 바인드 된다.
+ 트랜잭션이 끝날 때, 비록 커밋되든 또는 롤백되든 어느 경우든 Hibenate는 당신을 위해 쓰레드로부터
+ <literal>Session</literal>을 자동적으로 언바인드시키고 그것을 닫는다. 만일 당신이 다시
+ <literal>getCurrentSession()</literal>를 호출할 경우, 당신은 새로운 <literal>Session</literal>을 얻고
+ 새로운 작업 단위를 시작할 수 있다. 이 <emphasis>thread-bound</emphasis> 프로그래밍 모형은
+ Hibernate를 사용하는 가장 대중적인 방법이다. 왜냐하면 그것은 당신의 코드를 유연하게 배치하는 것을
+ 허용해주기 때문이다(트랜잭션 경계구분 코드는 데이터베이스 접근 코드와 분리될 수 있으며,
+ 우리는 이 튜토리얼의 뒷 부분에서 이것을 다룰 것이다).
</para>
<para>
- 이 첫 번째 루틴을 실행하기 위해서 우리는 호출 가능한 대상을 Ant 빌드 파일에 추가해야 한다:
+ 작업 영역의 단위와 관련하여, Hibernate <literal>Session</literal>은 한 개 내지 여러 개의
+ 데이터베이스 오퍼레이션들을 실행시키는데 사용될 수 있는가? 위의 예제는 한 개의 오퍼레이션에
+ 대해 한 개의 <literal>Session</literal>을 사용하고 있다. 이것은 단순한 일치이며, 예제는
+ 어떤 다른 오퍼레이션을 보여주기에는 충분히 복잡하지 않다. Hibernate <literal>Session</literal>의
+ 영역은 유연하지만 당신은 <emphasis>모든</emphasis> 데이터페이스 오퍼레이션에 대해
+ 새로운 Hibernate <literal>Session</literal>을 사용하도록 당신의 어플리케이션을 설계해서는
+ 결코 아니될 것이다. 따라서 만일 당신이 다음 (매우 사소한) 예제들에서 여러번 그것을 보게될지라도,
+ <emphasis>session-per-operation</emphasis> 안티-패턴(anti-pattern)을 고려하라.
+ 실제 (웹) 어플리케이션은 이 튜토리얼의 뒷 부분에 예시되어 있다.
</para>
+ <para>
+ 트랜잭션 핸들링과 경계구분에 대한 추가 정보는 <xref linkend="transactions"/>을 살펴보라.
+ 우리는 또한 앞의 예제에서 임의의 오류 처리와 롤백을 생략했다.
+ </para>
+
+ <para>
+ 이 첫 번째 루틴을 실행하기 위해서 우리는 호출 가능한 대상을 Ant 빌드 파일에 추가해야 한다:
+ </para>
+
<programlisting><![CDATA[<target name="run" depends="compile">
<java fork="true" classname="events.EventManager" classpathref="libraries">
<classpath path="${targetdir}"/>
@@ -1201,7 +1220,7 @@
그것은 새로운 이벤트들을 입력하기 위한 HTML form을 제공한다.
</para>
- <sect2 id="tutorial-webapp-servlet" revision="1">
+ <sect2 id="tutorial-webapp-servlet" revision="2">
<title>기본 서블릿 작성하기</title>
<para>
@@ -1249,24 +1268,30 @@
}]]></programlisting>
<para>
- 우리가 여기서 적용하는 패턴은 <emphasis>session-per-request</emphasis>이다. 하나의 요청이
- 서블릿에 도달할 때, 하나의 새로운 Hibernate <literal>Session</literal>이
+ 우리가 여기서 적용하는 패턴은 <emphasis>session-per-request</emphasis>이다. 하나의 요청이
+ 서블릿에 도달할 때, 하나의 새로운 Hibernate <literal>Session</literal>이
<literal>SessionFactory</literal> 상의 <literal>getCurrentSession()</literal>에 대한
- 첫번째 호출을 통해 열린다. 그때 하나의 데이터베이스 트랜잭션이 시작되고, 모든 데이터 접근이 하나의 트랜잭션
- 내에서 발생하는 한, 데이터가 읽혀지거나 기록되는데 문제가 없다(우리는 어플리케이션들 내에서 auto-commit 모드를
- 사용하지 않는다).
+ 첫번째 호출을 통해 열린다. 그때 하나의 데이터베이스 트랜잭션이 시작되고, 모든 데이터 접근이 하나의 트랜잭션
+ 내에서 발생하는 한, 데이터가 읽혀지거나 기록되는데 문제가 없다(우리는 어플리케이션들 내에서 auto-commit 모드를
+ 사용하지 않는다).
</para>
<para>
- 다음으로, 요청의 가능한 액션들이 처리되고 응답 HTML이 렌더링된다. 우리는 곧장 그부분으로 갈 것이다.
+ 모든 데이터베이스 오퍼레이션에 대해 새로운 Hibernate <literal>Session</literal>을 사용하지 <emphasis>말라</emphasis>.
+ 전체 요청에 대해 영역지워진 한 개의 Hibernate <literal>Session</literal>을 사용하라. <literal>getCurrentSession()</literal>을
+ 사용하라. 그것은 현재의 자바 쓰레드에 자동적으로 바인드된다.
</para>
<para>
- 마지막으로, 프로세싱과 렌더링이 완료될 때 작업 단위가 종료된다. 만일 어떤 문제가 프로세싱과 렌더링 동안에 발생될 경우,
- 하나의 예외상황이 던져질 것이고 데이터베이스 트랜잭션은 롤백될 것이다. 이것은 <literal>session-per-request</literal>을
- 완료시킨다. 모든 서블릿 내에 있는 트랜잭션 구획 코드 대신에 당신은 또한 서블릿 필터를 사용할 수 있다.
+ 다음으로, 요청의 가능한 액션들이 처리되고 응답 HTML이 렌더링된다. 우리는 곧장 그부분으로 갈 것이다.
+ </para>
+
+ <para>
+ 마지막으로, 프로세싱과 렌더링이 완료될 때 작업 단위가 종료된다. 만일 어떤 문제가 프로세싱과 렌더링 동안에 발생될 경우,
+ 하나의 예외상황이 던져질 것이고 데이터베이스 트랜잭션은 롤백될 것이다. 이것은 <literal>session-per-request</literal>을
+ 완료시킨다. 모든 서블릿 내에 있는 트랜잭션 구획 코드 대신에 당신은 또한 서블릿 필터를 사용할 수 있다.
<emphasis>Open Session in View</emphasis>로 명명되는 이 패턴에 대한 추가 정보는 Hibernate 웹 사이트와 위키를 보라.
- 당신은 서블릿 내에서가 아닌 JSP 내에 당신의 뷰를 렌더링하는 것을 고려할 때 그것을 필요로 할 것이다.
+ 당신은 서블릿 내에서가 아닌 JSP 내에 당신의 뷰를 렌더링하는 것을 고려할 때 그것을 필요로 할 것이다.
</para>
</sect2>
@@ -1275,7 +1300,7 @@
<title>프로세싱과 렌더링</title>
<para>
- 요청의 처리와 페이지의 렌더링을 구현하자.
+ 요청의 처리와 페이지의 렌더링을 구현하자.
</para>
<programlisting><![CDATA[// Write HTML header
16 years, 7 months
Hibernate SVN: r14767 - core/tags/v326/doc/reference/ko.
by hibernate-commits@lists.jboss.org
Author: jdkim528
Date: 2008-06-15 10:36:50 -0400 (Sun, 15 Jun 2008)
New Revision: 14767
Modified:
core/tags/v326/doc/reference/ko/master.xml
Log:
Modified: core/tags/v326/doc/reference/ko/master.xml
===================================================================
--- core/tags/v326/doc/reference/ko/master.xml 2008-06-14 07:43:17 UTC (rev 14766)
+++ core/tags/v326/doc/reference/ko/master.xml 2008-06-15 14:36:50 UTC (rev 14767)
@@ -33,7 +33,7 @@
<bookinfo lang="ko">
<title>HIBERNATE - 개성있는 자바를 위한 관계 영속</title>
<subtitle>하이버네이트 참조 문서</subtitle>
- <releaseinfo lang="ko">3.2 cr3</releaseinfo>
+ <releaseinfo lang="ko">3.2.6</releaseinfo>
</bookinfo>
<toc lang="ko" />
16 years, 7 months
Hibernate SVN: r14766 - search/trunk/src/test/org/hibernate/search/test/reader.
by hibernate-commits@lists.jboss.org
Author: sannegrinovero
Date: 2008-06-14 03:43:17 -0400 (Sat, 14 Jun 2008)
New Revision: 14766
Modified:
search/trunk/src/test/org/hibernate/search/test/reader/NotSharedReaderPerfTest.java
search/trunk/src/test/org/hibernate/search/test/reader/ReaderPerfTestCase.java
search/trunk/src/test/org/hibernate/search/test/reader/SharedReaderPerfTest.java
Log:
cleanup ReaderPerfTestCase: was run twice in suite.
Modified: search/trunk/src/test/org/hibernate/search/test/reader/NotSharedReaderPerfTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/NotSharedReaderPerfTest.java 2008-06-13 22:42:10 UTC (rev 14765)
+++ search/trunk/src/test/org/hibernate/search/test/reader/NotSharedReaderPerfTest.java 2008-06-14 07:43:17 UTC (rev 14766)
@@ -2,9 +2,7 @@
package org.hibernate.search.test.reader;
import org.hibernate.cfg.Configuration;
-import org.hibernate.search.store.FSDirectoryProvider;
import org.hibernate.search.Environment;
-import org.apache.lucene.analysis.StopAnalyzer;
/**
* @author Emmanuel Bernard
@@ -12,9 +10,6 @@
public class NotSharedReaderPerfTest extends ReaderPerfTestCase {
protected void configure(Configuration cfg) {
super.configure( cfg );
- cfg.setProperty( "hibernate.search.default.directory_provider", FSDirectoryProvider.class.getName() );
- cfg.setProperty( "hibernate.search.default.indexBase", "./indextemp" );
- cfg.setProperty( Environment.ANALYZER_CLASS, StopAnalyzer.class.getName() );
cfg.setProperty( Environment.READER_STRATEGY, "not-shared" );
}
}
Modified: search/trunk/src/test/org/hibernate/search/test/reader/ReaderPerfTestCase.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/ReaderPerfTestCase.java 2008-06-13 22:42:10 UTC (rev 14765)
+++ search/trunk/src/test/org/hibernate/search/test/reader/ReaderPerfTestCase.java 2008-06-14 07:43:17 UTC (rev 14766)
@@ -26,7 +26,7 @@
/**
* @author Emmanuel Bernard
*/
-public class ReaderPerfTestCase extends SearchTestCase {
+public abstract class ReaderPerfTestCase extends SearchTestCase {
protected void setUp() throws Exception {
File sub = getBaseIndexDir();
sub.mkdir();
@@ -221,7 +221,7 @@
super.configure( cfg );
File sub = getBaseIndexDir();
cfg.setProperty( "hibernate.search.default.indexBase", sub.getAbsolutePath() );
- cfg.setProperty( "hibernate.search.Clock.directory_provider", FSDirectoryProvider.class.getName() );
+ cfg.setProperty( "hibernate.search.default.directory_provider", FSDirectoryProvider.class.getName() );
cfg.setProperty( Environment.ANALYZER_CLASS, StopAnalyzer.class.getName() );
}
Modified: search/trunk/src/test/org/hibernate/search/test/reader/SharedReaderPerfTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/SharedReaderPerfTest.java 2008-06-13 22:42:10 UTC (rev 14765)
+++ search/trunk/src/test/org/hibernate/search/test/reader/SharedReaderPerfTest.java 2008-06-14 07:43:17 UTC (rev 14766)
@@ -2,10 +2,7 @@
package org.hibernate.search.test.reader;
import org.hibernate.cfg.Configuration;
-import org.hibernate.search.store.RAMDirectoryProvider;
-import org.hibernate.search.store.FSDirectoryProvider;
import org.hibernate.search.Environment;
-import org.apache.lucene.analysis.StopAnalyzer;
/**
* @author Emmanuel Bernard
@@ -13,9 +10,6 @@
public class SharedReaderPerfTest extends ReaderPerfTestCase {
protected void configure(Configuration cfg) {
super.configure( cfg );
- cfg.setProperty( "hibernate.search.default.directory_provider", FSDirectoryProvider.class.getName() );
- cfg.setProperty( "hibernate.search.default.indexBase", "./indextemp" );
- cfg.setProperty( Environment.ANALYZER_CLASS, StopAnalyzer.class.getName() );
cfg.setProperty( Environment.READER_STRATEGY, "shared" );
}
}
16 years, 7 months
Hibernate SVN: r14765 - in search/trunk/src: test/org/hibernate/search/test/reader and 2 other directories.
by hibernate-commits@lists.jboss.org
Author: sannegrinovero
Date: 2008-06-13 18:42:10 -0400 (Fri, 13 Jun 2008)
New Revision: 14765
Added:
search/trunk/src/java/org/hibernate/search/reader/SharingBufferReaderProvider.java
search/trunk/src/test/org/hibernate/search/test/reader/functionality/
search/trunk/src/test/org/hibernate/search/test/reader/functionality/SharingBufferIndexProviderTest.java
search/trunk/src/test/org/hibernate/search/test/reader/functionality/TestableSharingBufferReaderProvider.java
search/trunk/src/test/org/hibernate/search/test/reader/performance/
search/trunk/src/test/org/hibernate/search/test/reader/performance/AbstractActivity.java
search/trunk/src/test/org/hibernate/search/test/reader/performance/BufferSharingReaderPerfTest.java
search/trunk/src/test/org/hibernate/search/test/reader/performance/IndexFillRunnable.java
search/trunk/src/test/org/hibernate/search/test/reader/performance/InsertActivity.java
search/trunk/src/test/org/hibernate/search/test/reader/performance/NotSharedReaderPerfTest.java
search/trunk/src/test/org/hibernate/search/test/reader/performance/ReaderPerformance.java
search/trunk/src/test/org/hibernate/search/test/reader/performance/SearchActivity.java
search/trunk/src/test/org/hibernate/search/test/reader/performance/SharedReaderPerfTest.java
search/trunk/src/test/org/hibernate/search/test/reader/performance/UpdateActivity.java
Log:
HSEARCH-212 : Added a new very efficient ReaderProvider
Added: search/trunk/src/java/org/hibernate/search/reader/SharingBufferReaderProvider.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/reader/SharingBufferReaderProvider.java (rev 0)
+++ search/trunk/src/java/org/hibernate/search/reader/SharingBufferReaderProvider.java 2008-06-13 22:42:10 UTC (rev 14765)
@@ -0,0 +1,200 @@
+package org.hibernate.search.reader;
+
+import static org.hibernate.search.reader.ReaderProviderHelper.buildMultiReader;
+import static org.hibernate.search.reader.ReaderProviderHelper.clean;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.lucene.index.IndexReader;
+import org.hibernate.search.SearchException;
+import org.hibernate.search.engine.SearchFactoryImplementor;
+import org.hibernate.search.store.DirectoryProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Sanne Grinovero
+ */
+public class SharingBufferReaderProvider implements ReaderProvider {
+
+ //contains last updated Reader; protected by lockOnOpenLatest.
+ private volatile ReaderUsagePair current;
+
+ private final Lock lockOnOpenLatest = new ReentrantLock();
+
+ //contains all older Readers:
+ protected final Map<IndexReader,ReaderUsagePair> oldReaders = new ConcurrentHashMap<IndexReader,ReaderUsagePair>();
+
+ private final Logger log = LoggerFactory.getLogger ( SharingBufferReaderProvider.class );
+
+ public void closeReader(IndexReader reader) {
+ if ( reader == current.reader ) {
+ boolean closeit;
+ lockOnOpenLatest.lock();
+ try {
+ if ( reader == current.reader ){
+ current.usageCounter.getAndDecrement();
+ closeit = false;
+ }
+ else {
+ closeit = true;
+ }
+ }
+ finally {
+ lockOnOpenLatest.unlock();
+ }
+ if ( closeit ) {
+ closeOldReader( reader );
+ }
+ }
+ else {
+ closeOldReader( reader );
+ }
+ printState();
+ }
+
+ private void closeOldReader(IndexReader reader) {
+ try {
+ ReaderUsagePair pair = oldReaders.get( reader );
+ boolean closed = pair.close(); //also testing "assert pair!=null";
+ if ( closed ) {
+ //not longer needed, so remove references:
+ oldReaders.remove( reader );
+ log.trace( "IndexReader closed." );
+ }
+ else {
+ log.trace( "Closing of IndexReader skipped: still being used." );
+ }
+ }
+ catch (IOException e) {
+ log.warn( "Unable to close Lucene IndexReader", e );
+ //remove references anyway:
+ oldReaders.remove( reader );
+ }
+ }
+
+ public void initialize(Properties props, SearchFactoryImplementor searchFactoryImplementor) {
+ //FIXME initialize currentReaderContainer here instead of lazy
+ }
+
+ public IndexReader openReader(DirectoryProvider... directoryProviders) {
+ boolean trace = log.isTraceEnabled();
+ if ( trace ) log.trace( "Opening IndexReader for directoryProviders: {}", directoryProviders );
+ IndexReader toReturn;
+ lockOnOpenLatest.lock();
+ try {
+ if ( current == null ) { //FIXME move this case to initialize
+ current = initialReaderOpening( directoryProviders );
+ log.trace( "IndexReader initialized." );
+ }
+ else {
+ reopenIndexreader();
+ }
+ toReturn = current.reader; //choose reader before unlock
+ } finally {
+ lockOnOpenLatest.unlock();
+ }
+ printState();
+ return toReturn;
+ }
+
+ private void reopenIndexreader() {
+ // we own the lock
+ IndexReader before = current.reader;
+ IndexReader updatedReader;
+ try {
+ updatedReader = before.reopen();
+ } catch (IOException e) {
+ throw new SearchException( "Unable to reopen IndexReader", e );
+ }
+ if ( before == updatedReader ) {
+ current.incrementUseCounter();
+ }
+ else { //store the old one for close() functionality.
+ int useCount = current.usageCounter.get();
+ if ( useCount != 0 ) {
+ oldReaders.put( before, current );
+ }
+ else {
+ //or close it if nobody uses.
+ try {
+ current.reader.close();
+ } catch (IOException e) {
+ log.warn( "Unable to close Lucene IndexReader", e );
+ }
+ }
+ current = new ReaderUsagePair( updatedReader );
+ }
+ }
+
+ public final void printState(){
+ if ( log.isTraceEnabled())
+ log.trace( "Current "+ current + " older:" + oldReaders.values() );
+ }
+
+ private ReaderUsagePair initialReaderOpening(DirectoryProvider[] directoryProviders) {
+ // we own the lock
+ final int length = directoryProviders.length;
+ IndexReader[] readers = new IndexReader[length];
+ try {
+ for (int index = 0; index < length; index++) {
+ readers[index] = IndexReader.open( directoryProviders[index].getDirectory() );
+ }
+ }
+ catch (IOException e) {
+ //TODO more contextual info
+ clean( new SearchException( "Unable to open one of the Lucene indexes", e ), readers );
+ }
+ IndexReader iR = readerFactory( length, readers );
+ return new ReaderUsagePair( iR );
+ }
+
+ //overridable method for testability:
+ protected IndexReader readerFactory(int length, IndexReader[] readers) {
+ return buildMultiReader( length, readers );
+ }
+
+ protected static class ReaderUsagePair {
+ protected final IndexReader reader;
+ protected final AtomicInteger usageCounter;
+
+ ReaderUsagePair(IndexReader r) {
+ reader = r;
+ usageCounter = new AtomicInteger( 1 );
+ }
+
+ void incrementUseCounter() {
+ usageCounter.incrementAndGet();
+ }
+
+ public int getUsageCount(){
+ return usageCounter.get();
+ }
+
+ /**
+ * @return true when really closing the underlying IndexReader
+ * @throws IOException
+ */
+ private boolean close() throws IOException {
+ int count = usageCounter.decrementAndGet();
+ if ( count == 0 ) {
+ reader.close();
+ return true;
+ }
+ assert count >= 0;
+ return false;
+ }
+
+ public String toString(){
+ return "Reader:"+this.hashCode()+" count="+usageCounter.get();
+ }
+
+ }
+
+}
Added: search/trunk/src/test/org/hibernate/search/test/reader/functionality/SharingBufferIndexProviderTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/functionality/SharingBufferIndexProviderTest.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/reader/functionality/SharingBufferIndexProviderTest.java 2008-06-13 22:42:10 UTC (rev 14765)
@@ -0,0 +1,79 @@
+package org.hibernate.search.test.reader.functionality;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.hibernate.search.test.reader.functionality.TestableSharingBufferReaderProvider.MockIndexReader;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Sanne Grinovero
+ */
+public class SharingBufferIndexProviderTest extends TestCase {
+
+ private final TestableSharingBufferReaderProvider readerProvider = new TestableSharingBufferReaderProvider();
+ private final CountDownLatch startSignal = new CountDownLatch(1);
+ private final Runnable searchTask = new SearchTask();
+ private final Runnable changeTask = new ChangeTask();
+ private final AtomicInteger countDoneSearches = new AtomicInteger();
+ private final AtomicInteger countDoneIndexmods = new AtomicInteger();
+ private static final int SEARCHES_NUM = 5000;
+
+ public void testStressingMock() throws InterruptedException {
+ ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool( 200 );//much chaos
+ for ( int i = 0; i < SEARCHES_NUM; i++ ) {
+ executor.execute( makeTask( i ) );
+ }
+ executor.shutdown();
+ startSignal.countDown();
+ executor.awaitTermination( 15, TimeUnit.SECONDS );
+ assertTrue( "memory leak: holding a reference to some unused IndexReader", readerProvider.isMapEmpty() );
+ MockIndexReader openReader = readerProvider.fakeOpenReader();
+ for ( MockIndexReader reader : readerProvider.getCreatedIndexReaders() ) {
+ if ( reader != openReader ) {
+ assertTrue( "an IndexReader is still open", reader.isClosed() );
+ }
+ }
+ assertTrue( "the most current reader should be open", ! openReader.isClosed() );
+ assertEquals( SEARCHES_NUM, countDoneSearches.get() );
+ assertEquals( SEARCHES_NUM/10, countDoneIndexmods.get() );
+ }
+
+ private Runnable makeTask(int i) {
+ if ( i % 10 == 0) {
+ return changeTask;
+ }
+ else {
+ return searchTask;
+ }
+ }
+
+ private class SearchTask implements Runnable {
+ public void run() {
+ try {
+ startSignal.await();
+ } catch (InterruptedException e) {
+ //manage termination:
+ return;
+ }
+ MockIndexReader fakeOpenReader = readerProvider.fakeOpenReader();
+ Thread.yield();
+ readerProvider.closeReader( fakeOpenReader );
+ countDoneSearches.incrementAndGet();
+ }
+ }
+
+ private class ChangeTask extends SearchTask {
+ public void run() {
+ super.run();
+ Thread.yield();
+ readerProvider.setToDirtyState();
+ countDoneIndexmods.incrementAndGet();
+ }
+ }
+
+}
Added: search/trunk/src/test/org/hibernate/search/test/reader/functionality/TestableSharingBufferReaderProvider.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/functionality/TestableSharingBufferReaderProvider.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/reader/functionality/TestableSharingBufferReaderProvider.java 2008-06-13 22:42:10 UTC (rev 14765)
@@ -0,0 +1,206 @@
+package org.hibernate.search.test.reader.functionality;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Vector;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.FieldSelector;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermDocs;
+import org.apache.lucene.index.TermEnum;
+import org.apache.lucene.index.TermFreqVector;
+import org.apache.lucene.index.TermPositions;
+import org.apache.lucene.index.TermVectorMapper;
+import org.hibernate.search.reader.SharingBufferReaderProvider;
+import org.hibernate.search.store.DirectoryProvider;
+
+/**
+ * @author Sanne Grinovero
+ */
+public class TestableSharingBufferReaderProvider extends SharingBufferReaderProvider {
+
+ private final AtomicBoolean isIndexReaderCurrent = new AtomicBoolean( false );//starts at true, see MockIndexReader contructor
+ private final AtomicBoolean factoryCalled = new AtomicBoolean( false );
+ private final Vector<MockIndexReader> createdReadersHistory = new Vector<MockIndexReader>( 500 );
+ private final MockIndexReader firstIndexReader = new MockIndexReader();
+
+ @Override
+ protected IndexReader readerFactory(int length, IndexReader[] readers) {
+ if ( factoryCalled.compareAndSet( false, true) ) {
+ return firstIndexReader;
+ }
+ else {
+ throw new IllegalStateException( "factory for reader called more than once" );
+ }
+ }
+
+ public void setToDirtyState() {
+ isIndexReaderCurrent.set( false );
+ }
+
+ public boolean isMapEmpty(){
+ return super.oldReaders.isEmpty();
+ }
+
+ public List<MockIndexReader> getCreatedIndexReaders(){
+ return createdReadersHistory;
+ }
+
+ public MockIndexReader fakeOpenReader() {
+// System.out.println( "tracking "+oldReaders.size() + " old readers." );
+ return (MockIndexReader) super.openReader( new DirectoryProvider[0] );
+ }
+
+ public class MockIndexReader extends IndexReader {
+
+ private final AtomicBoolean closed = new AtomicBoolean( false );
+ private final AtomicBoolean hasAlreadyBeenReOpened = new AtomicBoolean( false );
+
+ MockIndexReader(){
+ createdReadersHistory.add( this );
+ if ( ! isIndexReaderCurrent.compareAndSet(false, true) ) {
+ throw new IllegalStateException( "Unnecessarily reopened" );
+ }
+ }
+
+ public final boolean isClosed() {
+ return closed.get();
+ }
+
+ @Override
+ protected void doClose() throws IOException {
+ boolean okToClose = closed.compareAndSet(false, true);
+ if ( ! okToClose ) {
+ throw new IllegalStateException( "Attempt to close a closed IndexReader" );
+ }
+ if ( ! hasAlreadyBeenReOpened.get() ){
+ throw new IllegalStateException( "Attempt to close the most current IndexReader" );
+ }
+ }
+
+ @Override
+ public synchronized IndexReader reopen(){
+ if ( isIndexReaderCurrent.get() ) {
+ return this;
+ }
+ else {
+ if ( hasAlreadyBeenReOpened.compareAndSet( false, true) ) {
+ return new MockIndexReader();
+ }
+ else
+ throw new IllegalStateException( "Attempt to reopen an old IndexReader more than once" );
+ }
+ }
+
+ @Override
+ protected void doCommit() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void doDelete(int docNum) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void doSetNorm(int doc, String field, byte value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void doUndeleteAll() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int docFreq(Term t) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Document document(int n, FieldSelector fieldSelector) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Collection getFieldNames(FieldOption fldOption) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public TermFreqVector getTermFreqVector(int docNumber, String field) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void getTermFreqVector(int docNumber, String field, TermVectorMapper mapper) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void getTermFreqVector(int docNumber, TermVectorMapper mapper) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public TermFreqVector[] getTermFreqVectors(int docNumber) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean hasDeletions() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isDeleted(int n) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int maxDoc() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] norms(String field) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void norms(String field, byte[] bytes, int offset) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int numDocs() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public TermDocs termDocs() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public TermPositions termPositions() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public TermEnum terms() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public TermEnum terms(Term t) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+}
Added: search/trunk/src/test/org/hibernate/search/test/reader/performance/AbstractActivity.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/performance/AbstractActivity.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/reader/performance/AbstractActivity.java 2008-06-13 22:42:10 UTC (rev 14765)
@@ -0,0 +1,80 @@
+package org.hibernate.search.test.reader.performance;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.queryParser.MultiFieldQueryParser;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.search.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.search.FullTextQuery;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.Search;
+
+/**
+ * @author Sanne Grinovero
+ */
+public abstract class AbstractActivity implements Runnable {
+
+ private final ThreadLocal<QueryParser> parsers = new ThreadLocal<QueryParser>(){
+ @Override
+ protected QueryParser initialValue(){
+ return new MultiFieldQueryParser(
+ new String[] {"name", "physicalDescription", "suspectCharge"},
+ new StandardAnalyzer() );
+ }
+ };
+
+ private final SessionFactory sf;
+ private final AtomicInteger jobSeed = new AtomicInteger();
+ private final CountDownLatch startSignal;
+
+ AbstractActivity(SessionFactory sf, CountDownLatch startSignal) {
+ this.startSignal = startSignal;
+ this.sf = sf;
+ }
+
+ public final void run() {
+ try {
+ startSignal.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ return;
+ }
+ Session s = sf.openSession();
+ try {
+ FullTextSession fts = Search.createFullTextSession( s );
+ Transaction tx = s.beginTransaction();
+ boolean ok = false;
+ try {
+ doAction( fts, jobSeed.getAndIncrement() );
+ ok = true;
+ } finally {
+ if (ok)
+ tx.commit();
+ else
+ tx.rollback();
+ }
+ } finally {
+ s.close();
+ }
+ }
+
+ protected FullTextQuery getQuery(String queryString, FullTextSession s, Class... classes) {
+ Query luceneQuery = null;
+ try {
+ luceneQuery = parsers.get().parse(queryString);
+ }
+ catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return s.createFullTextQuery( luceneQuery, classes );
+ }
+
+ protected abstract void doAction(FullTextSession s, int jobSeed);
+
+}
Added: search/trunk/src/test/org/hibernate/search/test/reader/performance/BufferSharingReaderPerfTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/performance/BufferSharingReaderPerfTest.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/reader/performance/BufferSharingReaderPerfTest.java 2008-06-13 22:42:10 UTC (rev 14765)
@@ -0,0 +1,15 @@
+package org.hibernate.search.test.reader.performance;
+
+import org.hibernate.search.reader.SharingBufferReaderProvider;
+
+/**
+ * @author Sanne Grinovero
+ */
+public class BufferSharingReaderPerfTest extends ReaderPerformance {
+
+ @Override
+ protected String getReaderStrategyName() {
+ return SharingBufferReaderProvider.class.getName();
+ }
+
+}
Added: search/trunk/src/test/org/hibernate/search/test/reader/performance/IndexFillRunnable.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/performance/IndexFillRunnable.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/reader/performance/IndexFillRunnable.java 2008-06-13 22:42:10 UTC (rev 14765)
@@ -0,0 +1,37 @@
+package org.hibernate.search.test.reader.performance;
+
+import java.io.IOException;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.Field.Index;
+import org.apache.lucene.document.Field.Store;
+import org.apache.lucene.index.IndexWriter;
+
+/**
+ * @author Sanne Grinovero
+ */
+public class IndexFillRunnable implements Runnable {
+
+ private volatile int jobSeed = 0;
+ private final IndexWriter iw;
+
+ public IndexFillRunnable(IndexWriter iw) {
+ super();
+ this.iw = iw;
+ }
+
+ public void run() {
+ Field f1 = new Field("name", "Some One " + jobSeed++, Store.NO, Index.TOKENIZED );
+ Field f2 = new Field("physicalDescription", " just more people sitting around and filling my index... ", Store.NO, Index.TOKENIZED );
+ Document d = new Document();
+ d.add( f1 );
+ d.add( f2 );
+ try {
+ iw.addDocument( d );
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
Added: search/trunk/src/test/org/hibernate/search/test/reader/performance/InsertActivity.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/performance/InsertActivity.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/reader/performance/InsertActivity.java 2008-06-13 22:42:10 UTC (rev 14765)
@@ -0,0 +1,38 @@
+package org.hibernate.search.test.reader.performance;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.hibernate.SessionFactory;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.test.reader.Detective;
+import org.hibernate.search.test.reader.Suspect;
+
+/**
+ * @author Emmanuel Bernard
+ * @author Sanne Grinovero
+ */
+public class InsertActivity extends AbstractActivity {
+
+ InsertActivity(SessionFactory sf, CountDownLatch startSignal) {
+ super(sf, startSignal);
+ }
+
+ @Override
+ protected void doAction(FullTextSession s, int jobSeed) {
+ Detective detective = new Detective();
+ detective.setName("John Doe " + jobSeed);
+ detective.setBadge("123455" + jobSeed);
+ detective.setPhysicalDescription("Blond green eye etc etc");
+ s.persist(detective);
+ Suspect suspect = new Suspect();
+ suspect.setName("Jane Doe " + jobSeed);
+ suspect.setPhysicalDescription("brunette, short, 30-ish");
+ if (jobSeed % 20 == 0) {
+ suspect.setSuspectCharge("thief liar ");
+ } else {
+ suspect.setSuspectCharge(" It's 1875 in London. The police have captured career criminal Montmorency. In the process he has been grievously wounded and it is up to a young surgeon to treat his wounds. During his recovery Montmorency learns of the city's new sewer system and sees in it the perfect underground highway for his thievery. Washington Post columnist John Kelly recommends this title for middle schoolers, especially to be read aloud.");
+ }
+ s.persist(suspect);
+ }
+
+}
Added: search/trunk/src/test/org/hibernate/search/test/reader/performance/NotSharedReaderPerfTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/performance/NotSharedReaderPerfTest.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/reader/performance/NotSharedReaderPerfTest.java 2008-06-13 22:42:10 UTC (rev 14765)
@@ -0,0 +1,13 @@
+package org.hibernate.search.test.reader.performance;
+
+/**
+ * @author Sanne Grinovero
+ */
+public class NotSharedReaderPerfTest extends ReaderPerformance {
+
+ @Override
+ protected String getReaderStrategyName() {
+ return "not-shared";
+ }
+
+}
Added: search/trunk/src/test/org/hibernate/search/test/reader/performance/ReaderPerformance.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/performance/ReaderPerformance.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/reader/performance/ReaderPerformance.java 2008-06-13 22:42:10 UTC (rev 14765)
@@ -0,0 +1,119 @@
+package org.hibernate.search.test.reader.performance;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.lucene.analysis.SimpleAnalyzer;
+import org.apache.lucene.analysis.StopAnalyzer;
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.store.FSDirectory;
+import org.apache.lucene.store.LockObtainFailedException;
+import org.hibernate.search.Environment;
+import org.hibernate.search.store.FSDirectoryProvider;
+import org.hibernate.search.test.SearchTestCase;
+import org.hibernate.search.test.reader.Detective;
+import org.hibernate.search.test.reader.Suspect;
+import org.hibernate.search.util.FileHelper;
+
+/**
+ * To enable performance tests: de-comment buildBigIndex(); in setUp() and rename no_testPerformance
+ * @author Sanne Grinovero
+ */
+public abstract class ReaderPerformance extends SearchTestCase {
+
+ private static final File baseIndexDir = new File( new File( "." ), "indextemp" );
+
+ //more iterations for more reliable measures:
+ private static final int TOTAL_WORK_BATCHES = 1000;
+ //the next 3 define the kind of workload mix to test on:
+ private static final int SEARCHERS_PER_BATCH = 20;
+ private static final int UPDATES_PER_BATCH = 2;
+ private static final int INSERTIONS_PER_BATCH = 1;
+
+ private static final int WORKER_THREADS = 20;
+
+ protected void setUp() throws Exception {
+ baseIndexDir.mkdir();
+ File[] files = baseIndexDir.listFiles();
+ for ( File file : files ) {
+ FileHelper.delete( file );
+ }
+ super.setUp();
+ //enable this line:
+// buildBigIndex();
+ }
+
+ public void testFakeTest(){
+ //to make JUnit happy when disabling performance test
+ }
+
+ private void buildBigIndex() throws InterruptedException, CorruptIndexException, LockObtainFailedException, IOException {
+ FSDirectory directory = FSDirectory.getDirectory(new File(baseIndexDir, Detective.class.getCanonicalName()));
+ IndexWriter iw = new IndexWriter( directory, new SimpleAnalyzer(), true );
+ IndexFillRunnable filler = new IndexFillRunnable( iw );
+ ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool( WORKER_THREADS );
+ for (int batch=0; batch<=100000; batch++){
+ executor.execute( filler );
+ }
+ executor.shutdown();
+ executor.awaitTermination( 600, TimeUnit.SECONDS );
+ iw.close();
+ System.out.println( "Index created." );
+ }
+
+ protected Class[] getMappings() {
+ return new Class[] {
+ Detective.class,
+ Suspect.class
+ };
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+// FileHelper.delete( baseIndexDir );
+ }
+
+ protected final void configure(org.hibernate.cfg.Configuration cfg) {
+ super.configure( cfg );
+ cfg.setProperty( "hibernate.search.default.directory_provider", FSDirectoryProvider.class.getName() );
+ cfg.setProperty( "hibernate.search.default.indexBase", baseIndexDir.getAbsolutePath() );
+ cfg.setProperty( "hibernate.search.default.optimizer.transaction_limit.max", "10" ); // workaround too many open files
+ cfg.setProperty( Environment.ANALYZER_CLASS, StopAnalyzer.class.getName() );
+ cfg.setProperty( Environment.READER_STRATEGY, getReaderStrategyName() );
+ }
+
+ protected abstract String getReaderStrategyName();
+
+ //this test is disabled as it is very slow (and you should read the resulting numbers)
+ public final void no_testPerformance() throws InterruptedException{
+ ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool( WORKER_THREADS );
+ CountDownLatch startSignal = new CountDownLatch(1);
+ InsertActivity insertionTask = new InsertActivity( getSessions(), startSignal );
+ SearchActivity searchTask = new SearchActivity( getSessions(), startSignal );
+ UpdateActivity updateTask = new UpdateActivity( getSessions(), startSignal );
+ //we declare needed activities in order, scheduler will "mix":
+ for (int batch=0; batch<=TOTAL_WORK_BATCHES; batch++){
+ for ( int inserters=0; inserters<INSERTIONS_PER_BATCH; inserters++)
+ executor.execute( insertionTask );
+ for ( int searchers=0; searchers<SEARCHERS_PER_BATCH; searchers++)
+ executor.execute( searchTask );
+ for ( int updaters=0; updaters<UPDATES_PER_BATCH; updaters++)
+ executor.execute( updateTask );
+ }
+ executor.shutdown();
+ long startTime = System.currentTimeMillis();
+ startSignal.countDown();//start!
+ executor.awaitTermination( 600, TimeUnit.SECONDS );
+ long endTime = System.currentTimeMillis();
+ System.out.println( "Performance test for " + getReaderStrategyName() + ": " + (endTime - startTime) +"ms. (" +
+ (TOTAL_WORK_BATCHES*SEARCHERS_PER_BATCH) + " searches, " +
+ (TOTAL_WORK_BATCHES*INSERTIONS_PER_BATCH) + " insertions, " +
+ (TOTAL_WORK_BATCHES*UPDATES_PER_BATCH) + " updates)" );
+ }
+
+}
Added: search/trunk/src/test/org/hibernate/search/test/reader/performance/SearchActivity.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/performance/SearchActivity.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/reader/performance/SearchActivity.java 2008-06-13 22:42:10 UTC (rev 14765)
@@ -0,0 +1,27 @@
+package org.hibernate.search.test.reader.performance;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.hibernate.SessionFactory;
+import org.hibernate.search.FullTextQuery;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.test.reader.Detective;
+
+/**
+ * @author Emmanuel Bernard
+ * @author Sanne Grinovero
+ */
+public class SearchActivity extends AbstractActivity {
+
+ SearchActivity(SessionFactory sf, CountDownLatch startSignal) {
+ super(sf, startSignal);
+ }
+
+ @Override
+ protected void doAction(FullTextSession s, int jobSeed) {
+ FullTextQuery q = getQuery( "John Doe", s, Detective.class);
+ q.setMaxResults( 10 );
+ q.getResultSize();
+ }
+
+}
Added: search/trunk/src/test/org/hibernate/search/test/reader/performance/SharedReaderPerfTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/performance/SharedReaderPerfTest.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/reader/performance/SharedReaderPerfTest.java 2008-06-13 22:42:10 UTC (rev 14765)
@@ -0,0 +1,13 @@
+package org.hibernate.search.test.reader.performance;
+
+/**
+ * @author Sanne Grinovero
+ */
+public class SharedReaderPerfTest extends ReaderPerformance {
+
+ @Override
+ protected String getReaderStrategyName() {
+ return "shared";
+ }
+
+}
Added: search/trunk/src/test/org/hibernate/search/test/reader/performance/UpdateActivity.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/reader/performance/UpdateActivity.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/reader/performance/UpdateActivity.java 2008-06-13 22:42:10 UTC (rev 14765)
@@ -0,0 +1,30 @@
+package org.hibernate.search.test.reader.performance;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+import org.hibernate.SessionFactory;
+import org.hibernate.search.FullTextQuery;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.test.reader.Detective;
+
+/**
+ * @author Sanne Grinovero
+ */
+public class UpdateActivity extends AbstractActivity {
+
+ UpdateActivity(SessionFactory sf, CountDownLatch startSignal) {
+ super(sf, startSignal);
+ }
+
+ @Override
+ protected void doAction(FullTextSession s, int jobSeed) {
+ FullTextQuery q = getQuery( "John", s, Detective.class );
+ List list = q.setMaxResults( 1 ).list();
+ for ( Object o : list){
+ Detective detective = (Detective) o;
+ detective.setPhysicalDescription( "old" );
+ }
+ }
+
+}
16 years, 7 months
Hibernate SVN: r14764 - annotations/trunk/src/test/org/hibernate/test/annotations/manytomany.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2008-06-12 09:41:16 -0400 (Thu, 12 Jun 2008)
New Revision: 14764
Added:
annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/Contractor.java
Modified:
annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/Employee.java
annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/Employer.java
annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/ManyToManyTest.java
Log:
ANN-625:
- Added test case. Needs to be run against other db than HSQL. Produced query is also dodgy in HSQL, but seems not to cause a problem.
Added: annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/Contractor.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/Contractor.java (rev 0)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/Contractor.java 2008-06-12 13:41:16 UTC (rev 14764)
@@ -0,0 +1,26 @@
+//$Id: Employee.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.test.annotations.manytomany;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+
+/**
+ * Employee in an Employer-Employee relationship
+ *
+ * @author Emmanuel Bernard
+ */
+@Entity
+@SuppressWarnings("serial")
+public class Contractor extends Employee implements Serializable {
+
+ private float hourlyRate;
+
+ public float getHourlyRate() {
+ return hourlyRate;
+ }
+
+ public void setHourlyRate(float hourlyRate) {
+ this.hourlyRate = hourlyRate;
+ }
+}
Property changes on: annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/Contractor.java
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/Employee.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/Employee.java 2008-06-12 00:16:50 UTC (rev 14763)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/Employee.java 2008-06-12 13:41:16 UTC (rev 14764)
@@ -17,7 +17,8 @@
*
* @author Emmanuel Bernard
*/
-@Entity()
+@Entity
+@SuppressWarnings("serial")
public class Employee implements Serializable {
private Integer id;
private Collection<Employer> employers;
Modified: annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/Employer.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/Employer.java 2008-06-12 00:16:50 UTC (rev 14763)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/Employer.java 2008-06-12 13:41:16 UTC (rev 14764)
@@ -3,6 +3,8 @@
import java.io.Serializable;
import java.util.Collection;
+import java.util.List;
+
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
@@ -22,11 +24,32 @@
*/
@Entity()
@Table(name="`Employer`")
+@SuppressWarnings({"serial", "unchecked"})
public class Employer implements Serializable {
private Integer id;
private Collection employees;
+ private List contractors;
@ManyToMany(
+ targetEntity = org.hibernate.test.annotations.manytomany.Contractor.class,
+ cascade = {CascadeType.PERSIST, CascadeType.MERGE}
+ )
+ @JoinTable(
+ name = "EMPLOYER_CONTRACTOR",
+ joinColumns = {@JoinColumn(name = "EMPLOYER_ID")},
+ inverseJoinColumns = {@JoinColumn(name = "CONTRACTOR_ID")}
+ )
+ @Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE)
+ @OrderBy("name desc")
+ public List getContractors() {
+ return contractors;
+ }
+
+ public void setContractors(List contractors) {
+ this.contractors = contractors;
+ }
+
+ @ManyToMany(
targetEntity = org.hibernate.test.annotations.manytomany.Employee.class,
cascade = {CascadeType.PERSIST, CascadeType.MERGE}
)
@@ -36,7 +59,7 @@
inverseJoinColumns = {@JoinColumn(name = "EMPEE_ID")}
)
@Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE)
- @OrderBy("name")
+ @OrderBy("name asc")
public Collection getEmployees() {
return employees;
}
Modified: annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/ManyToManyTest.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/ManyToManyTest.java 2008-06-12 00:16:50 UTC (rev 14763)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/manytomany/ManyToManyTest.java 2008-06-12 13:41:16 UTC (rev 14764)
@@ -7,6 +7,7 @@
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
import org.hibernate.Hibernate;
@@ -20,6 +21,7 @@
*
* @author Emmanuel Bernard
*/
+@SuppressWarnings("unchecked")
public class ManyToManyTest extends TestCase {
public ManyToManyTest(String x) {
@@ -218,44 +220,115 @@
s.close();
}
- public void testOrderBy() throws Exception {
+ public void testOrderByEmployee() throws Exception {
Session s;
Transaction tx;
s = openSession();
tx = s.beginTransaction();
- Employer er = new Employer();
- Employee ee = new Employee();
- ee.setName( "Emmanuel" );
- Employee ee2 = new Employee();
- ee2.setName( "Alice" );
- s.persist( ee );
- s.persist( ee2 );
+ Employer employer = new Employer();
+ Employee employee1 = new Employee();
+ employee1.setName( "Emmanuel" );
+ Employee employee2 = new Employee();
+ employee2.setName( "Alice" );
+ s.persist( employee1 );
+ s.persist( employee2 );
Set erColl = new HashSet();
Collection eeColl = new ArrayList();
Collection eeColl2 = new ArrayList();
- erColl.add( ee );
- erColl.add( ee2 );
- eeColl.add( er );
- eeColl2.add( er );
- er.setEmployees( erColl );
- ee.setEmployers( eeColl );
- ee2.setEmployers( eeColl2 );
- //s.persist(ee);
+ erColl.add( employee1 );
+ erColl.add( employee2 );
+ eeColl.add( employer );
+ eeColl2.add( employer );
+ employer.setEmployees( erColl );
+ employee1.setEmployers( eeColl );
+ employee2.setEmployers( eeColl2 );
s.flush();
s.clear();
- er = (Employer) s.get( Employer.class, er.getId() );
- assertNotNull( er );
- assertNotNull( er.getEmployees() );
- assertEquals( 2, er.getEmployees().size() );
- Employee eeFromDb = (Employee) er.getEmployees().iterator().next();
- assertEquals( ee2.getName(), eeFromDb.getName() );
+ employer = (Employer) s.get( Employer.class, employer.getId() );
+ assertNotNull( employer );
+ assertNotNull( employer.getEmployees() );
+ assertEquals( 2, employer.getEmployees().size() );
+ Employee eeFromDb = (Employee) employer.getEmployees().iterator().next();
+ assertEquals( employee2.getName(), eeFromDb.getName() );
tx.rollback();
s.close();
}
+
+ /**
+ * ANN-625
+ *
+ * @throws Exception in case the test fails.
+ *
+ * This fails test fails for other databases (except HSQL) due to missing alias in order by clause:
+ *
+ * select
+ * contractor0_.EMPLOYER_ID as EMPLOYER1_1_,
+ * contractor0_.CONTRACTOR_ID as CONTRACTOR2_1_,
+ * contractor1_.id as id2_0_,
+ * contractor1_.fld_name as fld3_2_0_,
+ * contractor1_.hourlyRate as hourlyRate2_0_
+ * from
+ * EMPLOYER_CONTRACTOR contractor0_
+ * left outer join
+ * Employee contractor1_
+ * on contractor0_.CONTRACTOR_ID=contractor1_.id
+ * where
+ * contractor0_.EMPLOYER_ID=?
+ * order by
+ * Employee.fld_name desc
+ *
+ *
+ */
+ public void testOrderByContractor() throws Exception {
+
+ Session s;
+ Transaction tx;
+ s = openSession();
+ tx = s.beginTransaction();
+
+ // create some test entities
+ Employer employer = new Employer();
+ Contractor contractor1 = new Contractor();
+ contractor1.setName( "Emmanuel" );
+ contractor1.setHourlyRate(100.0f);
+ Contractor contractor2 = new Contractor();
+ contractor2.setName( "Hardy" );
+ contractor2.setHourlyRate(99.99f);
+ s.persist( contractor1 );
+ s.persist( contractor2 );
+
+ // add contractors to employer
+ List setOfContractors = new ArrayList();
+ setOfContractors.add( contractor1 );
+ setOfContractors.add( contractor2 );
+ employer.setContractors( setOfContractors );
+
+ // add employer to contractors
+ Collection employerListContractor1 = new ArrayList();
+ employerListContractor1.add( employer );
+ contractor1.setEmployers( employerListContractor1 );
+
+ Collection employerListContractor2 = new ArrayList();
+ employerListContractor2.add( employer );
+ contractor2.setEmployers( employerListContractor2 );
+ s.flush();
+ s.clear();
+
+ // assertions
+ employer = (Employer) s.get( Employer.class, employer.getId() );
+ assertNotNull( employer );
+ assertNotNull( employer.getContractors() );
+ assertEquals( 2, employer.getContractors().size() );
+ Contractor firstContractorFromDb = (Contractor) employer.getContractors().iterator().next();
+ assertEquals( contractor2.getName(), firstContractorFromDb.getName() );
+ tx.rollback();
+ s.close();
+ }
+
public void testRemoveInBetween() throws Exception {
Session s;
Transaction tx;
@@ -575,6 +648,7 @@
Friend.class,
Employer.class,
Employee.class,
+ Contractor.class,
Man.class,
Woman.class,
Store.class,
@@ -590,7 +664,6 @@
InspectorPrefixes.class,
BuildingCompany.class,
Building.class
-
};
}
16 years, 7 months
Hibernate SVN: r14763 - in core/trunk/documentation/releasenotes/src/main/docbook/en-US: images and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: bsatguna
Date: 2008-06-11 20:16:50 -0400 (Wed, 11 Jun 2008)
New Revision: 14763
Added:
core/trunk/documentation/releasenotes/src/main/docbook/en-US/images/hibernate_logo_a.png
Modified:
core/trunk/documentation/releasenotes/src/main/docbook/en-US/Article_Info.xml
core/trunk/documentation/releasenotes/src/main/docbook/en-US/Author_Group.xml
core/trunk/documentation/releasenotes/src/main/docbook/en-US/Book_Info.xml
core/trunk/documentation/releasenotes/src/main/docbook/en-US/Release_Notes.ent
core/trunk/documentation/releasenotes/src/main/docbook/en-US/Release_Notes.xml
core/trunk/documentation/releasenotes/src/main/docbook/en-US/Revision_History.xml
Log:
Preparing release notes for Hibernate 3.3.0.CR2
Modified: core/trunk/documentation/releasenotes/src/main/docbook/en-US/Article_Info.xml
===================================================================
--- core/trunk/documentation/releasenotes/src/main/docbook/en-US/Article_Info.xml 2008-06-11 15:26:07 UTC (rev 14762)
+++ core/trunk/documentation/releasenotes/src/main/docbook/en-US/Article_Info.xml 2008-06-12 00:16:50 UTC (rev 14763)
@@ -1,7 +1,29 @@
<?xml version='1.0'?>
<!DOCTYPE articleinfo PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
]>
-
+<!--
+ ~ Hibernate, Relational Persistence for Idiomatic Java
+ ~
+ ~ Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+ ~
+ ~ 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
+ -->
<articleinfo id="Release_Notes-Hibernate-Standalone">
<title>Hibernate</title>
<subtitle>Release Notes</subtitle>
@@ -9,12 +31,12 @@
<productnumber>1</productnumber>
<abstract><para>This document provides the release notes for Hibernate &VERSION;.</para>
</abstract>
- <corpauthor><inlinemediaobject>
+ <!--<corpauthor><inlinemediaobject>
<imageobject>
<imagedata fileref="Common_Content/images/hibernate_logo_a.png" />
</imageobject>
</inlinemediaobject>
- </corpauthor><copyright>
+ </corpauthor>--><copyright>
<year>&YEAR;</year>
<holder>&HOLDER;</holder>
</copyright>
Modified: core/trunk/documentation/releasenotes/src/main/docbook/en-US/Author_Group.xml
===================================================================
--- core/trunk/documentation/releasenotes/src/main/docbook/en-US/Author_Group.xml 2008-06-11 15:26:07 UTC (rev 14762)
+++ core/trunk/documentation/releasenotes/src/main/docbook/en-US/Author_Group.xml 2008-06-12 00:16:50 UTC (rev 14763)
@@ -1,7 +1,29 @@
<?xml version='1.0'?>
<!DOCTYPE authorgroup PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
]>
-
+<!--
+ ~ Hibernate, Relational Persistence for Idiomatic Java
+ ~
+ ~ Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+ ~
+ ~ 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
+ -->
<authorgroup>
<corpauthor>Redhat Documentation Group</corpauthor>
<author>
Modified: core/trunk/documentation/releasenotes/src/main/docbook/en-US/Book_Info.xml
===================================================================
--- core/trunk/documentation/releasenotes/src/main/docbook/en-US/Book_Info.xml 2008-06-11 15:26:07 UTC (rev 14762)
+++ core/trunk/documentation/releasenotes/src/main/docbook/en-US/Book_Info.xml 2008-06-12 00:16:50 UTC (rev 14763)
@@ -1,7 +1,29 @@
<?xml version='1.0'?>
<!DOCTYPE articleinfo PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
]>
-
+<!--
+ ~ Hibernate, Relational Persistence for Idiomatic Java
+ ~
+ ~ Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+ ~
+ ~ 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
+ -->
<articleinfo id="Release_Notes-Product_Name_and_Version">
<title>Hibernate</title>
<subtitle>Release Notes</subtitle>
Modified: core/trunk/documentation/releasenotes/src/main/docbook/en-US/Release_Notes.ent
===================================================================
--- core/trunk/documentation/releasenotes/src/main/docbook/en-US/Release_Notes.ent 2008-06-11 15:26:07 UTC (rev 14762)
+++ core/trunk/documentation/releasenotes/src/main/docbook/en-US/Release_Notes.ent 2008-06-12 00:16:50 UTC (rev 14763)
@@ -1,4 +1,4 @@
-<!ENTITY PRODUCT "Hibernate Standalone">
+<!ENTITY PRODUCT "Hibernate">
<!ENTITY BOOKID "Release_Notes">
<!ENTITY VERSION "3.3.0.CR2">
<!ENTITY YEAR "2008">
Modified: core/trunk/documentation/releasenotes/src/main/docbook/en-US/Release_Notes.xml
===================================================================
--- core/trunk/documentation/releasenotes/src/main/docbook/en-US/Release_Notes.xml 2008-06-11 15:26:07 UTC (rev 14762)
+++ core/trunk/documentation/releasenotes/src/main/docbook/en-US/Release_Notes.xml 2008-06-12 00:16:50 UTC (rev 14763)
@@ -121,17 +121,17 @@
The unit tests use the settings in <filename>etc/hibernate.properties</filename>. The value for <property>hibernate.jdbc.batch_versioned_data</property> is set to <parameter>true</parameter> in that file. If the unit tests involving optimistic locking fail, then the appropriate value for this flag is <parameter>false</parameter>. Some versions of Oracle JDBC do not support returning update counts for each command in a batch, so it is particularly important to test using the same version of JDBC as will be used in production.
</para>
- <section id="Expected_JUnit_Failures_And_Tests">
+ <!--<section id="Expected_JUnit_Failures_And_Tests">
<title>Expected failures and tests</title>
<para>
The following unit tests are expected to fail:
</para>
- </section>
+ </section>-->
</section>
- <section id="Issues" xreflabel="Issues">
+ <section id="Issues">
<title>Issues</title>
<section id="Issue_Type_Bugs">
@@ -169,53 +169,69 @@
</formalpara>
<formalpara>
<title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3282">[HHH-3282]</ulink> - <literal>DB2Dialect</literal> should report <literal>supportsLobValueChangePropogation()</literal> as false</title>
- <para>The above change has been incorporated.</para>
+ <para>This change has been incorporated.</para>
</formalpara>
</section>
<section id="Issue_Type_Improvement">
<title>Improvement</title>
- <formalpara><title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-1786">[HHH-1786]</ulink> JTASessionContext.CleanupSynch does not remove sessions from currentSessionMap</title><para></para></formalpara>
+ <formalpara>
+ <title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-1786">[HHH-1786] - </ulink> JTASessionContext.CleanupSynch does not remove sessions from currentSessionMap</title><para></para></formalpara>
- <formalpara><title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-2060">[HHH-2060]</ulink> - To be able to use <literal><generator></literal> with <composite-id></title>
+ <formalpara>
+ <title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-2060">[HHH-2060]</ulink> - To be able to use <literal><generator></literal> with <composite-id></title>
<para>Functionality to use <literal><generator></literal> has been incorporated.</para></formalpara>
- <formalpara><title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-2506">[HHH-2506]</ulink> - Make javassist the default ByteCodeProvider</title>
- <para>This is now incorporated into this release.</para></formalpara>
+ <formalpara>
+ <title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-2506">[HHH-2506]</ulink> - Make <literal>javassist</literal> the default <literal>ByteCodeProvider</literal></title>
+ <para>This has been incorporated into this release.</para></formalpara>
- <formalpara><title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-2875">[HHH-2875]</ulink> - repackage cglib/asm under org.hibernate namespace</title>
+ <formalpara>
+ <title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-2875">[HHH-2875]</ulink> - repackage cglib/asm under org.hibernate namespace</title>
+ <para>This issue is also associated with the above issue.</para></formalpara>
+
+ <formalpara>
+ <title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3229">[HHH-3229]</ulink> - Make cascade rules more transparent/explicit/deterministic</title>
<para></para></formalpara>
- <formalpara><title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3229">[HHH-3229]</ulink> - Make cascade rules more transparent/explicit/deterministic</title><para></para></formalpara>
+ <formalpara>
+ <title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3269">[HHH-3269]</ulink> - upgrade to jDocBook plugin version 2.1.1</title>
+ <para>Upgrade for jDocBook plugin version from 2.1.0 to 2.1.1 has been enabled for this release</para></formalpara>
- <formalpara><title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3269">[HHH-3269]</ulink> - upgrade to jDocBook plugin version 2.1.1</title><para></para></formalpara>
+ <formalpara>
+ <title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3276">[HHH-3276]</ulink> - review proposed new doc styling</title>
+ <para>Hibernate going to have a new look soon!</para></formalpara>
- <formalpara><title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3276">[HHH-3276]</ulink> - review proposed new doc styling</title><para></para></formalpara>
+ <formalpara>
+ <title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3283">[HHH-3283]</ulink> - protect BulkManipulationTest#testInsertWithGeneratedTimestampVersion where Dialect#supportsParametersInInsertSelect == false</title>
+ <para></para></formalpara>
- <formalpara><title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3283">[HHH-3283]</ulink> - protect BulkManipulationTest#testInsertWithGeneratedTimestampVersion where Dialect#supportsParametersInInsertSelect == false</title><para></para></formalpara>
+ <formalpara>
+ <title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3286">[HHH-3286]</ulink> - Move ACTION_PERSIST_SKIPLAZY from HEM to Core in CascadingAction</title>
+ <para></para></formalpara>
- <formalpara><title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3286">[HHH-3286]</ulink> - Move ACTION_PERSIST_SKIPLAZY from HEM to Core in CascadingAction</title><para></para></formalpara>
-
</section>
<section id="Issue_Type_New_Feature"><title>New Feature</title>
<formalpara>
- <title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3279">[HHH-3279]</ulink> - create series of maven plugins offering functionality of the ant tools</title><para></para>
+ <title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3279">[HHH-3279]</ulink> - create series of maven plugins offering functionality of the ant tools</title>
+ <para></para>
</formalpara>
</section>
<section id="Issue_Type_Task"><title>Task</title>
<formalpara>
- <title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3270">[HHH-3270]</ulink> - follow up on documentation license questions</title><para></para>
+ <title><ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3270">[HHH-3270]</ulink> - follow up on documentation license questions</title>
+ <para>License information has been modified to reflect LGPL licensing. </para>
</formalpara>
</section>
</section>
- <section id="Documentation" xreflabel="documentation">
+ <section id="Documentation">
<title>Documentation</title>
<itemizedlist>
<listitem>
Modified: core/trunk/documentation/releasenotes/src/main/docbook/en-US/Revision_History.xml
===================================================================
--- core/trunk/documentation/releasenotes/src/main/docbook/en-US/Revision_History.xml 2008-06-11 15:26:07 UTC (rev 14762)
+++ core/trunk/documentation/releasenotes/src/main/docbook/en-US/Revision_History.xml 2008-06-12 00:16:50 UTC (rev 14763)
@@ -1,7 +1,29 @@
<?xml version='1.0'?>
<!DOCTYPE revhistory PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
]>
-
+<!--
+ ~ Hibernate, Relational Persistence for Idiomatic Java
+ ~
+ ~ Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+ ~
+ ~ 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
+ -->
<revhistory>
<revision>
<revnumber>1.0</revnumber>
Added: core/trunk/documentation/releasenotes/src/main/docbook/en-US/images/hibernate_logo_a.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/documentation/releasenotes/src/main/docbook/en-US/images/hibernate_logo_a.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
16 years, 7 months
Hibernate SVN: r14762 - search/branches/jboss_cache_integration.
by hibernate-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-06-11 11:26:07 -0400 (Wed, 11 Jun 2008)
New Revision: 14762
Modified:
search/branches/jboss_cache_integration/build.xml
search/branches/jboss_cache_integration/common-build.xml
Log:
Updated ant scripts
Modified: search/branches/jboss_cache_integration/build.xml
===================================================================
--- search/branches/jboss_cache_integration/build.xml 2008-06-11 13:51:06 UTC (rev 14761)
+++ search/branches/jboss_cache_integration/build.xml 2008-06-11 15:26:07 UTC (rev 14762)
@@ -17,7 +17,7 @@
<!-- Name of project and version, used to create filenames -->
<property name="Name" value="Hibernate Search"/>
<property name="name" value="hibernate-search"/>
- <property name="version" value="3.1.0.Beta1"/>
+ <property name="version" value="3.1.0.NAVIN-SNAPSHOT"/>
<property name="javadoc.packagenames" value="org.hibernate.search.*"/>
<property name="copy.test" value="true"/>
<property name="javac.source" value="1.5"/>
Modified: search/branches/jboss_cache_integration/common-build.xml
===================================================================
--- search/branches/jboss_cache_integration/common-build.xml 2008-06-11 13:51:06 UTC (rev 14761)
+++ search/branches/jboss_cache_integration/common-build.xml 2008-06-11 15:26:07 UTC (rev 14762)
@@ -457,7 +457,7 @@
</target>
<!-- maven deploy: to be used by the subbuild and delcare deps on jar -->
- <target name="deploy" depends="jar">
+ <target name="install" depends="jar">
<fail unless="offline.repository.jboss.org" message="offline.repository.jboss.org must be defined"/>
<jar jarfile="${src.jar}" basedir="${src.dir}">
<include name="**/*.java" />
@@ -466,11 +466,12 @@
</jar>
<artifact:pom id="maven.project" file="${pom.file}" />
-
- <artifact:install file="${jar.file.name}">
+ <echo>GENERATED POM</echo>
+ <artifact:install file="${jar.file.name}" overwrite="true">
<pom refid="maven.project"/>
</artifact:install>
-
+ </target>
+ <target name="deploy" depends="install">
<artifact:deploy file="${jar.file.name}">
<pom refid="maven.project" />
<remoteRepository refId="offline.repository.jboss.org">
16 years, 7 months
Hibernate SVN: r14761 - in annotations/trunk/src: java/org/hibernate/cfg/annotations and 2 other directories.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2008-06-11 09:51:06 -0400 (Wed, 11 Jun 2008)
New Revision: 14761
Added:
annotations/trunk/src/test/org/hibernate/test/annotations/id/JoinColumnOverrideTest.java
annotations/trunk/src/test/org/hibernate/test/annotations/id/entities/TwinkleToes.java
Modified:
annotations/trunk/src/java/org/hibernate/cfg/AnnotationBinder.java
annotations/trunk/src/java/org/hibernate/cfg/Ejb3JoinColumn.java
annotations/trunk/src/java/org/hibernate/cfg/annotations/TableBinder.java
annotations/trunk/src/test/org/hibernate/test/annotations/id/IdTest.java
annotations/trunk/src/test/org/hibernate/test/annotations/id/entities/Bunny.java
annotations/trunk/src/test/org/hibernate/test/annotations/id/entities/PointyTooth.java
Log:
ANN-748
- Added new entity (TwinkleToe) in order to test one ManyToOne with JoinColumn and one without
- Split test into seperate class for easier debugging
- changed overrideSqlTypeIfNecessary() to overrideFromReferencedColumnIfNecessary() in Ejb3JoinColumn and made sure that not only sqlType gets taken care of, but also length, precision and scale. Updated TableBinder accordingly.
Modified: annotations/trunk/src/java/org/hibernate/cfg/AnnotationBinder.java
===================================================================
--- annotations/trunk/src/java/org/hibernate/cfg/AnnotationBinder.java 2008-06-11 07:33:15 UTC (rev 14760)
+++ annotations/trunk/src/java/org/hibernate/cfg/AnnotationBinder.java 2008-06-11 13:51:06 UTC (rev 14761)
@@ -145,6 +145,7 @@
*
* @author Emmanuel Bernard
*/
+@SuppressWarnings("unchecked")
public final class AnnotationBinder {
/*
Modified: annotations/trunk/src/java/org/hibernate/cfg/Ejb3JoinColumn.java
===================================================================
--- annotations/trunk/src/java/org/hibernate/cfg/Ejb3JoinColumn.java 2008-06-11 07:33:15 UTC (rev 14760)
+++ annotations/trunk/src/java/org/hibernate/cfg/Ejb3JoinColumn.java 2008-06-11 13:51:06 UTC (rev 14761)
@@ -24,6 +24,7 @@
*
* @author Emmanuel Bernard
*/
+@SuppressWarnings("unchecked")
public class Ejb3JoinColumn extends Ejb3Column {
/**
* property name repated to this column
@@ -36,7 +37,7 @@
private String mappedByTableName;
private String mappedByEntityName;
- //FIXME hacky solution to get the information at proeprty ref resolution
+ //FIXME hacky solution to get the information at property ref resolution
public String getManyToManyOwnerSideEntityName() {
return manyToManyOwnerSideEntityName;
}
@@ -444,11 +445,24 @@
}
}
- public void overrideSqlTypeIfNecessary(org.hibernate.mapping.Column column) {
+ /**
+ * Called to apply column definitions from the referenced FK column to this column.
+ *
+ * @param column the referenced column.
+ */
+ public void overrideFromReferencedColumnIfNecessary(org.hibernate.mapping.Column column) {
+
+ // columnDefinition can also be specified using @JoinColumn, hence we have to check
+ // whether it is set or not
if ( StringHelper.isEmpty( sqlType ) ) {
sqlType = column.getSqlType();
if ( getMappingColumn() != null ) getMappingColumn().setSqlType( sqlType );
}
+
+ // these properties can only be applied on the referenced column - we can just take them over
+ getMappingColumn().setLength(column.getLength());
+ getMappingColumn().setPrecision(column.getPrecision());
+ getMappingColumn().setScale(column.getScale());
}
@Override
Modified: annotations/trunk/src/java/org/hibernate/cfg/annotations/TableBinder.java
===================================================================
--- annotations/trunk/src/java/org/hibernate/cfg/annotations/TableBinder.java 2008-06-11 07:33:15 UTC (rev 14760)
+++ annotations/trunk/src/java/org/hibernate/cfg/annotations/TableBinder.java 2008-06-11 13:51:06 UTC (rev 14761)
@@ -32,6 +32,7 @@
*
* @author Emmanuel Bernard
*/
+@SuppressWarnings("unchecked")
public class TableBinder {
//TODO move it to a getter/setter strategy
private static Logger log = LoggerFactory.getLogger( TableBinder.class );
@@ -201,7 +202,7 @@
}
while ( mappedByColumns.hasNext() ) {
Column column = (Column) mappedByColumns.next();
- columns[0].overrideSqlTypeIfNecessary( column );
+ columns[0].overrideFromReferencedColumnIfNecessary( column );
columns[0].linkValueUsingAColumnCopy( column, value );
}
}
@@ -219,7 +220,7 @@
}
while ( idColumns.hasNext() ) {
Column column = (Column) idColumns.next();
- columns[0].overrideSqlTypeIfNecessary( column );
+ columns[0].overrideFromReferencedColumnIfNecessary( column );
columns[0].linkValueUsingDefaultColumnNaming( column, referencedEntity, value );
}
}
@@ -306,7 +307,7 @@
else {
joinCol.linkWithValue( value );
}
- joinCol.overrideSqlTypeIfNecessary( col );
+ joinCol.overrideFromReferencedColumnIfNecessary( col );
match = true;
break;
}
@@ -329,17 +330,17 @@
private static void linkJoinColumnWithValueOverridingNameIfImplicit(
PersistentClass referencedEntity, Iterator columnIterator, Ejb3JoinColumn[] columns, SimpleValue value
- ) {
+ ) {
for (Ejb3JoinColumn joinCol : columns) {
- Column synthCol = (Column) columnIterator.next();
+ Column synthCol = (Column) columnIterator.next();
if ( joinCol.isNameDeferred() ) {
//this has to be the default value
joinCol.linkValueUsingDefaultColumnNaming( synthCol, referencedEntity, value );
}
else {
joinCol.linkWithValue( value );
+ joinCol.overrideFromReferencedColumnIfNecessary( synthCol );
}
- joinCol.overrideSqlTypeIfNecessary( synthCol );
}
}
Modified: annotations/trunk/src/test/org/hibernate/test/annotations/id/IdTest.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/id/IdTest.java 2008-06-11 07:33:15 UTC (rev 14760)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/id/IdTest.java 2008-06-11 13:51:06 UTC (rev 14761)
@@ -3,13 +3,10 @@
import org.hibernate.Session;
import org.hibernate.Transaction;
-import org.hibernate.cfg.AnnotationConfiguration;
-import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.mapping.Column;
import org.hibernate.test.annotations.TestCase;
import org.hibernate.test.annotations.id.entities.Ball;
import org.hibernate.test.annotations.id.entities.BreakDance;
-import org.hibernate.test.annotations.id.entities.Bunny;
import org.hibernate.test.annotations.id.entities.Computer;
import org.hibernate.test.annotations.id.entities.Department;
import org.hibernate.test.annotations.id.entities.Dog;
@@ -21,13 +18,10 @@
import org.hibernate.test.annotations.id.entities.Home;
import org.hibernate.test.annotations.id.entities.Monkey;
import org.hibernate.test.annotations.id.entities.Phone;
-import org.hibernate.test.annotations.id.entities.PointyTooth;
import org.hibernate.test.annotations.id.entities.Shoe;
import org.hibernate.test.annotations.id.entities.SoundSystem;
import org.hibernate.test.annotations.id.entities.Store;
import org.hibernate.test.annotations.id.entities.Tree;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* @author Emmanuel Bernard
@@ -36,8 +30,6 @@
public class IdTest extends TestCase {
// FIXME split Sequence and Id tests to explicit the run failure on Oracle etc
- private Logger log = LoggerFactory.getLogger(IdTest.class);
-
public IdTest(String x) {
super(x);
}
@@ -289,43 +281,6 @@
}
/**
- * See JIRA bug ANN-748.
- */
- public void testBlownPrecision() throws Exception {
-
- try {
- AnnotationConfiguration config = new AnnotationConfiguration();
- config.addAnnotatedClass(Bunny.class);
- config.addAnnotatedClass(PointyTooth.class);
- config.buildSessionFactory();
- String[] schema = config
- .generateSchemaCreationScript(new SQLServerDialect());
- for (String s : schema) {
- log.debug(s);
- }
- String expectedMappingTableSql = "create table PointyTooth (id numeric(128,0) not null, " +
- "bunny_id numeric(128,0) null, primary key (id))";
- assertEquals("Wrong SQL", expectedMappingTableSql, schema[1]);
- } catch (Exception e) {
- fail(e.getMessage());
- }
-
-
-// Session s = openSession();
-// Transaction tx = s.beginTransaction();
-// Bunny bunny = new Bunny();
-// PointyTooth tooth = new PointyTooth();
-// Set<PointyTooth> teeth = new HashSet<PointyTooth>();
-// teeth.add(tooth);
-// bunny.setTeeth(teeth);
-// tooth.setBunny(bunny);
-// s.persist(bunny);
-// s.flush();
-// tx.rollback();
-// s.close();
- }
-
- /**
* @see org.hibernate.test.annotations.TestCase#getMappings()
*/
protected Class[] getMappings() {
@@ -333,7 +288,7 @@
Department.class, Dog.class, Computer.class, Home.class,
Phone.class, Tree.class, FirTree.class, Footballer.class,
SoundSystem.class, Furniture.class, GoalKeeper.class,
- BreakDance.class, Monkey.class, Bunny.class, PointyTooth.class };
+ BreakDance.class, Monkey.class};
}
/**
Added: annotations/trunk/src/test/org/hibernate/test/annotations/id/JoinColumnOverrideTest.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/id/JoinColumnOverrideTest.java (rev 0)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/id/JoinColumnOverrideTest.java 2008-06-11 13:51:06 UTC (rev 14761)
@@ -0,0 +1,64 @@
+//$Id$
+package org.hibernate.test.annotations.id;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.hibernate.cfg.AnnotationConfiguration;
+import org.hibernate.dialect.SQLServerDialect;
+import org.hibernate.test.annotations.TestCase;
+import org.hibernate.test.annotations.id.entities.Bunny;
+import org.hibernate.test.annotations.id.entities.PointyTooth;
+import org.hibernate.test.annotations.id.entities.TwinkleToes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tests for JIRA issue ANN-748.
+ *
+ * @author Hardy Ferentschik
+ */
+@SuppressWarnings("unchecked")
+public class JoinColumnOverrideTest extends TestCase {
+
+ private Logger log = LoggerFactory.getLogger(JoinColumnOverrideTest.class);
+
+ public JoinColumnOverrideTest(String x) {
+ super(x);
+ }
+
+ public void testBlownPrecision() throws Exception {
+
+ try {
+ AnnotationConfiguration config = new AnnotationConfiguration();
+ config.addAnnotatedClass(Bunny.class);
+ config.addAnnotatedClass(PointyTooth.class);
+ config.addAnnotatedClass(TwinkleToes.class);
+ config.buildSessionFactory();
+ String[] schema = config
+ .generateSchemaCreationScript(new SQLServerDialect());
+ for (String s : schema) {
+ log.debug(s);
+ }
+ String expectedSqlPointyTooth = "create table PointyTooth (id numeric(128,0) not null, " +
+ "bunny_id numeric(128,0) null, primary key (id))";
+ assertEquals("Wrong SQL", expectedSqlPointyTooth, schema[1]);
+
+ String expectedSqlTwinkleToes = "create table TwinkleToes (id numeric(128,0) not null, " +
+ "bunny_id numeric(128,0) null, primary key (id))";
+ assertEquals("Wrong SQL", expectedSqlTwinkleToes, schema[2]);
+ } catch (Exception e) {
+ StringWriter writer = new StringWriter();
+ e.printStackTrace(new PrintWriter(writer));
+ log.debug(writer.toString());
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * @see org.hibernate.test.annotations.TestCase#getMappings()
+ */
+ protected Class[] getMappings() {
+ return new Class[] {};
+ }
+}
Property changes on: annotations/trunk/src/test/org/hibernate/test/annotations/id/JoinColumnOverrideTest.java
___________________________________________________________________
Name: svn:keywords
+ Id
Modified: annotations/trunk/src/test/org/hibernate/test/annotations/id/entities/Bunny.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/id/entities/Bunny.java 2008-06-11 07:33:15 UTC (rev 14760)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/id/entities/Bunny.java 2008-06-11 13:51:06 UTC (rev 14761)
@@ -32,8 +32,15 @@
@OneToMany(mappedBy = "bunny", cascade = { CascadeType.PERSIST })
Set<PointyTooth> teeth;
+
+ @OneToMany(mappedBy = "bunny", cascade = { CascadeType.PERSIST })
+ Set<TwinkleToes> toes;
public void setTeeth(Set<PointyTooth> teeth) {
this.teeth = teeth;
}
+
+ public BigInteger getId() {
+ return id;
+ }
}
Modified: annotations/trunk/src/test/org/hibernate/test/annotations/id/entities/PointyTooth.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/id/entities/PointyTooth.java 2008-06-11 07:33:15 UTC (rev 14760)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/id/entities/PointyTooth.java 2008-06-11 13:51:06 UTC (rev 14761)
@@ -31,11 +31,14 @@
private BigInteger id;
@ManyToOne
- // comment out the below line and the test will pass
- //@JoinColumn(name = "bugs_bunny_id")
+ @JoinColumn(name = "bunny_id")
Bunny bunny;
public void setBunny(Bunny bunny) {
this.bunny = bunny;
}
+
+ public BigInteger getId() {
+ return id;
+ }
}
Added: annotations/trunk/src/test/org/hibernate/test/annotations/id/entities/TwinkleToes.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/id/entities/TwinkleToes.java (rev 0)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/id/entities/TwinkleToes.java 2008-06-11 13:51:06 UTC (rev 14761)
@@ -0,0 +1,42 @@
+//$Id$
+package org.hibernate.test.annotations.id.entities;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+
+import org.hibernate.annotations.GenericGenerator;
+
+/**
+ * Blown precision on related entity when @JoinColumn is used.
+ * Does not cause an issue on HyperSonic, but replicates nicely on PGSQL.
+ *
+ * @see ANN-748
+ * @author Andrew C. Oliver andyspam(a)osintegrators.com
+ */
+@Entity
+@SuppressWarnings("serial")
+public class TwinkleToes implements Serializable {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "java5_uuid")
+ @GenericGenerator(name = "java5_uuid", strategy = "org.hibernate.test.annotations.id.UUIDGenerator")
+ @Column(name = "id", precision = 128, scale = 0)
+ private BigInteger id;
+
+ @ManyToOne
+ Bunny bunny;
+
+ public void setBunny(Bunny bunny) {
+ this.bunny = bunny;
+ }
+
+ public BigInteger getId() {
+ return id;
+ }
+}
Property changes on: annotations/trunk/src/test/org/hibernate/test/annotations/id/entities/TwinkleToes.java
___________________________________________________________________
Name: svn:keywords
+ Id
16 years, 7 months