Announcement Announcement Module
Collapse
No announcement yet.
application freeze when trying to save an object Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • application freeze when trying to save an object

    Hi,
    I use hibernate and spring in an application. I migrate from an old application that was previously in pure jdbc connection.
    All unit tests for my DAOs work but I have a problem in a real case that I can't reproduce in unit test (but I can reproduce every time in a real case).

    I know that I freeze in a DAO when I try to do :

    Code:
            getCurrentSession().saveOrUpdate(obj);
    Just before that, I saw in debug mode :

    2007.02.27 22:09:25,625 DEBUG Login Client /127.0.0.1 org.hibernate.impl.SessionImpl opened session at timestamp: 4803012876800000
    2007.02.27 22:09:25,703 DEBUG Login Client /127.0.0.1 org.hibernate.jdbc.JDBCContext opening user JDBC connection, application must close it

    Note that this is only in a second passage, the first one works.

    I have the feelings that I have a problem with session but I'm not sure...

    I use hibernate 3 and spring 2. Transaction are managed by interceptor in spring.xml. There is no open or close session in my code, I let Spring do all this work.

    Any clue ?

  • #2
    Is it possible to see your applicationContext.xml and also explain which beans are getting called? It would also be useful to see more of the log.

    Comment


    • #3
      The application context is attached to the post.

      To explain a little :
      - a user connect to the server, I use the dao to check is user is present in database, I check password. If connection succeed, I use DAO to update last connexion time.
      And now, after the migration with hibernate/spring, the first connexion works, but if I retry, it freeze when I use the DAO to update last connexion time.
      => it always freeze in AccountsDAO

      The code is quite basic :
      Code:
          /**
           * Either save() or update() the given instance, depending upon the value of its
           * identifier property.
           */
          public void saveOrUpdate(Object obj) {
              getSessionFactory().getCurrentSession().saveOrUpdate(obj);
          }

      Here is the log of hibernate and spring in debug mode the first time I login : logFirstTry.txt


      And the second time : logSecondTry.txt

      nothing more after this.

      I think I could try to see with mysqladministrator how many connexion are open but I don't know if would be helpfull.

      Comment


      • #4
        Are you using HibernateDaoSupport with Hibernate? If so you can just call getHibernateTemplate.saveOrUpdate(..) instead. It would be useful to suspend the threads in Eclipse and see where the code is getting stuck. Turning on SQL logging in Hibernate might also give some hints.

        Comment


        • #5
          I extend my DAO from hibernateDAOSupport but I don't use HibernateTemplate as it is recommended by the spring documentation for hibernate3 :

          http://www.springframework.org/docs/...aoSupport.html

          NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can also be coded in plain Hibernate style. Hence, for newly started projects, consider adopting the standard Hibernate3 style of coding data access objects instead, based on SessionFactory.getCurrentSession().
          The log I attached is already in show_sql=true
          Wee see that the second update is not made.

          I have to try to debug in eclipse. It's just hard for the moment to have the application and eclipse on the same machine ^^

          Comment


          • #6
            couple of ideas:

            1. see Hibernate is leaking JDBC connections!

            2. if you have a declarative TX management, and the method where you call saveOrUpdate() is declared as transactional, then you don't realy need to call it, as the hibernate checks for the dirty objects during flushing just before the end of transaction and session. Of course, if the object is not persistant, you'll have to call save( obj ).

            Comment


            • #7
              In point 1. it is a point about session management. But I delegate this problematic to Spring, I don't open or close a session.
              In point 2., I understand the point, but do you think that saveOrUpdate could leak a session if I call it instead of save ? I'm not sure.
              I really have to find a way to debug under eclipse without crashing my machine ^^

              Comment


              • #8
                Looking at the logs, Injecteer's suggestions do seem very possible. It's trying to get a connection but can't and it's therefore hung. I do appreciate what you are saying however and wonder how it can actually get into this position. Debugging it will obviously point to the problem, if eclipse will actually let you do it!

                Comment


                • #9
                  No, point 1 has nothing to do with the session management (at least directly) .
                  I mean, in your context.xml you let hibernate's SF manage the pooling:
                  Code:
                  	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
                  		<property name="hibernateProperties">
                  			<props>
                  			   <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                  			   <prop key="hibernate.show_sql">false</prop>
                  			   <prop key="hibernate.c3p0.min_size">1</prop>
                  			   <prop key="hibernate.c3p0.max_size">20</prop>
                  			   <prop key="hibernate.c3p0.timeout">0</prop>
                  			   <prop key="hibernate.c3p0.max_statement">100</prop>
                  			   <prop key="hibernate.c3p0.idle_test_period">60</prop>
                  instead, I would put it into the dataSource's definition. There's a plenty of setters for that.
                  In my projects in "hibernateProperties" I define only hibernate-specific entries, like dialect, caching etc.

                  Also, I'd disable the pooling at all just to see if there are any differences.

                  Comment


                  • #10
                    That seems like a good idea! If you want to try without connection pooling then go for DriverManagerDataSource. Otherwise the attached link has an example of setting up c3p0 as a dataSource.
                    http://www.springframework.org/docs/...ataSource.html
                    http://forum.springframework.org/showthread.php?t=33166

                    Comment


                    • #11
                      I succeed to reproduce the case in a testCase. So I can run it under eclipse !!

                      I change configuration like said above but it didn't solved the problem.
                      However, I see that my problem is clearly a connexion leak.

                      In applicationContext, I tried :

                      <property name="maxPoolSize"><value>100</value></property>
                      I monitored number of connexion with mysqlAdministrator and I see that I had something like 4 connexion on beginning and it increases to 100. The treatment freez like always on 100 :
                      DEBUG : opening user JDBC connection, application must close it

                      I notice that sometimes hibernate release session :
                      DEBUG Finalizer org.hibernate.jdbc.ConnectionManager running Session.finalize()

                      but it is not enough.

                      I understand the problem, I search the solution now. If you have a clue, I take it ^^

                      Comment


                      • #12
                        If you have managed to reproduce and isolate the problem, it would be useful to see the required code and TestCase.

                        Comment


                        • #13
                          Hi,
                          I tried to delete the maximum that is not related to the test.

                          I let in the zip :
                          the bean : Accounts.java
                          the mapping file
                          the dao
                          the service
                          the manager that implement the login method
                          the test that call 50 times the login method of loginmanager.

                          You need a database and those data :

                          Code:
                          DROP TABLE IF EXISTS `accounts`;
                          CREATE TABLE IF NOT EXISTS `accounts` (
                            `login` varchar(45) NOT NULL default '',
                            `password` varchar(45) default NULL,
                            `lastactive` decimal(20,0) default NULL,
                            `access_level` int(11) default NULL,
                            `lastIP` varchar(20) default NULL,
                            PRIMARY KEY  (`login`)
                          ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
                          
                          
                          
                          INSERT INTO `accounts` (`login`, `password`, `lastactive`, `access_level`, `lastIP`) VALUES ('corwin', 'qUqP5cyxm6YcTAhz05Hph5gvu9M=', '1172698101359', 0, '127.0.0.1'),
                          ('toto', 'qUqP5cyxm6YcTAhz05Hph5gvu9M=', '1172691596546', 0, '127.0.0.1');
                          and you need maven2 to get the dependencies : mvn eclipse:eclipse

                          Comment


                          • #14
                            why don't you put the LoginManager into the appContext.xml as well?
                            I'd also apply TX semantics on the whole loginValid() as well, because all operations there form a single transaction. In this case you don't need to call _service.addOrUpdateAccount(acc).

                            Comment


                            • #15
                              I try to keep some logic from old application when I migrate it. I firstly create DAO, beans and let the manager as it is. But you're right, I can embed it in applicationContext.
                              For the test, I tried to do it, I appli TX semantics to loginValid and remove addOrUpdateAccount but same result.
                              I simplify the method and now, I just have :

                              Code:
                              	/**
                              	 * user name is not case sensitive any more
                              	 * @param user
                              	 * @param password
                              	 * @param address
                              	 * @return
                              	 */
                              	public boolean loginValid(String user, String password)
                              	{
                                      // o find Account
                                      // -------------
                              		Accounts acc = _service.getAccountById(user);
                                      
                                      // If account is not found
                                      // try to create it if AUTO_CREATE_ACCOUNTS is activated
                                      // or return false
                                      // ------------------------------------------------------
                              		if (acc == null)
                              		{
                              			_log.warn("case delete from unit test" );
                              		}
                                      // o account is found
                                      // ---------------------------------------------
                                      else
                                      {
                              			_log.warn("before updating info" );
                              			acc.setLastactive(new BigDecimal(System.currentTimeMillis()));
                                          acc.setLastIp("127.0.0.1");
                                          //_service.addOrUpdateAccount(acc);
                                          _log.warn("after updating info" );
                              		}
                              		return true;
                              	}
                              This is really basic but this test :

                              Code:
                                  public void testConnection() throws IOException
                                  {
                                      for (int i=0;i<50;i++)
                                      {
                                      	System.out.println(i);
                                      	assertTrue(loginManager.loginValid("corwin", "test"));
                                      }
                                  }
                              freeze

                              I really don't understand

                              Comment

                              Working...
                              X