Hi
When I am saving a large set of objects in a long transaction, I am getting primary key constraintviolation. I am saving a NetworkElement which has children and grandchildren..
The dbobjects are defined in an hierarchy.NetworkElement(has),Shelf(has),Pack(has), DSLPort. All objects have their own oracle sequence defined. NetworkElement also has association with other
objects, in a one-to-one or one-to-many relations.
I parse a registry from the NetworkElement and save all the children and grandchildren objects in the database, includin the NE and its associated objects, inside a long spring platformtransaction.
When I am parsing 2 NetworkElements simultaneously, with lot of data in it, I endup with ConstraintViolationException, in any of the child objects or the associated objects with the Network Element. The transaction
fails and a rollback happens.
Each NetworkElement do not have common children, so a DSLPort in one NE is independent of another DSLPort in another NE. But the 2 independent transactions running simultaneously complain about
ConstraintViolation on any of the objects, say DSLPort here.
For instance I mostly get ConstraintViolation on DSLPortDBObj, each NE has a large set of ports. The primary key is handled by Hibernate, it retrieves the sequence id before saving.
Code:
@MappedSuperclass
public abstract class ManagedIdCMDBObject extends EMSDBObject{
protected Integer id;
protected Long version;
@Id
@GeneratedValue(generator="SEQ_GEN")
public Integer getId() {
return id;
}
....
Code:
@Table(name = "DSLPORT")
@Entity
@GenericGenerator(name = "SEQ_GEN", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
@Parameter(name = "sequence_name", value = "DSLPORT_SEQ"),
@Parameter(name = "initial_value", value = "1"),
@Parameter(name = "increment_size", value = "1") })
public class DSLPortDBObj extends ManagedIdCMDBObject implements Serializable {
private PackDBObj pack;
@ManyToOne
@JoinColumn(name="fk_dsl_pack")
@ForeignKey(name="fk_dsl_pack")
@Index(name="INDEX_DSL_PACK")
public PackDBObj getPack() {
return pack;
}
Code:
@Table(name = "PACK")
@GenericGenerator(name = "SEQ_GEN", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
@Parameter(name = "sequence_name", value = "PACK_SEQ"),
@Parameter(name = "initial_value", value = "1"),
@Parameter(name = "increment_size", value = "1") })
public class PackDBObj extends ManagedIdCMDBObject implements Serializable {
private List<DSLPortDBObj> dslPorts = new ArrayList<DSLPortDBObj>();
@OneToMany( mappedBy = "pack")
public List<DSLPortDBObj> getDslPorts() {
return dslPorts;
}
called by EMSDBServiceImpl
Code:
public class GenericDaoImpl<T, ID extends Serializable> extends HibernateDaoSupport
implements GenericDaoInterface<T, ID>{
public T persist(final T entity) throws DataAccessException {
getHibernateTemplate().persist(entity);
return entity;
}
called by CMDTOServiceImpl
Code:
@Transactional(propagation=Propagation.SUPPORTS)
public class EMSDBServiceImpl implements EMSDBServiceInterface{
protected GenericDaoImpl genericDao = null;
public EMSDBObject add(EEUFdn parentFdn, EMSDBObject dbObj) throws
DBException {
//set links to parent object, pack and then save
EMSDBObject o = (EMSDBObject) dbService.getGenericDao().persist(emsObjectDBObj);
}
called by discoveryutils
Code:
@Transactional(propagation = Propagation.REQUIRED)
public class CMDTOServiceImpl implements CMDTOServiceInterface {
//inject the dbservice
public CMObject addCMObject(EEUFdn parentFdn, CMObject cmObject) throws DTOException {
try {
--convert cmObject(DTO Object) to dbobject using dozer library.
dbService.add(parentFdn, (ManagedIdCMDBObject)dbObj);
..
} catch (Exception e) {
throw new DTOException(BaseExceptionEnum.DTO_ADD_FAILED,
cmObject.getFdn().toString(), e);
}
Code:
public class CMDiscoveryUtils {
public static void writeRegistry2DB(..) {
PlatformTransactionManager platformTransactionManager = CMDiscoveryMgr.getInstance().getTransactionManager();
TransactionStatus status = platformTransactionManager.getTransaction(new DefaultTransactionDefinition());
try {
NEDBObj cluster = getClusterFromDB(neId);
..
for (int i = 0; i < numShelves; i++) {
..save shelf
for each pack {
--save multiple DSLPorts in a loop.
DSLPortDBObj dsl = new DSLPortDBObj();
dsl.setAid(portAid);
CMDiscoveryMgr.getInstance().getDBService(). add(pack.getFdn(), dsl);
}
[color=#FF0000]...query shelf object causes flush of DSLPorts and mostly causes constraintviolation on the primary key[/color]
}
} catch (Exception ex) {
platformTransactionManager.rollback(status);
EntLogger.severe(CMDiscoveryUtils.class, ex.getMessage(), ex);
throw ex;
}
platformTransactionManager.commit(status);
}
The platformtransaction in CMDiscoveryUtils starts the transaction and the DTOService continues the transaction. The CMDTOService has transaction defined at the class level(annotation based).
If 2 different transactions are saving the multiple DSLPorts, the transactions seem to be retrieving distinct primary keys from DSLPort_Seq from Oracle. But at the time of flush caused by query, ahead of the commit, one of the DSLPort persist throws an ConstraintViolationException on the primary key id. The log does not seem to indicate the same id being used.
I can only reproduce this when I have a large set of DSLPorts but not otherwise. Please advice what is going wrong.