java - cfg - ¿Cómo puedo configurar Datasource cuando estoy creando Hibernate SessionFactory?
hibernate.cfg.xml example (8)
Estoy creando SessionFactory y tengo mi fuente de datos como objeto en el código donde estoy creando SessionFactory, pero no puedo establecer la fuente de datos en el objeto de Configuración de Hibernate. Entonces, ¿cómo puedo configurar mi fuente de datos en mi 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();
La respuesta de Luiggi Mendoza es por qué mi búsqueda me envió aquí, pero creo que debería dar mi versión porque dediqué bastante tiempo a buscar la forma de hacerlo: la configura con la base de datos Spring In-Memory para pruebas, un SessionContext y el hbm.xml en caso de que no estés usando anotaciones:
/**
* 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;
}
}
y necesitarás estos:
<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>
No creo que puedas. La API de Hibernate te permitirá configurar las propiedades de JDBC para que pueda administrar las conexiones por sí mismo, o puedes darle una ubicación de JNDI DataSource para que pueda ir a buscarla, pero no creo que puedas darle un DataSource.
Si no está usando Spring, es más fácil: use LocalSessionFactoryBean
para configurar Hibernate e inyecte su DataSource en eso. La primavera realiza la magia necesaria en el fondo.
Para suministrar conexiones JDBC a la sesión, necesita una implementación de ConnectionProvider .
Por defecto de Bu, Hibernate usa DatasourceConnectionProvider
que obtiene una instancia de DataSource
de JNDI.
Para usar la instancia de DataSource
personalizada, use InjectedDataSourceConnectionProvider
e inyecte la instancia de DataSource
en ella.
Hay una nota de TODO en InjectedDataSourceConnectionProvider
NOTA: setDataSource (javax.sql.DataSource) debe llamarse antes de configurar (java.util.Properties).
TODO: no se pudo encontrar donde se llama a setDataSource. ¿No se puede pasar esto para configurar?
Según la nota, llame setDataSource()
método setDataSource()
desde el método 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);
}
}
También puede extender UserSuppliedConnectionProvider .
Según el contrato de ConnectionProvider
Los implementadores deben proporcionar un constructor público predeterminado.
Hibernate invocará este constructor, si el ConnectionProvider personalizado se establece a través de la instancia de Configuración.
Configuration cfg = new Configuration();
Properties props = new Properties();
props.put( Environment.CONNECTION_PROVIDER, InjectedDataSourceConnectionProvider.class.getName() );
cfg.addProperties(props);
Si está utilizando Spring framework, entonces use LocalSessionFactoryBean para inyectar su fuente de datos a 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>
Si ha implementado una clase con javax.sql.DataSource
, DataSource
de Hibernate se puede configurar mediante la configuración de propiedades.
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();
...
}
}
Si su fuente de datos está delimitada en el árbol JNDI:
configuration.setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test");
De lo contrario, si tiene un objeto DataSource en el código, que desea utilizar:
java.sql.Connection conn = datasource.getConnection();
Session session = sessionFactory.openSession(conn);
Recomendaría el primero, para que Hibernate maneje el ciclo de vida de la conexión según sea necesario. En el segundo enfoque, asegúrese de cerrar la conexión cuando ya no sea necesaria.
Si tiene su DataSource
almacenado en JNDI, simplemente use:
configuration.setProperty(
"hibernate.connection.datasource",
"java:comp/env/jdbc/yourDataSource");
Pero si usa un proveedor de fuente de datos personalizado como Apache DBCP o BoneCP y no desea usar un marco de inyección de dependencias como Spring , entonces puede inyectarlo en StandardServiceRegistryBuilder
antes de crear 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());
Tenga en cuenta que si utiliza este enfoque, no necesita poner más los parámetros de conexión en su hibernate.cfg.xml. Aquí hay un ejemplo de un archivo hibernate.cfg.xml compatible cuando se usa el método de arriba:
<?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>
Código anterior probado en Hibernate 4.3.
Utilicé LocalContainerEntityManagerFactoryBean para crear la instancia de EntityManagerFactory en la clase de configuración.
Si se requiere configurar otro DataSource, entonces es posible actualizarlo con la instancia de fábrica del administrador de entidades en el tiempo de ejecución:
@Service("myService")
public class MyService
{
....
@Autowired
private LocalContainerEntityManagerFactoryBean emf;
....
public void replaceDataSource(DataSource dataSource)
{
emf.setDataSource(dataSource);
emf.afterPropertiesSet();
}
....
}
Funciona con Hibernate 5.2.9 Final.