2013-02-13 9 views
6

Sto usando Hibernate in combinazione con Spring. Come database attualmente sto usando HSQL, che memorizza i suoi dati in un file (come SQLite). Il percorso del file HSQL è attualmente codificato nel persistence.xml. Come posso accedere e modificare questo valore in fase di runtime, in modo che un utente possa caricare e salvare da/a un file HSQL arbitrario?Cambiare hibernate.connection.url dall'interno della primavera

persistence.xml:

<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
           http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" 
      version="1.0"> 

    <persistence-unit name="something-unit"> 
     <provider>org.hibernate.ejb.HibernatePersistence</provider> 

     <properties> 
      <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" /> 
      <property name="hibernate.connection.url" value="jdbc:hsqldb:file:~/something-db/somethingdb" /> 
      <property name="hibernate.connection.username" value="sa" /> 
      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> 
      <property name="hibernate.hbm2ddl.auto" value="update" /> 
     </properties> 
    </persistence-unit> 

</persistence> 

primavera applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?> 

<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:context="http://www.springframework.org/schema/context" 
     xmlns:data="http://www.springframework.org/schema/data/jpa" 
     xmlns:tx="http://www.springframework.org/schema/tx" 
     xsi:schemaLocation=" 
       http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd 
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-2.5.xsd 
       http://www.springframework.org/schema/data/jpa 
       http://www.springframework.org/schema/data/jpa/spring-jpa.xsd 
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> 


    <!-- Database Setup --> 

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> 
     <property name="persistenceUnitName" value="something-unit" /> 
    </bean> 

    <data:repositories base-package="com.something.playlist"/> 

    <!-- Transaction Setup --> 

    <tx:annotation-driven/> 

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <property name="entityManagerFactory" ref="entityManagerFactory"/> 
    </bean> 

</beans> 

Grazie per qualsiasi suggerimento!

+0

aggiunto un premio in quanto ho bisogno di un esempio concreto/più aiuto con questo. –

risposta

3

È possibile specificare un'origine dati JNDI e passarla a Sospensione. Oppure si può definire la propria strategia di plug-in per ottenere le connessioni JDBC implementando l'interfaccia org.hibernate.connection.ConnectionProvider

Per ulteriori suggerimenti vedere: http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/session-configuration.html

Edit 2/16: C'è un esempio su StackOverflow sulla creazione di un ConnectionProvider personalizzato: How can I set Datasource when I'm creating Hibernate SessionFactory?

Se si desidera modificare l'origine dati al volo, piuttosto che all'avvio, sarà necessario riavviare il factory di sessione di sospensione. Per farlo correttamente, dovrai assicurarti che non ci siano transazioni in esecuzione al momento del riavvio. A seguito di domande/risposte vi aiutano con quel: Hibernate Sessionfactory restart | Spring

+0

potresti voler unirti al bounty? ;-) –

+0

Ho aggiunto un paio di riferimenti. Spero che questo aiuti sia te che qualcuno che vorrebbe scrivere una soluzione completa per la taglia. In bocca al lupo! – Olaf

1

Una strategia comunemente usato è quello di definire tutte le configurazioni di esecuzione in uno o più file * .properties e utilizzare PropertyPlaceholderConfigurer di primavera per caricare i valori e sostituire il segnaposto in applicationContext.xml, leggi di più qui: Best ways to deal with properties values in XML file in Spring, Maven and Eclipses.

app.properties:

# Dadabase connection settings: 
hibernate.connection.driver_class=org.hsqldb.jdbcDriver 
hibernate.connection.url=jdbc:hsqldb:file:~/something-db/somethingdb 
hibernate.connection.username=sa 
hibernate.connection.password=changeit 
hibernate.dialect=org.hibernate.dialect.HSQLDialect 
hbm2ddl.auto=update 
... ... 

applicationContext-dataStore.xml:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
    <property name="locations"> 
    <list> 
     <!-- Default location inside war file --> 
     <value>classpath:app.properties</value> 
     <!-- Environment specific location, a fixed path on deployment server --> 
     <value>file:///opt/my-app/conf/app.properties</value> 
    </list> 
    </property> 
    <property name="ignoreResourceNotFound" value="true"/> 
</bean> 

... ... 

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
    <property name="driverClassName" value="${hibernate.connection.driver_class}" /> 
    <property name="url" value="${hibernate.connection.url}" /> 
    <property name="username" value="${hibernate.connection.username}" /> 
    <property name="password" value="${hibernate.connection.password}" /> 
</bean> 

Un problema qui è la PropertyPlaceholderConfigurer non analizza persistence.xml, la soluzione è quella di spostare tutta la configurazione di sospensione in Spring applicationContext.xml, poiché non è necessario impostarli in persistence.xml. leggi di più qui: loading .properties in spring-context.xml and persistence.xml.

persistence.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" 
    version="1.0"> 
    <persistence-unit name="JPAService" transaction-type="RESOURCE_LOCAL"/> 
</persistence> 

applicationContext-datSource.xml:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
    <property name="driverClassName" value="${hibernate.connection.driver_class}"/> 
    <property name="url" value="${hibernate.connection.url}"/> 
    <property name="username" value="${hibernate.connection.username}"/> 
    <property name="password" value="${hibernate.connection.password}"/> 
</bean> 

... ... 

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="persistenceXmlLocation" value="classpath:./META-INF/persistence.xml"/> 
    <property name="persistenceUnitName" value="JPAService"/> 
    <property name="dataSource" ref="dataSource"/> 

    <property name="jpaVendorAdapter"> 
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
      <property name="databasePlatform" value="${hibernate.dialect}"/> 
      <property name="showSql" value="true" /> 
      <property name="generateDdl" value="true"/> 
     </bean> 
    </property> 
    <property name="jpaProperties"> 
    <!-- set extra properties here, e.g. for Hibernate: --> 
    <props> 
     <prop key="hibernate.hbm2ddl.auto">${hbm2ddl.auto}</prop> 
    </props> 
    </property> 
</bean> 

Si noti che l'applicazione web ha bisogno di essere riavviato ogni volta che si modifica la configurazione in/opt/my-app /conf/app.properties, per rendere effettive le modifiche.

Spero che questo aiuti.

+0

yorkw, grazie per la risposta dettagliata. Ma se capisco che hai ragione, non posso cambiare hibernate.connection.url al volo usando la tua soluzione? In realtà ho bisogno di cambiarlo al volo, quindi un utente può utilizzare per es. file: apri e seleziona un file che include un database HSQL. Hai qualche suggerimento su questo? Grazie :-) –

1

Se si desidera utilizzare l'ibernazione tramite l'astrazione JPA, è possibile scrivere il codice o il servizio per utilizzare javax.persistence.EntityManagerFactory.Scambia uno di questi e chiama createEntityManager (Mappa mappa); È possibile fornire un'origine dati nella mappa. È possibile avvolgere l'entity manager con la propria implementazione che estrae il parametro da un thread-local per la creazione dell'origine dati.

MODIFICA: lettura errata del contesto e visualizzazione dell'utilizzo di EntityManagerFactory. In tal caso, basta leggere l'ultima parte in cui si avvolge la Factory con un delegato che crea l'origine dati corretta da un threadlocal.

Problemi correlati