After several hours we were able to create a test case. Here is all data that you need.
{code:title=ehcache.xml} <ehcache updateCheck="false" monitoring="on" dynamicConfig="false" name="TestCache"> <defaultCache maxEntriesLocalHeap="2"/> </ehcache> {code}
{code:title=hibernate.xml} <property name="hibernate.cache.use_second_level_cache">true</property> <property name="net.sf.ehcache.configurationResourceName">ehcache.xml</property> <property name="hibernate.default_batch_fetch_size">0</property> <property name="hibernate.cache.provider_class">org.hibernate.cache.ehcache.EhCacheProvider</property> <property name="hibernate.cache.use_structured_entries">true</property> <property name="hibernate.cache.use_query_cache">true</property> <property name="hibernate.cache.use_minimal_puts">true</property> <property name="hibernate.max_fetch_depth">1</property> <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property> {code}
{code:title=create.sql} drop table if exists EhCacheDeadLockTest; create table EhCacheDeadLockTest (`id` int not null,`value` varchar(255) not null, primary key (`id`) ) engine=InnoDB; insert into EhCacheDeadLockTest values (1,'1'); insert into EhCacheDeadLockTest values (2,'2'); insert into EhCacheDeadLockTest values (10010003,'3'); insert into EhCacheDeadLockTest values (10010004,'4'); {code}
{code:title=EhCacheDeadLockEntity.java|borderStyle=solid} import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table;
@Entity @Table( name = "EhCacheDeadLockTest" ) @Cache( usage = CacheConcurrencyStrategy.READ_WRITE ) public class EhCacheDeadLockEntity { @Id @Column( name = "id" ) private int id;
@Column( name = "value" ) private String value;
public int getId() { return id; }
public void setId( int id ) { this.id = id; }
public String getValue() { return value; }
public void setValue( String value ) { this.value = value; }
@Override public String toString() { return "EhCacheDeadLockEntity{" + "id=" + id + ", value='" + value + '\'' + '}'; }
@Override public boolean equals( Object o ) { if ( this == o ) return true; if ( !( o instanceof EhCacheDeadLockEntity ) ) return false;
EhCacheDeadLockEntity that = (EhCacheDeadLockEntity) o;
if ( id != that.id ) return false;
return true; }
@Override public int hashCode() { return id; } }
{code}
{code:title=EhCacheDeadLockTest.java|borderStyle=solid}
private static final int[] ID_LIST = new int[]{ 1, 2, 10010003, 10010004 }; static volatile boolean finish = false; static AtomicInteger counter = new AtomicInteger();
class Worker implements Runnable { Random rnd = new Random();
@Override public void run() { while ( !finish ) { try { final Session session = HibernateFactory.getCurrentSession(); Transaction tx = session.beginTransaction(); try { session.clear(); int id = ID_LIST[rnd.nextInt( ID_LIST.length )]; EhCacheDeadLockEntity entity = (EhCacheDeadLockEntity) session.get( EhCacheDeadLockEntity.class, id ); entity.setValue( String.valueOf( rnd.nextInt() ) ); session.save( entity ); } finally { tx.commit(); counter.incrementAndGet(); } } catch ( Throwable e ) { System.out.println( e ); } } } }
@Test public void testDeadLock() throws Exception { final int THREAD_COUNT = 32; Worker[] workers = new Worker[THREAD_COUNT]; Thread[] threads = new Thread[THREAD_COUNT];
for ( int i = 0; i < workers.length; i++ ) workers[i] = new Worker();
for ( int i = 0; i < workers.length; i++ ) threads[i] = new Thread( workers[i] );
for ( int i = 0; i < workers.length; i++ ) threads[i].start();
Thread.sleep( 5000 ); System.out.println( "counter=" + counter.get() ); finish = true;
for ( int i = 0; i < workers.length; i++ ) threads[i].join(); } {code}
|