Announcement Announcement Module
Collapse
No announcement yet.
Hibernate update from within Runnable ? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Hibernate update from within Runnable ?

    Hi,

    I am having a problem using Hibernate with Spring-managed sessions within a threaded object.

    I have a class that extends Runnable that I use to read byte arrays from a socket that's connected to an external system. It is instantiated using Thread.

    I get a nullPointerException error when I try to get the Spring sessionFactory that I've injected into the class. Also, if I call my DAO objects to do database updates from within the Thread, I also get a nullPointerException for the Hibernate session.

    My DAO classes work fine when I do not call them from a Thread. I use a separate session to avoid deadlock issues.

    Starting thread:

    Code:
    Thread thread = new Thread(new MyThreadedClass(param1, param2));
    			thread.start();
    MyThreadedClass is fairly big, so I will just post salient snippets:

    Code:
    @Repository
    public class MyThreadedClass implements Runnable {
    	
    	private SessionFactory sessionFactory;
    
    	@Autowired
    	public void setSessionFactory(SessionFactory factory)
    	{
    		sessionFactory = factory;
    	}
    
    @Transactional
    	public void updateDatabase()
    	{
    		
    		Session mySession = sessionFactory.openSession();
    		Transaction tx = null;
    		
    		try {
    			tx = mySession.beginTransaction();
    		} catch (HibernateException e1) {
    			logger.error("!!!!!!!!! booHooHoo  failed to start transaction : {}", e1);
    		}
    	
    		try
    		{
    			mySession.update(myTable);
    			tx.commit();
    		}
    		catch (HibernateException e)
    		{
    			logger.error("!!!!!!!!! booHooHoo  update of myTable failed : {}", e);
    		}
    Please help !
    Last edited by Slidewayz; Aug 16th, 2011, 03:47 AM.

  • #2
    So you expect the instance you create yourself to be injected by spring... Now spring can do much but it won't do that (not without work)... Create a bean definition and make it prototype scoped, then instead of creating a new instance retrieve a new instance from the application context.

    Comment


    • #3
      Thank you, Marten...it makes perfect sense that Spring can't autowire an object I create myself.

      I just read the Spring doc on Bean scopes, so that explains how to define the bean in the applicationContext. I assume I could @Autowire it into my calling class. Since I am doing asynchronous comm. to multiple external devices, would I use SimpleAsyncTaskExecutor to create the threads, with Spring dynamically injecting the sessionFactory for each instance ? It is not clear to me how these would get garbage-collected...is that handled by SimpleAsyncTaskExecutor's relationship to the Spring container or do I still need a custom bean post-processor?

      Thanks again !!!

      Comment


      • #4
        I suggest a read of the reference guide... IMHO you should simply use a TaskExecutor to execute your tasks. The task I would configure in the application with the scope prototype. Then simply wire the TaskExecutor and the BeanFactory/ApplicationContext and use that to retrieve the bean, that should also take care of of gc'ing in the end...

        Code:
        @Autowired
        private TaskExecutor executor;
        
        @Autowired
        private ApplicationContext context;
        
        public void scheduleUpdateTask() {
          Runnable myTask = context.getBean("myTask");
          executor.execute(myTask);
        }
        Now you can also take advantage of @Transactional and you shouldn't need to mess around with the session/transactions yourself....

        Again I suggest a read of the scheduling/executor chapter of the reference guide.

        Comment


        • #5
          Thanks again, Marten.

          I've read up on and tried some examples for TaskScheduler/TaskExecutor.

          The only issue I'm now facing is how to set dynamic constructor properties in the prototype object I've obtained from the context.

          Lamentably, casting the object to my class (or back to Runnable) so I can set its properties does not work, as I get a 'Proxy cannot be cast to' error.

          This doesn't work:

          Code:
          MyTaskObj myTaskObj = (MyTaskObj) context.getBean("myTaskObj");
          			myTaskObj.setParam1(objectA);
          			myTaskObj.setParam2("myString");
          			Runnable myTask = (Runnable) myTaskObj;
          		        taskExecutor.execute(myTask);
          I haven't found any examples that show how to dynamically set properties for beans retrieved from the context. I have to pass in the ipAddress and the
          requestType for each device.

          The Spring documentation show how to define constructor arguments, but not how to pass them in to an object retrieved from the context:

          Code:
          <bean id="exampleBean" class="examples.ExampleBean">
               <constructor-arg name="years" value="7500000"/>
               <constructor-arg name="ultimateanswer" value="42"/>
          </bean>
          It has to be fairly common for someone to read in data from a socket and persist it to a database using Spring/Hibernate ? Any advice is
          very warmly received !!!

          Comment


          • #6
            There is a getBean method which takes more arguments and one of those methods also takes arguments which will be used as constructor arguments.

            Comment


            • #7
              Originally posted by Marten Deinum View Post
              There is a getBean method which takes more arguments and one of those methods also takes arguments which will be used as constructor arguments.
              Thanks again, Marten. It is definitely getting closer.

              I am throwing a null exception now on the update because I am not passing in
              'object' to myTask. So, there are 2 parameters, one Object and one String that
              need to be passed in.

              Please let me know if you see any problem with how I did it. Also, do you have
              any books you could recommend that cover stuff like this? I have Spring Enterprise
              Recipes, but it does not go into this kind of detail.

              Thanks again !!!

              Code:
              Runnable myTask = (Runnable) context.getBean("MyTask", object, stringParam);
              
              <bean id="myTask"
              	  class="externalInterface.MyTask"
              	  scope="prototype">
              		  <constructor-arg name="object" value="object"/>
              		  <constructor-arg name="stringParam" value="stringParam"/>
              		  <property name="sessionFactory" ref="sessionFactory"/>
              </bean>

              Comment

              Working...
              X