Announcement Announcement Module
Collapse
No announcement yet.
Store problem when activating Transactions Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Store problem when activating Transactions

    Hi,

    I've been searching on a problem for almost a week now. I've been debugging way back into hibernate and into springframework and do not get it.

    The following is what is happening. I'm using detached objects.

    I've got the following piece of code that should capture and solve a concurrency between a Doctor and his Assistent both adding data to a collection 'Interventies' associated with a object 'Zitting'.

    The Collection initially can contain some other values. In the end the doctor stores his data successfully, while the Assistent should get a Optimistic Lock exception. Now we catch this exception and merges the data of the Assistent and the data from the doctor, which was reloaded from the database before merging. So eventually the collection should contain two more objects.

    Here you can see the code of my testcase:

    (1)

    Code:
     /**
         * Tests the {@link ZittingDAOHibernateImpl#store(Zitting)} method.
         *
         * @throws Exception when an error occurs
         */    
        public void testStoreConcurrent() throws Exception {
            setSecureContext();
    
            Zitting zitting = objectFactory.createZitting();
            
            AssociationInitializerConfig aiConfig = new AssociationInitializerConfigImpl();
            aiConfig.setPath(Zitting.MEDISCHEINTERVENTIE_ASSOCIATION + "." 
            		+ MedischeInterventie.MEDISCHETUSSENKOMST_ASSOCIATION + "."
            		+ MedischeTussenkomst.MEDISCHEINTERVENTIES_ASSOCIATION);
                 
            // load the zitting for the AG
            Zitting loadedZittingAG = zittingDAO.load(zitting.getPrimaryKey(), aiConfig);
    
            assertNotNull("The zitting should not be null.", loadedZittingAG);
            assertEquals("Invalid zitting retrieved: the PKs are different.",
                    zitting.getPrimaryKey(), loadedZittingAG.getPrimaryKey());
            
            // load the same zitting for the ASS
            Zitting loadedZittingASS = zittingDAO.load(zitting.getPrimaryKey(), aiConfig);
    
            assertNotNull("The zitting should not be null.", loadedZittingASS);
            assertEquals("Invalid zitting retrieved: the PKs are different.",
                    zitting.getPrimaryKey(), loadedZittingASS.getPrimaryKey());                
            
            Werknemer werknemer1 = objectFactory.createWerknemer();
            Werknemer werknemer2 = objectFactory.createWerknemer();
            Date date = Calendar.getInstance().getTime();
            
            // Add an intervention to the loadedZittingAG  
            MedischeInterventie interventie1 = IKMOObjectFactory.createMedischeInterventie();
            interventie1.setPrimaryKey("Interventie1");
            interventie1.setAg(loadedZittingAG.getAg());
            interventie1.setWerknemer(werknemer1);
            interventie1.setStatus(MedischeInterventie.STATUS_OPGER);
            interventie1.setInterventietype(objectFactory.createInterventieType());
            
            MedischeTussenkomst medischeTussenkomst1 = IKMOObjectFactory.createMedischeTussenkomst();
            medischeTussenkomst1.setPrimaryKey("medischeTussenkomst1");
            medischeTussenkomst1.setWerknemer(werknemer1);        
    		medischeTussenkomst1.setDatumUitgevoerd(date);
            
    					
    		loadedZittingAG.addMedicalIntervention(interventie1);
            medischeTussenkomst1.addMedischeInterventie(interventie1);
            
            // Add an intervention to the loadedZittingASS
            MedischeInterventie interventie2 = IKMOObjectFactory.createMedischeInterventie();
            interventie2.setPrimaryKey("Interventie2");
            interventie2.setAg(loadedZittingASS.getAg());
            interventie2.setWerknemer(werknemer2);
            interventie2.setStatus(MedischeInterventie.STATUS_OPGER);
            interventie2.setInterventietype(objectFactory.createInterventieType());
            
            MedischeTussenkomst medischeTussenkomst2 = IKMOObjectFactory.createMedischeTussenkomst();
            medischeTussenkomst2.setPrimaryKey("medischeTussenkomst2");
            medischeTussenkomst2.setWerknemer(werknemer2);
            medischeTussenkomst2.setDatumUitgevoerd(date);
            
            loadedZittingASS.addMedicalIntervention(interventie2);
            medischeTussenkomst2.addMedischeInterventie(interventie2);
                    
            
            Set<MedischeInterventie> interventiesAG = loadedZittingAG.getMedischeInterventies();
            
            // collect MI info
            /* A list that contains all new medischeInterventies */
            List<MedischeInterventie> newInterventies = new ArrayList<MedischeInterventie>();
            /* A list that contains the primary keys of all persistent medischeInterventies that have the status STATUS_ANNUL */
            List<Serializable> removedInterventies = new ArrayList<Serializable>(); // primary keys
            /* A map that map all new medischeInterventies to a persistent medischeTussenkomst, if they have been added to a persistent medischeTussenkomst */
            Map<MedischeInterventie, Serializable> persistentMedischeTussenkomsten = new HashMap<MedischeInterventie, Serializable>();
            
            for (MedischeInterventie mi : interventiesAG) {
                if (!mi.isPersistent()) {
                    newInterventies.add(mi);
                    if (mi.getMedischeTussenkomst().isPersistent()) {
                        persistentMedischeTussenkomsten.put(mi, mi.getMedischeTussenkomst().getPrimaryKey());
                    }
                } else if (mi.getStatus().equals(MedischeInterventie.STATUS_ANNUL)) {
                    removedInterventies.add(mi.getPrimaryKey());
                }
            }
            
            // Store the loadedZittingASS
            Zitting savedZittingASS = null;
        	try{
        		savedZittingASS = zittingDAO.store(loadedZittingASS);    
        	} catch (DAOException e) {
        		e.printStackTrace();
        	}
                    
            assertNotNull("Stored ASS zitting should not be null", savedZittingASS);                
            
            // and now try to store the loadedZittingAG                
            Zitting savedZittingAG = null;        
            try{        	        
            	zittingDAO.store(loadedZittingAG);
            	fail("Should have thrown a DAOException");
            } catch (DAOException ex){        	
    			BusinessException businessException = (BusinessException)ex.getCause().getCause();
    			if(businessException != null && businessException instanceof OptimisticLockException) {
                	Zitting mergedZitting 
                		= mergeZittingInterventiesWithLastZittingInterventies(loadedZittingAG, newInterventies, removedInterventies, persistentMedischeTussenkomsten, false);
                	
                	try{            		
    	            	savedZittingAG = zittingDAO.store(mergedZitting);    
                	} catch (Exception e) {
                		e.printStackTrace();
                	}
    	            
                	assertNotNull("Stored AG zitting should not be null", savedZittingAG);        
                }
            }
        }
    No the ZittingDAO has the transaction defined as follows:

    @Transactional(propagation=Propagation.REQUIRED, rollbackFor={DAOException.class})
    public class ZittingDAOHibernateImpl extends HibernateDaoSupport implements ZittingDAO {

    When I put this Transaction in comment, the Unit Test runs fine, otherwise it fails.

    Now the code that is called via the zittingDAO which is causing the problem is the following piece:

    (2)

    Code:
            Zitting savedZittingAG = null;        
            try{        	        
            	zittingDAO.store(loadedZittingAG);
            	fail("Should have thrown a DAOException");
            } catch (DAOException ex){         
    		BusinessException businessException = (BusinessException)ex.getCause().getCause();
    			if(businessException != null && businessException instanceof OptimisticLockException) {
                	Zitting mergedZitting 
                		= mergeZittingInterventiesWithLastZittingInterventies(loadedZittingAG, newInterventies, removedInterventies, persistentMedischeTussenkomsten, false);
                	
                	try{            		
    	            	savedZittingAG = zittingDAO.store(mergedZitting);    
                	} catch (Exception e) {
                		e.printStackTrace();
                	}
    	            
                	assertNotNull("Stored AG zitting should not be null", savedZittingAG);        
                }
    In the store method I do the following:


    (3)

    Code:
     public final Persistent saveOrUpdateObject(final Persistent persistent) {
        	
            //use a hibernate callback instead of the hibernate template directly
            //because we need to do several things while the hibernate session is open
            return (Persistent) execute(new HibernateCallback() {
                public Object doInHibernate(Session session) throws HibernateException, SQLException {
                    checkWriteOperationAllowed(session);
                    session.saveOrUpdate(persistent);
                    session.flush();
                    
                    //create association initializer config based on current persistent object
                    AssociationInitializerConfigImpl associationInitializerConfig = new AssociationInitializerConfigImpl();
                    populateAssociationInitializerConfig(persistent, associationInitializerConfig, new HashSet());
                    session.refresh(persistent);
                    postLoad(persistent, associationInitializerConfig, new HibernateDaoSession(session));
                    return persistent;
                }
            });
        }
    Now the second store in (2) fails, as this is suppose not to fail.
    Now when replacing the first store via the DAO in (2) by directly using the hibernate session and as such bypassing the HibernateTemplate it works fine. It also works fine if I put a Thread.sleep(120000) just before the second call for storing the merged Zitting object.

    Can anyone see what I am doing wrong?

    Thnx in advance?
    Nico De Groote
    JCS Int
    http://www.jcs.be
    Last edited by ndgroote; Oct 13th, 2006, 09:12 AM. Reason: Made it more readable

  • #2
    Removing some read-write cache on the business objects in the Hibernate Mapping files do "fix" this problem. Now the question is if the problem is in the caching system or in the calls towards the caching system.

    Nico

    Comment


    • #3
      The problems seems to be lying in the timeToIdleSeconds="120" configured for the cache.

      Any ideas why this should result into the problem I have above?

      Nico

      Comment


      • #4
        Ok I did replace the EHCache by some of the other Cache systems it resulted in the same problems. So this doesn't seem to be a Spring problem after all.
        Up towards Hibernate;

        Comment


        • #5
          The following link brings you to the reason of the problem.

          http://opensource.atlassian.com/proj...rowse/HHH-1100

          Comment

          Working...
          X