Announcement Announcement Module
Collapse
No announcement yet.
JdbcDaoSupport and HibernateDaoSupport in single class Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • JdbcDaoSupport and HibernateDaoSupport in single class

    Spring have HibernateDaoSupport and JdbcDaoSupport, when each of
    its has HibernateTemplate and JdbcTemplate accordingly.
    I have question: how I can use JdbcTemplate in HibernateDaoSupport and HibernateTemplate in JdbcDaoSupport?
    Thanx.

  • #2
    Hi sinnus,

    If you write a DAO that extends HibernateDaoSupport but you also want to perform some JdbcTemplate actions in it, simply add a JdbcTemplate property to your DAO, and inject the DAO with a JdbcTemplate. However, be sure to configure the JdbcTemplate with the same DataSource that your injected SessionFactory was set to use.

    HibernateAndJdbcAttributeDao class (which uses HibernateTemplate and JdbcTemplate):
    Code:
    package org.spring.forum.dao;
    
    import java.util.List;
    
    import org.spring.forum.domain.Attribute;
    import org.springframework.dao.DataAccessException;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
    
    public class HibernateAndJdbcAttributeDao extends HibernateDaoSupport implements AttributeDao {
    
      /* Used for direct Jdbc querying. */
      private JdbcTemplate jdbcTemplate;
    	
      /* Setter method for injection via Spring. */
      public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
      }
    
      /*
       * Uses the JdbcTemplate instance rather than HibernateTemplate. The
       * JdbcTemplate is configured with the same DataSource provided Hibernate.
       */
      public List getAttributes() throws DataAccessException {
        /*
         * Returns a List where each entry is a Map with each entry in the map
         * representing the column value for that row. See JdbcTemplate for more
         * information.
         */
        List rows = this.jdbcTemplate.queryForList("select * from Attributes");
        return rows;
      }
    	
      /* However, you can use the HibernateTemplate for other DAO operations. */
      public Attribute getAttribute(String attributeId) throws DataAccessException {
        return (Attribute)getHibernateTemplate().get(Attribute.class, attributeId);
      }
    
    }
    ApplicationContext.xml file:
    Code:
    <beans>
    
      <!-- define single datasource bean here like normal -->
      <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
      </bean>
    
      <!--  configure Hibernate SessionFactory with above defined datasource -->
      <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--  define all other properties here like normal -->
      </bean>
    
      <!--  configure JdbcTemplate with the same datasource -->
      <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
      </bean>
    
      <bean id="attributeDao" class="org.spring.forum.dao.HibernateAndJdbcAttributeDao">
        <!--  provide the sessionFactory like normal -->
        <property name="sessionFactory" ref="sessionFactory" />
    
        <!-- in addition, provide configured jdbcTemplate for jdbc access -->
        <property name="jdbcTemplate" ref="jdbcTemplate" />
      </bean>
    
    </beans>
    And of course, you could inject a SessionFactory into a DAO that extends JdbcDaoSupport to perform HibernateTemplate actions.

    Hope this helps!

    -Arthur Loder

    Comment


    • #3
      OK.
      But when I use TransactionProxyFactoryBean:

      Code:
        <bean id="JDBCDAO"
      class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
          <property name="transactionManager" ref="transactionManager" />
          <property name="target" ref="JDBCDAOTarget" />
          <property name="transactionAttributes">
            <props>
              <prop key="*">PROPAGATION_REQUIRED,-Exception</prop>
            </props>
          </property>
        </bean>
      changes which performed by jdbctemplate are not rollbacked, but changes of
      hibernatetemplate are rollbacked...

      Code:
              log.debug("*********************************** before");
              ProductCategory productCategory1 = new ProductCategory();
              productCategory1.setName("Name 1");
      
      // will be rollbacked after exception
              productDAO.addProductCategory(productCategory1);
      
              getHibernateTemplate().flush();
      
      // will not be rollbacked after exception
              getJdbcTemplate()
                      .execute(
                              "insert into product_category(id, name) values "
                                      + "((select next value for hibernate_sequence from dual_hibernate_sequence), "
                                      + "'xxx')");
              //        getJdbcTemplate().execute("delete from product_category");
      
              ProductCategory productCategory2 = new ProductCategory();
              productCategory2.setName("Name 2");
      // will be rollbacked after exception
              productDAO.addProductCategory(productCategory2);
      
              getHibernateTemplate().flush();
      
              if (true)
                  throw new RuntimeException("Runtime exception");
      What I make wrong?
      Thanx.

      Comment


      • #4
        Another version of the same thing
        Code:
        public class MyDao extends HibernateDaoSupport {
            private MyJdbcDao innerDao;
            public MyDao() {
                innerDao = new MyJdbcDao();
            }
            public void update(MyDomainObject obj) {
                // use Hibernate to persist the data
            }
            public MyDomainObject getById(int someId) {
                return innerDao.getBy(someId);
            }
            // do using JDBC
            private static class MyJdbcDao extends JdbcDaoSupport {
                
                public MyDomainObject getBy(int someId) {
                    // do some real processing
                    return null;
                }
            }
        }

        Comment


        • #5
          Set DataSource/JdbcTemplate?

          Hi Arno,

          I have a question regarding your posted code (I'm just repeating the static inner class):
          Code:
          private static class MyJdbcDao extends JdbcDaoSupport {
                  
            public MyDomainObject getBy(int someId) {
              // do some real processing
              return null;
            }
          }
          Don't you need to provide the MyJdbcDao class with a DataSource or JdbcTemplate in order to do the jdbc-based operations? That is why I injected a JdbcTemplate directly into the HibernateDaoSupport subclass.

          I know this doesn't solve sinnus's new issue, but I am just curious...

          -Arthur Loder

          Comment


          • #6
            Mixing DataSource/Hibernate TransactionManagers

            Hi sinnus,

            I have not worked much with Spring's transaction support, so I'm just throwing this out as a possibility (I'm probably in over my head).

            The DataSourceTransactionManager class, which can be used to manage transactions for code that accesses a single database via JDBC, uses the DataSourceUtils class to obtain/close connections. Because JdbcTemplate uses the DataSourceUtils class for obtaining connections, data access using JdbcTemplate can participate in a Spring-managed transaction if the DataSourceTransactionManager is used.

            The HibernateTransactionManager, which can be used to manage transactions for a locally defined SessionFactory, uses the SessionFactoryUtils class to obtain/close Sessions. Because HibernateTemplate use the SessionFactoryUtils class for obtaining Sessions, data access using HibernateTemplate can participate in a Spring-managed transaction if the HibernateTransactionManager is used.

            I'm not sure, but is the issue that you just cannot mix the two? Did you configure a HibernateTransactionManager as the "transactionManager" property of your "JDBCDAO" bean? If so, maybe that explains why the HibernateTemplate-based code gets rolled-back, and the JdbcTemplate-based code does not.

            Another related issue is the Hibernate cache. If you were performing read-only access via the JdbcTemplate, then I think you would be okay. However, I don't think Hibernate will know about the updates to the database that you achieve via the JdbcTemplate. In addition, if you are performing read-only access via the JdbcTemplate, then you wouldn't have any operations to roll back.

            I'm sure this is a common scenario that someone else can give a more definitive answer to.

            So I wonder, as a test, if you switch the "transactionManager" bean to use the DataSourceTransactionManager class, will the HibernateTemplate operations not get rolled back instead?

            I have personally never mixed HibernateTemplate operations with JdbcTemplate, so I can't really help...

            -Arthur Loder
            Last edited by Arthur Loder; Aug 17th, 2006, 05:27 PM.

            Comment


            • #7
              Originally posted by Arthur Loder
              Don't you need to provide the MyJdbcDao class with a DataSource or JdbcTemplate in order to do the jdbc-based operations? That is why I injected a JdbcTemplate directly into the HibernateDaoSupport subclass
              Yes, in a full implementation I have to provide at least datasource or the jdbc template, otherwise how we could create a template.
              My post is just a skeleton to illustrate an idea of modularizing JDBC specific access to data from Hibernate mechanism.

              Comment


              • #8
                Originally posted by Arthur Loder
                I'm not sure, but is the issue that you just cannot mix the two?
                I've made a run of mixing in transaction management hibernate dao support with jdbc template.
                Config
                Code:
                <beans>
                ...
                <bean
                        id="transactionServiceBean"
                        parent="transactionProxy">
                        <property
                            name="proxyInterfaces"
                            value="&serviceRemote;" />
                        <property
                            name="target"
                            ref="serviceBean" />
                    </bean>
                    <bean
                        id="serviceBean"
                        class="&serviceBean;">
                        <property
                            name="personDao"
                            ref="personDao" />
                        <property
                            name="catDao"
                            ref="catDao" />
                    </bean>
                    <bean
                        id="transactionProxy"
                        class="&TransactionProxyFactoryBean;"
                        abstract="true">
                        <property name="transactionManager">
                            <bean
                                class="&HibernateTransactionManager;"
                                parent="abstractSessionFactoryHost" />
                        </property>
                        <property name="transactionAttributes">
                            <props>
                                <prop key="create*">PROPAGATION_REQUIRED</prop>
                                <prop key="update*">PROPAGATION_REQUIRED</prop>
                                <prop key="delete*">
                                    PROPAGATION_REQUIRED,+ArrayIndexOutOfBoundsException
                                </prop>
                            </props>
                        </property>
                    </bean>
                    <bean
                        id="catDao"
                        class="&catDaoImpl;"
                        parent="baseDao">
                        <property name="dataSource">
                            <bean class="&jndiObjectFactoryBean;">
                                <property
                                    name="jndiName"
                                    value="&dataSourceJndiName;" />
                            </bean>
                        </property>
                    </bean>
                
                <bean
                        id="baseDao"
                        class="&baseDaoImpl;"
                        abstract="true">
                        <property
                            name="helper"
                            ref="springHelper" />
                    </bean>
                ...
                </beans>
                service layer proxied on delete and throwing ArrayIndexOutOfBoundsException
                Code:
                ...
                public void deleteAllCats() {
                        catDao.deleteAll();
                        throw new ArrayIndexOutOfBoundsException("Wow!!!");
                    }
                ...
                Dao layer based on hibernate template yet using jdbc as well (helper extends HibernateDaoSupport )
                Code:
                public class CatDaoImpl extends BaseDaoTemplate implements CatDao {
                ...
                public void create(Object param) {
                        helper.save((Cat) param);
                    }
                
                public void deleteAll() {
                        innerDao.deleteAllCats();
                    }
                ...
                private JdbcDao innerDao = new JdbcDao();
                    public void setDataSource(DataSource dataSource) {
                        innerDao.setDataSource(dataSource);
                    }
                    private static class JdbcDao extends JdbcDaoSupport {
                        public void deleteAllCats() {
                            getJdbcTemplate().execute("delete from cat");
                        }
                    }
                }
                Works like a charm. If +ArrayIndexOutOfBoundsException all cats are gone - no rollback.
                If -ArrayIndexOutOfBoundsException - delete rolled back and all my cats stay where they are.
                Love Spring. Love cats.

                Comment


                • #9
                  I have made test for the issue.
                  Please, look into attachment.
                  What I make wrong?
                  Thanx.
                  Last edited by sinnus; Aug 18th, 2006, 07:16 AM.

                  Comment


                  • #10
                    Up! Up! Up!

                    Comment


                    • #11
                      Maybe you need to specify WHAT is going wrong.

                      Comment


                      • #12
                        Originally posted by mdeinum
                        Maybe you need to specify WHAT is going wrong.
                        I have method of class extended from HibernateDaoSupport:
                        Code:
                            public void createAndDelete() {
                                log.debug("*********************************** before");
                        
                                Product productCategory1 = new Product();
                                productCategory1.setName("Name 1");
                                getHibernateTemplate().save(productCategory1);
                        
                                getHibernateTemplate().flush();
                        
                                getJdbcTemplate()
                                        .execute(
                                                "insert into product(id, name) values "
                                                        + "((select next value for hibernate_sequence from dual_hibernate_sequence), "
                                                        + "'xxx')");
                        
                                Product productCategory2 = new Product();
                                productCategory2.setName("Name 2");
                                getHibernateTemplate().save(productCategory2);
                        
                                getHibernateTemplate().flush();
                        
                                if (true)
                                    throw new RuntimeException("Runtime exception");
                                log.debug("*********************************** after");
                            }
                        When exception occures, changes was maded by JdbcTemplate did not rolled-back, but must.
                        Last edited by sinnus; Aug 22nd, 2006, 05:27 AM.

                        Comment


                        • #13
                          When I change getProductCount on:

                          Code:
                              public int getProductCount() {
                                  int productCount;
                                  try {
                                      getJdbcTemplate().getDataSource().getConnection().commit();
                                  } catch (SQLException e) {
                                      // TODO Auto-generated catch block
                                      e.printStackTrace();
                                  }
                          
                                  productCount = getJdbcTemplate().queryForInt("select count(*) from product");
                                  log.info("Product count: " + productCount);
                                  return productCount;
                              }
                          getProductCount has returned zero...
                          I think, that transaction after execute method createAndDelete has not been commited. Why?

                          Comment


                          • #14
                            DataSourceUtils.getConnection

                            Originally posted by sinnus
                            When I change getProductCount on:

                            Code:
                                public int getProductCount() {
                                    int productCount;
                                    try {
                                        getJdbcTemplate().getDataSource().getConnection().commit();
                                    } catch (SQLException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                    }
                            
                                    productCount = getJdbcTemplate().queryForInt("select count(*) from product");
                                    log.info("Product count: " + productCount);
                                    return productCount;
                                }
                            getProductCount has returned zero...
                            I think, that transaction after execute method createAndDelete has not been commited. Why?
                            I would be careful with the following code from above:
                            Code:
                            getJdbcTemplate().getDataSource().getConnection().commit();
                            I don't think you should work with a Connection object directly. When using the JdbcTemplate, connections are obtained (transparently) via the DataSourceUtils.getConnection method, and this allows for Spring's transaction support.

                            -Arthur Loder

                            Comment


                            • #15
                              Originally posted by Arthur Loder
                              I would be careful with the following code from above:
                              Code:
                              getJdbcTemplate().getDataSource().getConnection().commit();
                              I don't think you should work with a Connection object directly. When using the JdbcTemplate, connections are obtained (transparently) via the DataSourceUtils.getConnection method, and this allows for Spring's transaction support.

                              -Arthur Loder
                              Yes, i agree with your advice.
                              But when i change spring 1.2.4 to spring 1.2.8 the bug not are reproducing...
                              I think it spring's 1.2.4 bug.
                              I am looking changelist...

                              Comment

                              Working...
                              X