【问题标题】:How can I set Datasource when I'm creating Hibernate SessionFactory?创建 Hibernate SessionFactory 时如何设置数据源?
【发布时间】:2011-05-23 08:36:16
【问题描述】:

我正在创建 SessionFactory,并且我在创建 SessionFactory 的代码中将数据源作为对象,但我无法将数据源设置为 Hibernate Configuration 对象。那么如何将我的数据源设置为我的 SessionFactory?

Configuration configuration = new Configuration();
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect");
configuration.setProperties(properties);
configuration.setProperty("packagesToScan", "com.my.app");
SessionFactory sessionFactory = configuration.configure().buildSessionFactory();

【问题讨论】:

    标签: java hibernate sessionfactory


    【解决方案1】:

    要为 Session 提供 JDBC 连接,您需要实现 ConnectionProvider

    默认情况下,Hibernate 使用 DatasourceConnectionProvider,它从 JNDI 获取 DataSource 实例。

    要使用自定义DataSource 实例,请使用InjectedDataSourceConnectionProvider 并将DataSource 实例注入其中。

    InjectedDataSourceConnectionProvider有TODO注释

    注意: setDataSource(javax.sql.DataSource) 必须在之前调用 配置(java.util.Properties)。

    TODO : 找不到在哪里 setDataSource 实际上是被调用的。 这不能只是传递给 配置???

    按照说明,从configure()方法调用setDataSource()方法。

    public class CustomConnectionProvider extends InjectedDataSourceConnectionProvider {
        @Override
        public void configure(Properties props) throws HibernateException {
            org.apache.commons.dbcp.BasicDataSource dataSource = new BasicDataSource();
            org.apache.commons.beanutils.BeanUtils.populate( dataSource, props );
            setDataSource(dataSource);
    
            super.configure(props);
        }
    }
    

    您也可以扩展UserSuppliedConnectionProvider

    根据ConnectionProvider的约定

    实施者应该提供一个公共的 默认构造函数。

    如果通过 Configuration 实例设置了自定义 ConnectionProvider,Hibernate 将调用此构造函数。

    Configuration cfg = new Configuration();
    Properties props = new Properties();
    props.put( Environment.CONNECTION_PROVIDER, InjectedDataSourceConnectionProvider.class.getName() );
    cfg.addProperties(props);
    

    【讨论】:

      【解决方案2】:

      我使用 LocalContainerEntityManagerFactoryBean 在配置类创建 EntityManagerFactory 实例。

      如果需要设置另一个数据源,则可以在运行时使用实体管理器工厂实例对其进行更新:

      @Service("myService")
      public class MyService
      {
      ....
          @Autowired
          private LocalContainerEntityManagerFactoryBean emf;
      ....
          public void replaceDataSource(DataSource dataSource)
          {
              emf.setDataSource(dataSource);
              emf.afterPropertiesSet();
          }
      ....
      }
      

      它适用于 Hibernate 5.2.9 Final。

      【讨论】:

        【解决方案3】:

        Luiggi Mendoza 的回答是为什么我的搜索将我发送到这里,但我认为我应该提供我的版本,因为我花了很多时间四处寻找如何做到这一点 - 它使用 Spring 内存数据库进行测试,一个 SessionContext 和 hbm.xml 以防你不使用注释:

        /**
         * Instantiates a H2 embedded database and the Hibernate session.
         */
        public abstract class HibernateTestBase {
        
            private static EmbeddedDatabase dataSource;
            private static SessionFactory sessionFactory;
            private Session session;
        
            @BeforeClass
            public static void setupClass() {
                dataSource = new EmbeddedDatabaseBuilder().
                        setType(EmbeddedDatabaseType.H2).
                        addScript("file:SQLResources/schema-1.1.sql").
                        addScript("file:SQLResources/schema-1.2.sql").
                        build();
                Configuration configuration = new Configuration();
                configuration.addResource("hibernate-mappings/Cat.hbm.xml");
                configuration.setProperty("hibernate.dialect",
                        "org.hibernate.dialect.Oracle10gDialect");
                configuration.setProperty("hibernate.show_sql", "true");
                configuration.setProperty("hibernate.current_session_context_class",
                        "org.hibernate.context.internal.ThreadLocalSessionContext");
                StandardServiceRegistryBuilder serviceRegistryBuilder =
                        new StandardServiceRegistryBuilder();
                serviceRegistryBuilder.applySetting(Environment.DATASOURCE, dataSource);
                serviceRegistryBuilder.applySettings(configuration.getProperties());
                StandardServiceRegistry serviceRegistry =
                        serviceRegistryBuilder.build();
                sessionFactory = configuration.buildSessionFactory(serviceRegistry);
                sessionFactory.openSession();
            }
        
            @AfterClass
            public static void tearDown() {
                if (sessionFactory != null) {
                    sessionFactory.close();
                }
                if (dataSource != null) {
                    dataSource.shutdown();
                }
            }
        
            @Before
            public final void startTransaction() {
                session = sessionFactory.getCurrentSession();
                session.beginTransaction();
            }
        
            @After
            public final void rollBack() {
                session.flush();
                Transaction transaction = session.getTransaction();
                transaction.rollback();
            }
        
            public Session getSession() {
                return session;
            }
        
        }
        

        你需要这些:

        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>4.1.6.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>com.h2database</groupId>
          <artifactId>h2</artifactId>
          <version>1.4.184</version>
          <scope>test</scope>
        </dependency>
        

        【讨论】:

          【解决方案4】:

          如果你用javax.sql.DataSource实现了一个类,可以通过配置属性来设置Hibernate的DataSource

          import javax.sql.DataSource;
          public class HibernateDataSource implements DataSource {
              ...
          }
          
          
          import org.hibernate.cfg.Configuration;
          import org.hibernate.cfg.Environment;
          public class MyHibernateCfg {
              public void initialize() {
                  HibernateDataSource myDataSource = new HibernateDataSource();
                  Configuration cfg = new Configuration();
                  // this is how to configure hibernate datasource
                  cfg.getProperties().put(Environment.DATASOURCE, myDataSource);
                  ...
              }
          }
          
          
          import org.hibernate.cfg.Configuration;
          import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
          import org.hibernate.service.ServiceRegistry;
          import org.hibernate.SessionFactory;
          import org.hibernate.Session;
          public class TableClass {
              public void initialize() {
                  MyHibernateCfg cfg = new MyHibernateCfg();
                  Configuration conf = cfg.getCfg();
                  ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(conf.getProperties()).build();
                  SessionFactory sessionFactory = conf.buildSessionFactory(serviceRegistry);
                  Session sessionFactory.openSession();
                  ...
              }
          }
          

          【讨论】:

            【解决方案5】:

            如果您碰巧将您的DataSource 存储在 JNDI 中,那么只需使用:

            configuration.setProperty(
                "hibernate.connection.datasource",
                "java:comp/env/jdbc/yourDataSource");
            

            但是,如果您使用像 Apache DBCP 或 BoneCP 这样的自定义数据源提供程序,并且您不想使用像 Spring 这样的依赖注入框架,那么您可以在 StandardServiceRegistryBuilder 之前将其注入创建SessionFactory:

            //retrieve your DataSource
            DataSource dataSource = ...;
            Configuration configuration = new Configuration()
                .configure();
            //create the SessionFactory from configuration
            SessionFactory sf = configuration
                .buildSessionFactory(
                    new StandardServiceRegistryBuilder()
                        .applySettings(configuration.getProperties())
                        //here you apply the custom dataSource
                        .applySetting(Environment.DATASOURCE, dataSource)
                        .build());
            

            请注意,如果您使用这种方法,则无需再将连接参数放在您的 hibernate.cfg.xml 中。这是使用上述方法时兼容的 hibernate.cfg.xml 文件的示例:

            <?xml version="1.0" encoding="UTF-8"?>
            <!DOCTYPE hibernate-configuration PUBLIC
                    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
                    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
            <hibernate-configuration>
            
                <session-factory>
                    <property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
                    <property name="show_sql">false</property>
                    <!-- your mappings to classes go here -->
                </session-factory>
            </hibernate-configuration>
            

            以上代码在 Hibernate 4.3 上测试。

            【讨论】:

            • @PeterRader 这就是我正在使用的:.applySetting(Environment.DATASOURCE, dataSource)
            【解决方案6】:

            如果您使用的是 Spring 框架,则使用 LocalSessionFactoryBean 将数据源注入 Hibernate SessionFactory。

            <beans>
                <bean id="YourClass"
                    class="com.YourClass.
                    <property name="sessionFactory">
                        <ref bean="DbSessionFactory" />
                    </property>     
                </bean>
            
            
                <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
                    <property name="driverClassName">
                        <value>org.postgresql.Driver</value>
                    </property>
                    <property name="url">
                        <value>jdbc:postgresql://localhost/yourdb</value>
                    </property>
                    <property name="username">
                        <value>postgres</value>
                    </property>
                    <property name="password">
                        <value>postgres</value>
                    </property>     
                </bean>
            
                <bean id="DbSessionFactory"
                    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
                    <property name="dataSource">
                        <ref local="dataSource"/>
                    </property>     
                    <property name="mappingResources">
                        <list>
                            <value>conf/hibernate/UserMapping.hbm.xml</value>               
                        </list>
                    </property>
                    <property name="hibernateProperties">
                        <props>
                            <prop key="hibernate.dialect"> org.hibernate.dialect.PostgreSQLDialect </prop>      
                            <prop key="hibernate.hbm2ddl.auto">update</prop>
                            <prop key="hibernate.cache.use_second_level_cache"> true </prop>
                            <prop key="hibernate.cache.use_query_cache">true</prop>
                        </props>
                    </property>
                </bean>
            </beans>
            

            【讨论】:

              【解决方案7】:

              如果您的数据源以 JNDI 树为界:

              configuration.setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test");
              

              否则,如果您在代码中有要使用的 DataSource 对象:

              java.sql.Connection conn = datasource.getConnection();
              Session session = sessionFactory.openSession(conn);
              

              我会推荐第一个,让 Hibernate 根据需要处理连接生命周期。在第二种方法中,请确保在不再需要连接时关闭它。

              【讨论】:

              • 如何以编程方式将数据源添加到 JNDI?
              • 您在 JEE 环境中工作吗?如果是的话,最好在JEE容器上设置,让它在启动时处理数据源的创建和绑定。
              • 但是我每个客户有 1 个数据源,并且数据源是在应用程序启动时加载的,所以我必须在代码中执行此操作。每个客户都有自己的 sessionfactory,因为每个客户都有自己的数据库。
              • JEE 容器可以处理具有不同 JNDI 名称的多个数据源。当它们都可用时,您只需使用独特的 JNDI 名称来选择所需的名称。无论如何,正如我在回答中所说,如果你真的需要以编程方式设置连接,你可以做到。
              • 显然我无法在 tomcat 上将数据源添加到 JNDI,因为它是只读的。除了 JNDI 还有其他方法可以设置数据源吗?
              【解决方案8】:

              我不认为你可以。 Hibernate API 将允许您配置 JDBC 属性以便它可以自己管理连接,或者您可以给它一个 JNDI 数据源位置以便它可以去获取它,但我认为您不能提供 em> 它是一个数据源。

              如果您使用 Spring,它会更容易 - 使用 LocalSessionFactoryBean 配置 Hibernate,并将您的 DataSource 注入其中。 Spring 在后台执行必要的魔法。

              【讨论】:

              猜你喜欢
              • 2015-05-02
              • 2019-08-16
              • 2012-12-20
              • 2017-10-23
              • 2013-08-11
              • 2016-02-23
              • 1970-01-01
              • 2012-03-19
              • 1970-01-01
              相关资源
              最近更新 更多