Announcement Announcement Module
Collapse
No announcement yet.
new records lost after tomcat stops Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • new records lost after tomcat stops

    Hello,

    i have to adapt a MS Access and a MYSQL database in a spring application with hibernate. Reading from and writing to the database to MYSQL works perfectly and the data is persistent in the database. But the records newly written to the MS Access database get deleted when tomcat stops. While tomcat is running the records are in both databases. When tomcat stops the records in MS Access are deleted. Seems like a transaction gets rolled back. What can i do?

    Here is my hibernate configuration:

    Code:
    <bean id="hibernateSessionFactoryMSAccess"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    
    <property name="mappingResources">
    <list>
    <value>de/kraemerit/msl/repository/Article.hbm.xml</value>
    <value>de/kraemerit/msl/repository/Customer.hbm.xml</value>
    <value>de/kraemerit/msl/repository/Order.hbm.xml</value>
    <value>de/kraemerit/msl/repository/OrderPosition.hbm.xml</value>
    <value>de/kraemerit/msl/repository/TestDomain.hbm.xml</value>
    </list>
    </property>
    
    <!-- <property name="dataSource" ref="dataSourceMySQL" /> -->
    <property name="hibernateProperties">
    <props>
    
    <prop key="hiberante.show_sql">true</prop>
    
    <prop key="hibernate.connection.username" />
    <prop key="hibernate.connection.password" />
    <prop key="hibernate.dialect">com.hxtt.support.hibernate.HxttAccessDialect</prop>
    <prop key="hibernate.connection.url">jdbc:access:///d:/database.mdb?delayedClose=0</prop>
    <prop key="hibernate.connection.driver_class">com.hxtt.sql.access.AccessDriver</prop>
    
    <!-- <prop key="hibernate.show_sql">false</prop> -->
    <prop key="hibernate.format_sql">false</prop>
    <prop key="hibernate.use_sql_comments">false</prop>
    <prop key="hibernate.hbm2ddl.auto">update</prop>
    
    </props>
    </property>
    </bean>
    I have the following openSessionInViewInterceptor:

    Code:
    <bean name="openSessionInViewInterceptorMSAccess"
    		class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
    		<property name="sessionFactory">
    			<ref bean="hibernateSessionFactoryMSAccess" />
    		</property>
    		<property name="flushModeName">
    			<value>FLUSH_AUTO</value>
    		</property>
    	</bean>
    The openSessionInViewInterceptor is used in the handlerMapping Bean:

    Code:
    <bean id="handlerMapping"
    		class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    		<property name="interceptors">
    			<list>
    
    				<!--<ref bean="signonInterceptor" />-->
    				<ref bean="openSessionInViewInterceptorMySql" />
    				<ref bean="openSessionInViewInterceptorMSAccess" />
    
    				<!--
    					ensures that the hibernate session is available lazy fetching of
    					fields in the view
    				-->
    
    			</list>
    		</property>
    		<property name="urlMap">
    			<map>
    
    				<entry key="/articlegroup.action">
    					<ref local="articleGroupController" />
    				</entry>
    
    				<entry key="/article.action">
    					<ref local="articleController" />
    				</entry>
    
    
    				<entry key="/order.action">
    					<ref local="orderController" />
    				</entry>
    
    			</map>
    
    		</property>
    		
    	</bean>

  • #2
    Judging from your configuration, there is no transaction setup hence no transactions. The fact that it works in MySQL is probably due to the fact that you use MyISAM tables which are non-transactional.

    Comment


    • #3
      Hello Marten,

      thank you for your reply. I have transaction-managers for mysql and ms access. Mysql tables are innoDB. Do you have another idea?

      Code:
      <!-- A transaction manager for working with Hibernate SessionFactories -->
      	<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
      		<property name="sessionFactory" ref="hibernateSessionFactoryMySql"/>
      	</bean>
      	
      	<bean id="transactionManagerMSAccess" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
      		<property name="sessionFactory" ref="hibernateSessionFactoryMSAccess"/>
      	</bean>

      Comment


      • #4
        Do you need to write to the same database in 1 transaction? If that is the case you are probably going to need a JtaTransactionManager it they are both needed in the same transaction that is.

        Comment


        • #5
          I believe that i am writing only to one database in one transaction.

          The requests are coming via ajax. With each ajax request i only update/insert/select to one database. I use MultiActionController.

          Code:
          <bean id="articleController"
          		class="org.springframework.web.servlet.mvc.multiaction.MultiActionController">
          		<property name="methodNameResolver" ref="methodNameResolver" />
          		<property name="delegate">
          			<bean class="de.kraemerit.msl.web.controller.ArticleController" />
          		</property>
          	</bean>
          As i understand it, a mysql transaction and a ms access transaction is opened from the handlerMapping-bean with each request, because it calls the interceptors and closes them when the response is sent.

          Code:
          <bean id="handlerMapping"
          		class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
          		<property name="interceptors">
          			<list>
          
          				<!--<ref bean="signonInterceptor" />-->
          				<ref bean="openSessionInViewInterceptorMySql" />
          				<ref bean="openSessionInViewInterceptorMSAccess" />
          
          				<!--
          					ensures that the hibernate session is available lazy fetching of
          					fields in the view
          				-->
          
          			</list>
          		</property>
          		<property name="urlMap">
          			<map>
          
          				<entry key="/articlegroup.action">
          					<ref local="articleGroupController" />
          				</entry>
          
          				<entry key="/article.action">
          					<ref local="articleController" />
          				</entry>
          
          
          				<entry key="/order.action">
          					<ref local="orderController" />
          				</entry>
          
          			</map>
          
          		</property>
          		
          	</bean>
          The interceptors are looking like this:

          Code:
          <!-- needed to sustain hibernate session -->
          	<bean name="openSessionInViewInterceptorMySql"
          		class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
          		<property name="sessionFactory">
          			<ref bean="hibernateSessionFactoryMySql" />
          		</property>
          		<property name="flushModeName">
          			<value>FLUSH_AUTO</value>
          		</property>
          	</bean>
          
          	<bean name="openSessionInViewInterceptorMSAccess"
          		class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
          		<property name="sessionFactory">
          			<ref bean="hibernateSessionFactoryMSAccess" />
          		</property>
          		<property name="flushModeName">
          			<value>FLUSH_AUTO</value>
          		</property>
          	</bean>
          Am i right with one transaction for each database in every request?
          Last edited by springexplorer; May 18th, 2011, 06:04 AM.

          Comment


          • #6
            Your understanding is wrong... The fact that there is a session doesn't mean there is a transaction session != transaction... You can have multiple transaction with one session. You have a transactionamanger (multiple actually) but that is not enough to drive/enable transactions. I suggest a read of the transaction chapter of the reference guide.

            Comment


            • #7
              Thanks for the explanation.

              I misinterpreted the opening of a transaction. I use the skeleton-application of our company and overlooked that there are @transactional annotations in the manager classes. Therefore it is clear that the transaction only starts when one of the @transactional-methods is entered.

              The manager class that makes the inserts and updates to the ms access database is annotated with @transactional too. Therefore it should open a transaction and should close it when the method is left. In such an annotated method there are calls to hibernaterepository like this one:

              Code:
              package de.kraemerit.msl.repository;
              
              import java.util.List;
              
              import org.hibernate.Session;
              import org.hibernate.SessionFactory;
              import org.springframework.beans.factory.annotation.Autowired;
              import org.springframework.beans.factory.annotation.Qualifier;
              
              import de.kraemerit.msl.domain.Article;
              import de.kraemerit.msl.domain.Unit;
              
              public class HibernateArticleRepository implements ArticleRepository {
              
              	@Autowired
              	@Qualifier("hibernateSessionFactoryMSAccess")
              	private SessionFactory sessionFactory;
              
              	public HibernateArticleRepository() {
              		//this.sessionFactory = sessionFactory;
              	}
              	
              	@Override
              	public Article getById(Long id) {
              		return (Article) getCurrentSession().createQuery("Select a From Article a where a.id = ?").setLong(0, id).uniqueResult();
              	}
              
              	@Override
              	public Article getByShortDescription(String shortDescription) {
              		return (Article) getCurrentSession().createQuery("Select a From Article a where a.shortDescription = ?").setString(0, shortDescription).uniqueResult();
              	}
              
              	@Override
              	public void update(Article article) {
              		getCurrentSession().saveOrUpdate(article);
              	}
              
              	public void delete(Article article) {
              		getCurrentSession().delete(article);
              	}
              
              	@Override
              	public List<Article> getAll(Boolean isValid, Integer start, Integer limit) {
              		return getCurrentSession().createQuery("Select a From Article a where a.isValid = ? order by a.shortDescription").setBoolean(0, isValid).setFirstResult(start).setMaxResults(limit).list();
              	}
              	
              	public Long getCountAll(Boolean isValid) {
              		return (Long)getCurrentSession().createQuery("Select count(a) From Article a where a.isValid = ?").setBoolean(0, isValid).uniqueResult();
              	}
              	
              	@Override
              	public List<Article> getAllMsl() {
              		return getCurrentSession().createQuery("Select a From Article a where a.isValid = true order by a.shortDescription").list();
              	}
              
              	protected Session getCurrentSession() {
              		return sessionFactory.getCurrentSession();
              	}
              
              }

              With mysql i do it the same way. With mysql the records stay persistent in the database.

              Comment


              • #8
                i have the same transactional annotation for the manager classes for mysql AND for ms access.

                Code:
                @Transactional
                public class OrderManager {
                ...
                ...
                ...
                Do i have to a add a qualifier so that the right transaction manager gets choosed?

                Comment


                • #9
                  Do i have to a add a qualifier so that the right transaction manager gets choosed?
                  Yes you need to specify the tx manager as specified in the transactional section of the reference guide. Else it uses the default one, which probably is the mysql one, if you change something in the ms access database it isn't of much use to commit the tx of the mysql database (at least it does nothing for the ms access one).

                  Comment


                  • #10
                    The qualifier could be the solution.

                    When i add a qualifier to the @transactional annotation

                    e.g @Transactional("transactionManagerMySql")

                    i get the following error: "he attribute value is undefined for the annotation type Transactional"

                    I use spring 2.5.4 (org.springframework.transaction-2.5.4.A.jar). Do i have to update to spring 3.0?

                    Comment


                    • #11
                      Spring before 3.0 isn't usable with multiple transactionmanagers (at least not in a declarative way). Either switch to spring 3 or drop declarative transaction management and do everything by hand (you can wrap the specified calls in a TransactionTemplate). IMO the easiest would be to upgrade to spring 3, but I'm not sure if that is a viable solution (at the moment) for you, that is for you to decide...

                      Comment


                      • #12
                        Thank you very much for your help!

                        Comment


                        • #13
                          Hello Marten,

                          it works now with a little extension.

                          I have upgraded to Spring3 and use the qualifier with the name of the transactionmanager. But i had to flush the session after each update or insert. Without the flushing the records were deleted again as without a transactionManager (or the false one) when i normally stopped tomcat. After stopping the following lines were logged:

                          Code:
                          INFO : org.hibernate.impl.SessionFactoryImpl.close(SessionFactoryImpl.java:769) - closing
                          INFO : org.hibernate.connection.DriverManagerConnectionProvider.close(DriverManagerConnectionProvider.java:147) - cleaning up connection pool: jdbc:access:///d:/database.mdb?delayedClose=0
                          INFO : org.hibernate.impl.SessionFactoryImpl.close(SessionFactoryImpl.java:769) - closing
                          After that the records were deleted. When i terminated (not stopping) tomcat then the records were persistent. Therefore I had to add the flushing after eache insert/update:

                          Code:
                          package de.kraemerit.msl.repository;
                          
                          import java.util.List;
                          
                          import org.hibernate.Session;
                          import org.hibernate.SessionFactory;
                          import org.springframework.beans.factory.annotation.Autowired;
                          import org.springframework.beans.factory.annotation.Qualifier;
                          
                          import de.kraemerit.msl.domain.Article;
                          import de.kraemerit.msl.domain.Unit;
                          
                          public class HibernateArticleRepository implements ArticleRepository {
                          
                          	@Autowired
                          	@Qualifier("hibernateSessionFactoryMSAccess")
                          	private SessionFactory sessionFactory;
                          
                          	public HibernateArticleRepository() {
                          		//this.sessionFactory = sessionFactory;
                          	}
                          	
                          	@Override
                          	public Article getById(Long id) {
                          		return (Article) getCurrentSession().createQuery("Select a From Article a where a.id = ?").setLong(0, id).uniqueResult();
                          	}
                          
                          	@Override
                          	public Article getByShortDescription(String shortDescription) {
                          		return (Article) getCurrentSession().createQuery("Select a From Article a where a.shortDescription = ?").setString(0, shortDescription).uniqueResult();
                          	}
                          
                          	@Override
                          	public void update(Article article) {
                          		getCurrentSession().saveOrUpdate(article);
                          		getCurrentSession().flush();
                          	}
                          
                          	public void delete(Article article) {
                          		getCurrentSession().delete(article);
                          		getCurrentSession().flush();
                          	}
                          
                          	@Override
                          	public List<Article> getAll(Boolean isValid, Integer start, Integer limit) {
                          		return getCurrentSession().createQuery("Select a From Article a where a.isValid = ? order by a.shortDescription").setBoolean(0, isValid).setFirstResult(start).setMaxResults(limit).list();
                          	}
                          	
                          	public Long getCountAll(Boolean isValid) {
                          		return (Long)getCurrentSession().createQuery("Select count(a) From Article a where a.isValid = ?").setBoolean(0, isValid).uniqueResult();
                          	}
                          	
                          	@Override
                          	public List<Article> getAllMsl() {
                          		return getCurrentSession().createQuery("Select a From Article a where a.isValid = true order by a.shortDescription").list();
                          	}
                          
                          	protected Session getCurrentSession() {
                          		return sessionFactory.getCurrentSession();
                          	}
                          
                          }
                          Do you have an idea why the flushing is needed with ms access while with mysql is not?

                          Comment


                          • #14
                            springexplorer

                            Here is an ORM that works with Microsoft Access
                            https://www.kellermansoftware.com/p-...ess-layer.aspx

                            Comment

                            Working...
                            X