Page 1 of 2 12 LastLast
Results 1 to 10 of 13

Thread: scheduling a DAO operation in hibernate

  1. #1
    Join Date
    Aug 2007
    Posts
    7

    Thumbs down scheduling a DAO operation in hibernate

    i'm trying to schedule a call to a method within a class that performs a DAO operation, im using the java.util.Timer and java.util.TimerTask classes
    unfortunately, im getting the LazyInitializationException, which i assume is caused because theres no open session when im trying to perform the DAO operation?
    to fix it i tried to create a session using SessionFactoryUtils, and retrieving the session from my DAO object, but im still getting the LIE, my code is as follows

    Code:
    timer.schedule(new TimerTask() {
        public void run()
        {
              Session session = SessionFactoryUtils.getSession(taggerDAO.getSessionFactory(), true);
              try {
                     mod.train();
                   }
                   catch (HibernateException ex) {
                  throw SessionFactoryUtils.convertHibernateAccessException(ex);
                   }
        }    			
    }, 10*1000);
    my first post, apologies if its not formatted properly

  2. #2
    Join Date
    Nov 2005
    Location
    Reutlingen, Germany
    Posts
    2,098

    Default

    Formatting is ok

    For nearly sure the session stuff (as well as possible transaction handling) relies on ThreadLocals - which you obviously break with your timer. If that's not a problem (creating a new session in the timer thread) you probably use an entity which is attached to the session in the original thread, but not to the timer thread. You have to reattach it to the session in the timer thread - what ever this causes for side-effects in the original thread/ session.

    This all sounds like a major pain. Must it be a different thread? And if so, you should not do this inside the DAO but on the service level.

    Joerg
    This post can contain insufficient information.

  3. #3
    Join Date
    Aug 2007
    Posts
    7

    Default

    that method sits within the class that the dao instanciates, mod is a final copy of the object that its within, and the train method takes hours to complete, but only talks to the database once at the beginning and once at the end, so it must be done in a seperate thread

    here is what i have now, ive gotten it so that it can read the data from the database at a later date, still using the lazy associations in the mapping, so its generating the object graph, but it wont save, when it tries to save (the blob object does not exist) i get an illegalStateException error, and when i try to update it (the blob object exists but needs to be updated) it doesnt error out, but also doesnt update the database


    Code:
    public void scheduelTraining()
    {
    	final Timer timer = new Timer();
        	final Calendar cal = new GregorianCalendar();
        	final Model mod =this;
    	int h = 23-cal.get(Calendar.HOUR_OF_DAY);
        	int m = 60-cal.get(Calendar.MINUTE);
        	int s = 60-cal.get(Calendar.SECOND);
        	int time = s+60*m+3600*h;
    		timer.schedule(new TimerTask() {
    			public void run()
    			{
    				Session session = SessionFactoryUtils.getSession(taggerDAO.getSessionFactory(), true);
    				try {
    				mod.train(session);
    				}
    				catch (HibernateException ex) {
    					ex.printStackTrace();
    				     throw SessionFactoryUtils.convertHibernateAccessException(ex);
    				     
    				   }
    			}    			
    		}, 10*1000);
    		//schedueled=true;
    }



    Code:
    public void train(Session session)
    {		
    		Model mod=(Model)session.load(Model.class, this.getUID());
    		mod.setSchedueled(false);
    		System.out.println(mod.getName().trim()+" is now training");
    		Blob file = mod.getFile();
    		if(file==null)
    			file=new Blob();
    		String code = "";
    		String reg = "";
    		String div="";
    		int i=0;
    		for(Tag t : mod.getTrainingSet().getCodeBook().getTags())
    		{
    			if(i<4)
    			{
    				String subReg=t.getCode().trim();
    				String subCode = t.getName().trim();
    				if (i == 0)
    					div="";
    				else
    					div="<>";
    				code += div+subCode;
    				reg += div+subReg;
    			}
    			i++;
    		}
    		
    		code = code.replace("\\s+", "");
    		MEDClassifier medc = new MEDClassifier();
    		String[] codes = code.split("<>");
    		String[] regs = reg.toLowerCase().split("<>");
    		
    		file.setData(medc.train(mod.getTrainingSet(), codes, regs));
    		file.setFileName(mod.getName());
    		file.setContentType("application/PDt");
    		mod.setTrained(true);
    		mod.setSchedueled(false);
    		session.saveOrUpdate(file);
    		mod.setFile(file);
    		session.saveOrUpdate(mod);
    		
    }

    most of the middle part of the train() method can be ignored, its only the beginning where it reads in and end where it tries to save that i need help with,

  4. #4
    Join Date
    Aug 2004
    Posts
    1,905

    Default

    I would go another approach and use Spring's task execution support: http://static.springframework.org/sp...-task-executor

    The main benefit is that the job itself can then be proxied and can become transactional, just like your service.
    Colin Yates
    SpringSource - http://www.springsource.com - Spring Training, Consulting, and Support - "From the Source"
    Please read http://www.springframework.org/documentation
    Co-Author of Expert Spring MVC + Web Flow.

  5. #5
    Join Date
    Aug 2007
    Posts
    7

    Default

    thanks for all the help, i implemented your method with the executor, and im still getting the illegalStateException error, but only when i try to save, when it reads the values it reads them in fine and correctly


    Code:
    public class ModelTrainerExecutor {
    
    	public class ModelTrainer implements Runnable {
    		private int modelUID;
    		private SessionFactory sessionFact;
    		
    		public ModelTrainer(Model m, SessionFactory sf)
    		{
    			modelUID=m.getUID();
    			sessionFact=sf;
    		}
    		
    		public ModelTrainer(int m, SessionFactory sf)
    		{
    			modelUID=m;
    			sessionFact=sf;
    		}
    		
    		public void run()
    		{		
    			Session session = sessionFact.openSession();
    			Model mod=(Model)session.load(Model.class, modelUID);
    			mod.setSchedueled(false);
    			System.out.println(mod.getName().trim()+" is now training");
    			Blob file = mod.getFile();
    			if(file==null)
    				file=new Blob();
    			String code = "";
    			String reg = "";
    			String div="";
    			int i=0;
    			for(Tag t : mod.getTrainingSet().getCodeBook().getTags())
    			{
    				if(i<4)
    				{
    					String subReg=t.getCode().trim();
    					String subCode = t.getName().trim();
    					if (i == 0)
    						div="";
    					else
    						div="<>";
    					code += div+subCode;
    					reg += div+subReg;
    				}
    				i++;
    			}
    			
    			code = code.replace("\\s+", "");
    			MEDClassifier medc = new MEDClassifier();
    			String[] codes = code.split("<>");
    			String[] regs = reg.toLowerCase().split("<>");
    			
    			file.setData(medc.train(mod.getTrainingSet(), codes, regs));
    			file.setFileName(mod.getName());
    			file.setContentType("application/PDt");
    			mod.setTrained(true);
    			mod.setSchedueled(false);
    			session.saveOrUpdate(file);
    			mod.setFile(file);
    			session.saveOrUpdate(mod);
    			
    		}
    	}
    
      private TaskExecutor taskExecutor;
    
      public ModelTrainerExecutor(TaskExecutor taskExecutor) {
        this.taskExecutor = taskExecutor;
      }
    
      public void train(int uid,SessionFactory sf) {
        for(int i = 0; i < 25; i++) {
          taskExecutor.execute(new ModelTrainer(uid,sf));
        }
      }
    }

    here is the code that calls it
    Code:
    TimerTaskExecutor tte = new TimerTaskExecutor();
    tte.setDelay(10*1000);
    tte.afterPropertiesSet();
    (new ModelTrainerExecutor(tte)).train(mod.getUID(),taggerDAO.getSessionFactory());



    im basicaly getting the same problem i was before, when it tries to update, it just does nothing, and when i tries to save, it errors out

    thanks for you help

  6. #6
    Join Date
    Aug 2004
    Posts
    1,905

    Default

    Ah no, I wasn't being very clear

    I was suggesting that you define a Spring bean which you asynchronously execute; I wasn't suggesting that the asynchronous bean itself does the job.

    Code:
      public class DefaultModelTrainerFileReader implements ModelTrainerFileReader {
    
        private ModelDAO modelDAO;
    
        // constructor injection etc.
    
          @Transaction(....)
          public void parseFile() {
              // do the file reading in here etc.
          }
      }
    Then use the Spring task executor stuff to fire it off, that way all the transaction and hibernate session stuff will be taken care of, because the code doing the thing is actually wrapped in the Spring transactional proxy.

    It is a little bit more work (a new interface and class), but I think it is worth it....unit testing the FileReader is now easy etc.

    Does that make sense? Treat the file reading service just like any other service. The fact you want to execute it asynchronously is neither here nor there.

    So to actually fire off the job, you have a number of approaches, the important thing is that you ask Spring for the ModelTrainerFileReader, to give it a chance to create the TX and hibernate session.
    Colin Yates
    SpringSource - http://www.springsource.com - Spring Training, Consulting, and Support - "From the Source"
    Please read http://www.springframework.org/documentation
    Co-Author of Expert Spring MVC + Web Flow.

  7. #7
    Join Date
    Aug 2007
    Posts
    7

    Default

    sorry to be a bother
    but, i think ive almost got it, im getting a lazyInitializationException now, im assuming that means it didnt open a session, so the transactional annotation didnt do what i thought it would,


    heres the implementation of the trainer
    Code:
    public class DefaultModelTrainer implements ModelTrainer{
    
    	private TaggerDAO taggerDAO;
    	private int modelUID;
    	
    	@Transactional()
    	public void train() {
    		Model mod=taggerDAO.findModel(modelUID);
    		mod.setSchedueled(false);
    		System.out.println(mod.getName().trim()+" is now training");
    		Blob file = mod.getFile();
    		if(file==null)
    			file=new Blob();
    		String code = "";
    		String reg = "";
    		String div="";
    		int i=0;
    		for(Tag t : mod.getTrainingSet().getCodeBook().getTags())
    		{
    			if(i<4)
    			{
    				String subReg=t.getCode().trim();
    				String subCode = t.getName().trim();
    				if (i == 0)
    					div="";
    				else
    					div="<>";
    				code += div+subCode;
    				reg += div+subReg;
    			}
    			i++;
    		}
    		
    		code = code.replace("\\s+", "");
    		MEDClassifier medc = new MEDClassifier();
    		String[] codes = code.split("<>");
    		String[] regs = reg.toLowerCase().split("<>");
    		
    		file.setData(medc.train(mod.getTrainingSet(), codes, regs));
    		file.setFileName(mod.getName());
    		file.setContentType("application/PDt");
    		mod.setTrained(true);
    		mod.setSchedueled(false);
    		taggerDAO.saveOrUpdate(file);
    		mod.setFile(file);
    		taggerDAO.saveOrUpdate(mod);
    		
    	}
    
    	public int getModelUID() {
    		return modelUID;
    	}
    
    	public void setModelUID(int modelUID) {
    		this.modelUID = modelUID;
    	}
    
    	public TaggerDAO getTaggerDAO() {
    		return taggerDAO;
    	}
    
    	public void setTaggerDAO(TaggerDAO taggerDAO) {
    		this.taggerDAO = taggerDAO;
    	}
    	
    
    }
    heres where i set up the timer and call it
    tr is the trainer instance created by spring
    when it goes to the executor, it just calls tr.train() in 10 seconds
    Code:
    tr.setModelUID(this.getUID());
    TimerTaskExecutor tte = new TimerTaskExecutor();
    tte.setDelay(10*1000);
    tte.afterPropertiesSet();
    (new ModelTrainerExecutor(tte)).train(tr);

    here is bean declaration
    Code:
    <bean id="taggerDAO" class="com.verilogue.service.dao.TaggerHibernateDAO">
       		<property name="sessionFactory">
       			<ref bean="hibernateSessionFactory"/>
       		</property>			
      </bean>
      
      <bean id="ModelTrainer" class="com.verilogue.service.mallet.DefaultModelTrainer">
       		<property name="taggerDAO">
       			<ref bean="taggerDAO"/>
       		</property>			
      </bean>

    if im getting a LIE now, do i have to create a session from a session factory in the model trainers train() method?
    you said that if spring loaded it it would take care of that, so im thinking im missing something

    thanks again
    Dan

  8. #8
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    The problem here is that you are creating the object using the new operator. As it's not spring managed you aren't going to get a transactional proxy.
    Code:
    (new ModelTrainerExecutor(tte)).train(tr);
    Last edited by karldmoore; Aug 27th, 2007 at 02:38 PM.
    Barracuda Networks SSL VPN Lead Developer
    http://pramatr.wordpress.com
    http://twitter.com/karldmoore
    http://www.linkedin.com/in/karldmoore
    Any postings are my own opinion, and should not be attributed to my employer or clients.

  9. #9
    Join Date
    Aug 2007
    Posts
    7

    Default

    ohhhhhh, ok, now i get it, should i use the application context to instanciate it, or is there another method of doing so

  10. #10
    Join Date
    Aug 2007
    Posts
    7

    Default

    ok, so heres my new problem, the application context i pass in is the one at the current time (i implemented ApplicationContextAware in one of the classes and pass the context along)

    ctx.getBean("ModelTrainer"); returns a model trainer, but im still getting the LIE, is this because im using the application context from 10 seconds ago? if so, how can i possibly get the current running application context in a run method of a threadable class

    Code:
    public void run()
    {	
    	try
    	{
                    //ctx is the context from when the timer was set,  not now when it runs
    		trainer=(ModelTrainer)ctx.getBean("ModelTrainer");
    		trainer.setModelUID(modelUID);
    		trainer.train();
    	}
    	catch(Exception ex)
    	{
    		System.out.println("Cause: "+ex.getCause());
    		ex.printStackTrace();
    	}
    }
    if i understand correctly, the only way to get the context in a class is to have that class be applicationContextAware and have it be instanciated by spring, and i have no idea how to instanciate a runnable class by spring,
    so im asking, is that doable, or is there some other method of doing this i should go about

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •