Как настроить источник данных при создании Hibernate SessionFactory?
Я создаю SessionFactory, и у меня есть источник данных как объект в коде, где я создаю SessionFactory, но я не могу установить источник данных как объект конфигурации Hibernate. Итак, как я могу установить источник данных для моей 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();
8 ответов
Чтобы предоставить JDBC-соединения для Session, вам нужна реализация ConnectionProvider.
По умолчанию, Hibernate использует DatasourceConnectionProvider
который получает DataSource
экземпляр из JNDI.
Использовать кастом DataSource
использование экземпляра InjectedDataSourceConnectionProvider
и введите DataSource
экземпляр в это.
На InjectedDataSourceConnectionProvider есть примечание TODO
ПРИМЕЧАНИЕ: setDataSource(javax.sql.DataSource) должен быть вызван до настройки (java.util.Properties).
TODO: не удалось найти, где фактически вызывается setDataSource. Разве это не может быть просто передано для настройки???
Согласно примечанию, позвоните 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);
}
}
Вы также можете расширить UserSuppliedConnectionProvider.
Согласно договору ConnectionProvider
Разработчики должны предоставить общедоступный конструктор по умолчанию.
Hibernate вызовет этот конструктор, если пользовательский ConnectionProvider установлен через экземпляр конфигурации.
Configuration cfg = new Configuration();
Properties props = new Properties();
props.put( Environment.CONNECTION_PROVIDER, InjectedDataSourceConnectionProvider.class.getName() );
cfg.addProperties(props);
Если у вас есть ваш 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.
Ответ Луиджи Мендосы - это то, почему мой поиск отправил меня сюда, но я полагаю, что должен дать свою версию, потому что я потратил довольно много времени на поиски того, как это сделать - он устанавливает ее с базой данных 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>
Если ваш источник данных ограничен в дереве JNDI:
configuration.setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test");
В противном случае, если у вас есть объект DataSource в коде, который вы хотите использовать:
java.sql.Connection conn = datasource.getConnection();
Session session = sessionFactory.openSession(conn);
Я бы порекомендовал первый, чтобы позволить Hibernate обрабатывать жизненный цикл соединения по мере необходимости. При втором подходе убедитесь, что вы закрываете соединение, когда оно больше не нужно.
Если вы реализовали класс с javax.sql.DataSource
, Спящий 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();
...
}
}
Если вы используете Spring Framework, используйте 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>
Я не думаю, что ты можешь. Hibernate API позволит вам настроить свойства JDBC так, чтобы он мог управлять самими соединениями, или вы можете указать ему местоположение JSDI DataSource, чтобы он мог его извлекать, но я не думаю, что вы можете предоставить ему DataSource.
На случай, если вы используете Spring, это проще - используйте LocalSessionFactoryBean
настроить Hibernate и внедрить ваш источник данных в это. Весна выполняет необходимую магию в фоновом режиме.
Я использовал 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.