Java 创建 Hibernate SessionFactory 时如何设置数据源?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4406935/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 17:06:43  来源:igfitidea点击:

How can I set Datasource when I'm creating Hibernate SessionFactory?

javahibernatesessionfactory

提问by newbie

I'm creating SessionFactory and I have my datasource as object in code where I'm creating SessionFactory, but i cannot set datasource to Hibernate Configuration object. So how can I set my datasource to my SessionFactory?

我正在创建 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();

采纳答案by dira

To supply JDBC connections to Session, you need an implementation of ConnectionProvider.

要向 Session 提供 JDBC 连接,您需要一个ConnectionProvider的实现。

By default, Hibernate uses DatasourceConnectionProviderwhich obtains a DataSourceinstance from JNDI.

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

To use a custom DataSourceinstance, use InjectedDataSourceConnectionProviderand inject the DataSourceinstance into it.

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

There is TODO note on InjectedDataSourceConnectionProvider

InjectedDataSourceConnectionProvider上有待办事项说明

NOTE : setDataSource(javax.sql.DataSource) must be called prior to configure(java.util.Properties).

TODO : could not find where setDataSource is actually called. Can't this just be passed in to configure???

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

TODO:找不到实际调用 setDataSource 的位置。这个不能直接传入配置吗???

As per the note, call setDataSource()method from configure()method.

根据注释,setDataSource()configure()方法调用方法。

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);
    }
}

You can also extend UserSuppliedConnectionProvider.

您还可以扩展UserSuppliedConnectionProvider

According to the contract of ConnectionProvider

根据ConnectionProvider的约定

Implementors should provide a public default constructor.

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

Hibernate will invoke this constructor if custom ConnectionProvider is set through Configuration instance.

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

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

回答by skaffman

I don't think you can. The Hibernate API will let you configure the JDBC properties so that it can manage the connections itself, or you can give it a JNDI DataSource location so it can go and fetch it, but I don't think you can giveit a DataSource.

我不认为你可以。Hibernate API 将让您配置 JDBC 属性,以便它可以管理连接本身,或者您可以给它一个 JNDI 数据源位置,以便它可以去获取它,但我认为您不能它一个数据源。

On the off-chance that you're using Spring, it's easier - use LocalSessionFactoryBeanto configure Hibernate, and inject your DataSource into that. Spring performs the necessary magic in the background.

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

回答by Tomas Narros

If your datasource is bounded at the JNDI tree:

如果您的数据源在 JNDI 树上有界:

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

Otherwise, if you have a DataSource object in code, which you want to use:

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

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

I would recommend the first one, to let Hibernate handle the connection lifecycle as needed. At the second approach, make sure that you close the connection when it's no longer needed.

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

回答by nIKUNJ

If you are using Spring framework, then use LocalSessionFactoryBean for injecting your data source to Hibernate SessionFactory.

如果您使用的是 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>

回答by Luiggi Mendoza

If you happen to have your DataSourcestored in JNDI, then simply use:

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

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

But if you use a custom data source provider like Apache DBCP or BoneCP and you don't want to use a dependency injection framework like Spring, then you may inject it on the StandardServiceRegistryBuilderbefore creating the SessionFactory:

但是,如果您使用自定义数据源提供程序(如 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());

Note that if you use this approach, you don't need to put the connection parameters in your hibernate.cfg.xml anymore. Here's an example of a compatible hibernate.cfg.xml file when using approach from above:

请注意,如果您使用这种方法,则无需再将连接参数放在 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>

Code above tested on Hibernate 4.3.

上面的代码在 Hibernate 4.3 上测试过。

回答by user2601995

If you've implemented a class with javax.sql.DataSource, Hibernate's DataSourcecan be set by configuring properties.

如果您使用 实现了一个类javax.sql.DataSourceDataSource则可以通过配置属性来设置Hibernate 。

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();
        ...
    }
}

回答by Adam

Luiggi Mendoza's answer is why my search sent me here, but I figure I should give my version because I spent quite some time looking around for how to do this - it sets it up with the Spring in-memory database for testing, a SessionContext and the hbm.xml in case you're not using annotations:

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;
    }

}

and you'll need these:

你需要这些:

<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>

回答by user9117214

I used LocalContainerEntityManagerFactoryBean to create EntityManagerFactory instance at the configuration class.

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

If it is required to set another DataSource, than it is possible to update it with entity manager factory instance at runtime:

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

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

It works with Hibernate 5.2.9 Final.

它适用于 Hibernate 5.2.9 Final。