Announcement Announcement Module
Collapse
No announcement yet.
scheduling a DAO operation in hibernate Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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
    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

    Comment


    • #3
      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,

      Comment


      • #4
        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.

        Comment


        • #5
          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

          Comment


          • #6
            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.

            Comment


            • #7
              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

              Comment


              • #8
                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, 02:38 PM.

                Comment


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

                  Comment


                  • #10
                    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

                    Comment


                    • #11
                      Defining the transactional annotation isn't enough, you need to tell spring to process it.

                      How are you doing transactions elsewhere? With <tx:advice>? It doesn't matter how you do it, as long as you do it correctly

                      Please read the following to understand how to implement transactions in Spring...
                      http://static.springframework.org/sp...ansaction.html

                      Comment


                      • #12
                        OK, i got it working, i assume my solution is pretty specific to my own context, but ill post it anyway to see if it helps anyone

                        Code:
                        <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                            <property name="sessionFactory">
                              <ref bean="hibernateSessionFactory" />
                            </property>
                          </bean>
                          <bean id="txProxyController" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
                            <property name="transactionManager">
                              <ref bean="transactionManager" />
                            </property>
                            <property name="transactionAttributes">
                              <props>
                                <prop key="*">PROPAGATION_REQUIRED</prop>
                              </props>
                            </property>
                          </bean>
                        
                        <bean id="taggerDAO" class="com.verilogue.service.dao.TaggerHibernateDAO">
                           		<property name="sessionFactory">
                           			<ref bean="hibernateSessionFactory"/>
                           		</property>			
                          </bean>
                          
                          <bean id="ModelTrainer" parent="txProxyController">
                                <property name="target">
                                      <ref bean="nonTran_modelTrainer" />
                                </property>
                          </bean>
                              
                          <bean id="nonTran_modelTrainer" class="com.verilogue.service.mallet.DefaultModelTrainer">
                           		<property name="taggerDAO">
                           			<ref bean="taggerDAO"/>
                           		</property>
                           		<property name="sessionFactory">
                              		<ref bean="hibernateSessionFactory" />
                            	</property>		
                          </bean>


                        The call to set the event, passed in the current application context by a spring instanciated class that is applicationContextAware

                        Code:
                        public void scheduelTraining(ApplicationContext ctx)
                        	{
                            	TimerTaskExecutor tte = new TimerTaskExecutor();
                            	tte.setDelay(10*1000);
                            	tte.afterPropertiesSet();
                        		(new ModelTrainerExecutor(tte)).train(this.getUID(),ctx);
                        	}


                        the trainer executor, gets the trainer from spring using the context at runtime(in the future)
                        Code:
                        public class ModelTrainerExecutor {
                        
                        	public class RunModelTrainer implements Runnable {
                        		private int modelUID;
                        		private ApplicationContext ctx;
                        		private ModelTrainer trainer;
                        
                        		
                        		public RunModelTrainer(int m, ApplicationContext ctx)
                        		{
                        			modelUID=m;
                        			this.ctx=ctx;
                        		}
                        		
                        		public void run()
                        		{	
                        			try
                        			{
                        			trainer=(ModelTrainer)ctx.getBean("ModelTrainer");
                        			trainer.setModelUID(modelUID);
                        			trainer.train();
                        			}
                        			catch(Exception ex)
                        			{
                        				System.out.println("Cause: "+ex.getCause());
                        				ex.printStackTrace();
                        			}
                        		}
                        	}
                        
                          private TaskExecutor taskExecutor;
                        
                          public ModelTrainerExecutor(TaskExecutor taskExecutor) {
                            this.taskExecutor = taskExecutor;
                          }
                        
                          public void train(int uid, ApplicationContext ctx) {
                            taskExecutor.execute(new RunModelTrainer(uid,ctx));
                          }
                        }


                        the train method in the actual trainer
                        Code:
                        public class DefaultModelTrainer 
                        extends HibernateTemplate
                        implements ModelTrainer{
                        
                        	private TaggerDAO taggerDAO;
                        	private int modelUID;
                        	
                        	@Transactional()
                        	public void train() {
                        		//DAO loads and saves using the object graph
                        		
                        	}
                        
                        	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;
                        	}

                        i sincerely appreciate everyones help and patience, thank you
                        Dan

                        Comment


                        • #13
                          Couldn't you wire all of this together with Spring? All you need to do is make whatever bean you want a prototype.
                          Last edited by karldmoore; Aug 27th, 2007, 02:36 PM.

                          Comment

                          Working...
                          X