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

Posted

技术标签:

【中文标题】创建 Hibernate SessionFactory 时如何设置数据源?【英文标题】:How can I set Datasource when I'm creating 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();

【问题讨论】:

【参考方案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 在后台执行必要的魔法。

【讨论】:

你有示例配置的链接吗? @newbie:你的意思是喜欢文档? docs.jboss.org/hibernate/core/3.6/reference/en-US/html/… 我的意思是如何使用 LocalSessionFactoryBean @newbie: static.springsource.org/spring/docs/3.0.x/…

以上是关于创建 Hibernate SessionFactory 时如何设置数据源?的主要内容,如果未能解决你的问题,请参考以下文章

mybatis可以像hibernate一样自动创建表吗

idea创建Hibernate项目

Hibernate 不创建表并自动更改

hibernate动态创建表

在hibernate5中,关于让hibernate自动创建表报错的问题。

初识Hibernate 以及如何使用Maven创建Hibernate项目