【问题标题】:Hibernate configuring multiple datasources and multiple session factoriesHibernate 配置多个数据源和多个会话工厂
【发布时间】:2013-12-30 18:14:21
【问题描述】:

我正在使用 Spring 和 Hibernate,spring 配置如下。我如何配置两个数据源,会话工厂。事务使用注释进行管理。请指教

<!-- we can use annotations -->
<context:annotation-config/>

<!-- package to look for annotated classes -->
<context:component-scan base-package="com.XXX.XXX.service.impl"/>

<!-- we will manage transactions with annotations -->
<tx:annotation-driven/>


<bean id="transactionManager"   class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<!-- configure hibernate session factory -->

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close" p:driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
    p:url="jdbc:sqlserver://DB_NAME\DB_INSTANCE:DB_PORT;databaseName=DB_NAME;username=DB_USER;password=DB_PASSWORD;" />

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
   <property name="dataSource" ref="dataSource" />
    <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
            <prop key="hibernate.current_session_context_class">thread</prop>
            <prop key="show_sql">false</prop>
        </props>
    </property>

</bean>

【问题讨论】:

    标签: spring hibernate


    【解决方案1】:
    <!-- configure hibernate session factory for FirstDB -->
    
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close" p:driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
        p:url="jdbc:sqlserver://${FirstDB_DB_HosName}\${FirstDB_DB_instanceName}:${FirstDB_DB_PortNumber};databaseName=${FirstDB_DB_DatabaseName};username=${FirstDB_DB_UserName};password=${FirstDB_DB_Password};" />
    
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
       <property name="dataSource" ref="dataSource" />
        <property name="configLocation">
                <value>classpath:hibernate.cfg.xml</value>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
                <prop key="hibernate.current_session_context_class">thread</prop>
                <prop key="show_sql">false</prop>
            </props>
        </property>
    
    </bean>
    
    
     <!-- configure hibernate session factory for SecondDB database -->
    
    <bean id="SecondDBdataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close" p:driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
        p:url="jdbc:sqlserver://${SecondDB_DB_HOST}\${SecondDB_DB_INSTANCE}:${SecondDB_DB_PORT};databaseName=${SecondDB_DB_DATABASENAME};username=${SecondDB_DB_USERNAME};password=${SecondDB_DB_PASSWORD};" />
    
    
     <bean id="secondDBSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
       <property name="dataSource" ref="SecondDBdataSource" />
        <property name="configLocation">
                <value>classpath:hibernate-SecondDB.cfg.xml</value>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
                <prop key="hibernate.current_session_context_class">thread</prop>
                <prop key="show_sql">false</prop>
            </props>
        </property> 
    
    </bean>
    

    在 Hibernate DAO 中,我们可以使用@Qualifier 注解来连接 2 个会话工厂

    /**
     * Basic DAO operations dependent with Hibernate's specific classes
     * @see SessionFactory
     */
    @Transactional(propagation= Propagation.REQUIRED, readOnly=false)
    public class HibernateDao<E, K extends Serializable> implements GenericDao<E, K> {
    
      @Autowired
      @Qualifier(value="sessionFactory")
      private SessionFactory sessionFactory;
    
      @Autowired
      @Qualifier(value="secondDBSessionFactory")
      private SessionFactory secondDBSessionFactory;
    
    
      protected Class<? extends E> daoType;
    
      public HibernateDao() {
        daoType = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass())
                        .getActualTypeArguments()[0];
      }
    
      //Remaining Code
    }
    

    【讨论】:

    • 没有弹簧怎么办?
    • 请注意,两个 SessionFactories/Datasource 将共享相同的事务管理器,除非您也对其进行限定。检查这个link
    【解决方案2】:

    你可以在我的项目中展示这个简单的配置

     <context:component-scan base-package="it.dommy.portmaga" />
    
    <context:property-placeholder location="default.properties" />
    
    <!-- Enable annotation style of managing transactions -->
    <tx:annotation-driven />
    
    <context:annotation-config/>
    
    
    <bean id="dataSource"class="com.mchange.v2.c3p0.ComboPooledDataSource"
          destroy-method="close" >
        <property name="driverClass" value="${db.driverClassName}" />
        <property name="jdbcUrl" value="${db.url}" />
        <property name="user" value="${db.username}" />
        <property name="password" value="${db.password}" />
    </bean>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                <prop key="hibernate.hbm2ddl.auto">create-drop</prop>
                <!--<prop key="hibernate.use_sql_comments">${hibernate.use_sql_comments}</prop>-->
                <!--<prop key="hibernate.validator.apply_to_ddl">${hibernate.validator.apply_to_ddl}</prop>-->
                <!--<prop key="hibernate.max_fetch_depth">${hibernate.max_fetch_depth}</prop>-->
                <!--<prop key="hibernate.default_batch_fetch_size">${hibernate.default_batch_fetch_size}</prop>-->
                <!--<prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</prop>-->
                <!--<prop key="hibernate.validator.autoregister_listeners">true</prop>-->
                <!-- This will drop our existing database and re-create a new one. -->
    
            </props>
        </property>
        <property name="packagesToScan">
            <list>
                <value>it.dommy.portmaga.model.mysql</value>
            </list>
        </property>
    </bean>
    
    <bean id="secondDBdataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
          destroy-method="close">
    <property name="driverClass" value="${dba.driverClassName}" />
    <property name="jdbcUrl" value="${dba.url}" />
    <property name="user" value="${dba.username}" />
    <property name="password" value="${dba.password}" />
    </bean>
    
    <bean id="secondSessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="secondDBdataSource" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.a.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
            </props>
        </property>
        <property name="packagesToScan">
            <list>
                <value>it.dommy.portmaga.model.access</value>
            </list>
        </property>
    </bean>
    
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="secondSessionFactory" />
    
    </bean>
    

    如果您不显示所有项目,请转到此处:https://bitbucket.org/dgabriele/portmaga

    【讨论】:

    • 您好,您这里有一个事务管理器,它引用了一个会话工厂。如何选择另一个会话工厂?我们不需要另一个事务管理器
    【解决方案3】:

    调度程序-servlet.xml

                    <bean id="full-license-db-dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                        <property name="driverClassName" value="${db.driver}" />
                        <property name="url" value="${db.full.url}" />
                        <property name="username" value="${db.full.username}" />
                        <property name="password" value="${db.full.password}" />
                    </bean>
    
                    <bean id="sessionFactoryFull"
                          class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
                        <property name="packagesToScan"       value="ci.xyz.license.model.entity.full"/>  
                        <property name="dataSource" ref="full-license-db-dataSource" />
                        <property name="hibernateProperties">
                            <props>
                                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}    </prop>
                                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                            </props>
                        </property>
                    </bean>
    
    
    
                    <bean id="trial-license-db-dataSource"
                        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                        <property name="driverClassName" value="${db.driver}" />
                        <property name="url" value="${db.trial.url}" />
                        <property name="username" value="${db.trial.username}" />
                        <property name="password" value="${db.trial.password}" />
                    </bean>
    
                    <bean id="sessionFactoryTrial"
                          class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
                        <property name="dataSource" ref="trial-license-db-dataSource" />
                        <property name="packagesToScan" value="ci.xyz.license.model.entity.trial"/>
                        <property name="hibernateProperties">
                            <props>
                                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                            </props>
                        </property>
                    </bean>
    
                    <bean id="transactionManagerTrial"
                           class="org.springframework.orm.hibernate4.HibernateTransactionManager">
                        <property name="sessionFactory" ref="sessionFactoryTrial" />
                    </bean>
                    <bean id="transactionManagerFull"         class="org.springframework.orm.hibernate4.HibernateTransactionManager">
                        <property name="sessionFactory" ref="sessionFactoryFull" />
                    </bean>
                    <tx:annotation-driven transaction-manager="transactionManagerFull" />
                    <tx:annotation-driven transaction-manager="transactionManagerTrial" />
    

    Web.xml

                        <filter>
                            <filter-name>hibernateFilterTrial</filter-name>
                            <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
                            <init-param>
                                <param-name>sessionFactoryBeanName</param-name>
                                <param-value>sessionFactoryTrial</param-value>
                            </init-param>
                        </filter>
                        <filter-mapping>
                            <filter-name>hibernateFilterTrial</filter-name>
                            <url-pattern>/*</url-pattern>
                            <dispatcher>REQUEST</dispatcher>
                            <dispatcher>FORWARD</dispatcher>
                        </filter-mapping>
                                        <filter>
                            <filter-name>hibernateFilterFull</filter-name>
                            <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
                            <init-param>
                                <param-name>sessionFactoryBeanName</param-name>
                                <param-value>sessionFactoryFull</param-value>
                            </init-param>
                        </filter>
                        <filter-mapping>
                            <filter-name>hibernateFilterFull</filter-name>
                            <url-pattern>/*</url-pattern>
                            <dispatcher>REQUEST</dispatcher>
                            <dispatcher>FORWARD</dispatcher>
                        </filter-mapping>
    

    Java 代码快速参考

    @Repository @Scope(BeanDefinition.SCOPE_PROTOTYPE) public abstract class AbstractHibernateDao implements IBaseDao { private static final Log logger = LogFactory.getLog(AbstractHibernateDao.class);

          @Autowired
          protected SessionFactory sessionFactoryFull;
    
          @Autowired
          protected SessionFactory sessionFactoryTrial;
    
    
    
          protected Class<T> persistentClass;
    

    【讨论】:

      【解决方案4】:

      更新了新版本 Hibernate 的答案
      从休眠 5 版本开始,您必须为每个数据源定义事务管理器,但如果您在源代码中使用通用 @Transaction 注释,这会使事务管理器混淆选择哪个,休眠默认情况下采用您的第一个定义事务管理器xml 文件并用于任何代码上的所有 @Transaction 注释。为避免此问题,您需要为代码上的每个 @Transaction 手动定义事务管理器。示例:

        <!-- Step 1: Define First Database DataSource / connection pool -->
      <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
            destroy-method="close">
          <property name="driverClass" value="com.mysql.jdbc.Driver"/>
          <property name="jdbcUrl"
                    value="jdbc:mysql://localhost:3306/spring_security_custom_user_demo?allowPublicKeyRetrieval=true&amp;useSSL=false&amp;serverTimezone=UTC"/>
          <property name="user" value="{user}"/>
          <property name="password" value="{password}"/>
      
          <!-- these are connection pool properties for C3P0 -->
          <property name="minPoolSize" value="4"/>
          <property name="maxPoolSize" value="20"/>
          <property name="maxIdleTime" value="30000"/>
          <property name="initialPoolSize" value="5"/>
      </bean>
      
      <!-- Step 2: Setup Hibernate session factory -->
      <bean id="sessionFactory"
            class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
          <property name="dataSource" ref="myDataSource"/>
          <property name="packagesToScan" value="com.springdemo.entity"/>
          <property name="hibernateProperties">
              <props>
                  <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                  <prop key="hibernate.show_sql">true</prop>
              </props>
          </property>
      </bean>
      
      <!-- Step 3: Setup Hibernate transaction manager -->
      <bean id="myTransactionManager"
            class="org.springframework.orm.hibernate5.HibernateTransactionManager">
          <property name="sessionFactory" ref="sessionFactory"/>
      </bean>
      
      
      <!-- end -->
      
      <!-- Step 1: Define Second Database DataSource / connection pool -->
      <bean id="myDataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource"
            destroy-method="close">
          <property name="driverClass" value="com.mysql.jdbc.Driver"/>
          <property name="jdbcUrl"
                    value="jdbc:mysql://localhost:3306/web_customer_tracker?allowPublicKeyRetrieval=true&amp;useSSL=false&amp;serverTimezone=UTC"/>
          <property name="user" value="{user}"/>
          <property name="password" value="{password}"/>
      
          <!-- these are connection pool properties for C3P0 -->
          <property name="minPoolSize" value="4"/>
          <property name="maxPoolSize" value="20"/>
          <property name="maxIdleTime" value="30000"/>
          <property name="initialPoolSize" value="5"/>
      </bean>
      
      <!-- Step 2: Setup Hibernate session factory -->
      <bean id="sessionFactory2"
            class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
          <property name="dataSource" ref="myDataSource2"/>
          <property name="packagesToScan" value="com.springdemo.entity"/>
          <property name="hibernateProperties">
              <props>
                  <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                  <prop key="hibernate.show_sql">true</prop>
              </props>
          </property>
      </bean>
      
      <!-- Step 3: Setup Hibernate transaction manager -->
      <bean id="myTransactionManager2"
            class="org.springframework.orm.hibernate5.HibernateTransactionManager">
          <property name="sessionFactory" ref="sessionFactory2"/>
      </bean>
      
      <!-- Step 4: Enable configuration of transactional behavior based on annotations -->
      <tx:annotation-driven transaction-manager="myTransactionManager"/>
      <tx:annotation-driven  transaction-manager="myTransactionManager2"/>
      

      这是@Transaction注解示例。

          @Transactional("myTransactionManager")
          public User findByUsername(String username) {
                return userDao.findByUsername(username);
      
        }
      

      如果您需要引用另一个使用另一个数据源的事务管理器。

          @Transactional("myTransactionManager2")
          public User findByUsername(String username) {
                return userDao.findByUsername(username);
      
        }
      

      【讨论】:

        猜你喜欢
        • 2010-09-12
        • 2015-09-01
        • 2016-11-27
        • 1970-01-01
        • 2011-01-06
        • 1970-01-01
        • 1970-01-01
        • 2015-02-07
        • 1970-01-01
        相关资源
        最近更新 更多