I build application which import data into database. I do this job in multiple threads. After few record Hibernate throws exception
Quote:
unique constraint (XXX.UQ_TESTA) violated
or
Quote:
unique constraint (XXX.PK_TESTB) violated
.
I don't know why.
Thanks,
Martin
SQL to build test DB:
Code:
CREATE TABLE TESTA
(
A NUMBER(4) NOT NULL,
AB NUMBER(4) NOT NULL,
C VARCHAR2(10 BYTE)
)
TABLESPACE XXX
PCTUSED 0
PCTFREE 10
INITRANS 1
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
BUFFER_POOL DEFAULT
)
LOGGING
NOCACHE
NOPARALLEL
NOMONITORING;
ALTER TABLE TESTA ADD (
CONSTRAINT PK_TESTA
PRIMARY KEY
(A));
ALTER TABLE TESTA ADD (
CONSTRAINT UQ_TESTA
UNIQUE (C));
ALTER TABLE TESTA ADD (
CONSTRAINT FK_AB
FOREIGN KEY (AB)
REFERENCES TESTB (B));
CREATE TABLE TESTB
(
B NUMBER(4) NOT NULL
)
TABLESPACE XXX
PCTUSED 0
PCTFREE 10
INITRANS 1
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
BUFFER_POOL DEFAULT
)
LOGGING
NOCACHE
NOPARALLEL
NOMONITORING;
ALTER TABLE TESTB ADD (
CONSTRAINT PK_TESTB
PRIMARY KEY
(B));
Mapping file testa:Code:
<hibernate-mapping package="hr.test">
<class
name="Testa"
table="TESTA"
>
<meta attribute="sync-DAO">false</meta>
<id
name="Id"
type="integer"
column="A"
>
<generator class="increment"/>
</id>
<property name="c" column="C" type="string" length="10"/>
<many-to-one
name="ab"
column="AB"
class="Testb"
not-null="true"
cascade="save-update"
>
</many-to-one>
</class>
</hibernate-mapping>
Mapping file testb:Code:
<hibernate-mapping package="hr.test">
<class
name="Testb"
table="TESTB"
> <meta attribute="sync-DAO">false</meta>
<id
name="Id"
type="integer"
column="B"
>
<generator class="assigned"/>
</id>
<set name="As" inverse="true">
<key column="B" not-null="true"/>
<one-to-many class="Testa"/>
</set>
</class>
</hibernate-mapping>
Hiberante config file:Code:
<hibernate-configuration>
<session-factory>
<!-- local connection properties -->
<property name="hibernate.connection.url">
jdbc:oracle:thin:@test:1521:orcl
</property>
<property name="hibernate.connection.driver_class">
oracle.jdbc.driver.OracleDriver
</property>
<property name="hibernate.connection.username">test</property>
<property name="hibernate.connection.password">test</property>
<property name="hibernate.connection.pool_size">20</property>
<property name="current_session_context_class">thread</property>
<property name="hibernate.jdbc.batch_size">20</property>
<property name="hibernate.cache.use_second_level_cache">false</property>
<!-- dialect for Oracle (any version) -->
<property name="dialect">
org.hibernate.dialect.OracleDialect
</property>
<property name="hibernate.show_sql">false</property>
<property name="hibernate.transaction.factory_class">
org.hibernate.transaction.JDBCTransactionFactory
</property>
<mapping resource="Testa.hbm.xml" />
<mapping resource="Testb.hbm.xml" />
</session-factory>
</hibernate-configuration>
Test code (
test.java):
Code:
package hr.logos.test;
import hr.util.ACSHibernateUtil;
public class Test {
/**
*Randomly select some record
*/
public static Testa getTest() {
Testa r = new Testa();
r.setC(""+Math.round((Math.random()*100)));
r.setAb(new Testb((int)Math.round((Math.random()*100))));
return r;
}
/**
* @param args
*/
public static void main(String[] args) {
ThreadGroup threadGroup = new ThreadGroup("test");
ACSHibernateUtil.initialize();
for(int i=0; i < 50000; i++) {
while(threadGroup.activeCount() > 32){
try {
Thread.sleep(10);
}
catch(Exception e) {}
}
Thread t = new Thread(threadGroup, new TestaRunnable(i));
if(t != null) t.start();
}
while(threadGroup.activeCount() > 0){
try {
Thread.sleep(10);
}
catch(Exception e) {}
}
ACSHibernateUtil.closeSession();
}
}
Test code (
TestaRunnable.java):
Code:
package hr.test;
import hr.util.ACSHibernateUtil;
import java.util.List;
import org.apache.log4j.Logger;
public class TestaRunnable implements Runnable {
static Logger logger = Logger.getLogger(TestaRunnable.class);
private int id=0;
public TestaRunnable(int id) {
this.id = id;
}
private Testa getTesta(String cond) {
List result = null;
result = ACSHibernateUtil.getSession().createQuery(
"from Testa where c=?")
.setString(0,cond).list();
if ((result == null ? 0 : result.size()) == 0)
return null;
return (Testa) result.get(0);
}
private void insertTesta(Testa t) {
ACSHibernateUtil.getSession().save(t);
}
private void updateTesta(Testa t) {
ACSHibernateUtil.getSession().update(t);
}
public void run() {
Testa kFile = null;
try {
kFile = Test.getTest();
}
catch (Exception e) {
e.printStackTrace();
return;
}
Testa kBase = null;
int Id = 0;
try {
ACSHibernateUtil.beginTransaction();
kBase = getTesta(kFile.getC());
// if not exists in DB then insert
if (kBase == null) {
insertTesta(kFile);
}
//else update record
else {
ACSHibernateUtil.evict(kBase);
Id = kBase.getId();
kFile.setId(Id);
kFile.setAb(kBase.getAb());
updateTesta(kFile);
}
ACSHibernateUtil.commitTransaction();
}
catch (Exception e) {
e.printStackTrace();
ACSHibernateUtil.rollbackTransaction();
}
}
}
Test code (
ACSHibernateUtil.java):
Code:
package hr.util;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class ACSHibernateUtil {
private static final SessionFactory sessionFactory;
private static final ThreadLocal threadSession = new ThreadLocal();
private static final ThreadLocal threadTransaction = new ThreadLocal();
static {
try {
Configuration cfg = new Configuration().configure("hibernate.cfg.xml");
sessionFactory = cfg.buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static void initialize(){
//do nothing
}
public static Session getSession() {
Session s = (Session) threadSession.get();
try {
if (s == null) {
s = sessionFactory.openSession();
threadSession.set(s);
}
} catch (HibernateException ex) {
}
return s;
}
public static void closeSession(){
try {
Session s = (Session) threadSession.get();
threadSession.set(null);
if (s != null && s.isOpen())
s.close();
} catch (HibernateException ex) {
}
}
public static void beginTransaction() {
Transaction tx = (Transaction) threadTransaction.get();
try {
if (tx == null) {
tx = getSession().beginTransaction();
threadTransaction.set(tx);
}
} catch (HibernateException ex) {
}
}
public static void commitTransaction()throws HibernateException {
Transaction tx = (Transaction) threadTransaction.get();
try {
threadTransaction.set(null);
if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack())
tx.commit();
} catch (HibernateException ex) {
rollbackTransaction();
throw ex;
}
}
public static void rollbackTransaction(){
Transaction tx = (Transaction) threadTransaction.get();
try {
threadTransaction.set(null);
if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
tx.rollback();
}
} catch (HibernateException ex) {
} finally {
closeSession();
}
}
}