如何使用Hibernate的SchemaUpdate类和JPA的persistence.xml?

17

我有一个使用SchemaUpdate的主方法,可以在控制台上显示要更改/创建的表格,在我的Hibernate项目中运行良好:

 public static void main(String[] args) throws IOException {
  //first we prepare the configuration
  Properties hibProps = new Properties();
  hibProps.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("jbbconfigs.properties"));
  Configuration cfg = new AnnotationConfiguration();
  cfg.configure("/hibernate.cfg.xml").addProperties(hibProps);

  //We create the SchemaUpdate thanks to the configs
  SchemaUpdate schemaUpdate = new SchemaUpdate(cfg);


  //The update is executed in script mode only
  schemaUpdate.execute(true, false);
  ...  
我希望在一个JPA项目中重用这段代码,但是没有hibernate.cfg.xml文件(也没有.properties文件),而是有一个persistence.xml文件(根据JPA规范在META-INF目录中自动检测)。
我尝试了这个过于简单的适配方法,
Configuration cfg = new AnnotationConfiguration();
cfg.configure();

但它以那个异常失败了。

Exception in thread "main" org.hibernate.HibernateException: /hibernate.cfg.xml not found

有人做过这个吗? 谢谢。

3个回答

8

卡里姆说的有点对,但让我来尝试澄清。

假设你已经有了一个普通的JPA标准配置,除了类路径上具有Hibernate Jars之外,没有任何Hibernate特定的内容。如果你在J2SE引导模式下运行,你已经有一些代码看起来像这样,在Java中或者作为Spring配置等:

Map<String, Object> props = getJPAProperties();
EntityManagerFactory emf = 
    Persistence.createEntityManagerFactory("persistence-unit-name", props);

要运行SchemaUpdate,只需使用以下命令:
Map<String, Object> props = getJPAProperties();
Ejb3Configuration conf = 
    new Ejb3Configuration().configure("persistence-unit-name", props);
new SchemaUpdate(conf.getHibernateConfiguration()).execute(true, false);

我不确定在容器环境下如何操作,但在简单的J2SE或Spring类型的配置中,就是这样。


在Play框架上,我使用Ejb3Configuration中的getHibernateConfiguration(),但是我得到了一个“未提供数据源”的错误。我该如何提供连接(在play上使用DB.datasource.getConnection())? - g.annunziata
SchemaUpdate 构造函数不再有参数。execute() 方法不再接受 boolean 类型的参数。 - Nathan

4
你应该使用Ejb3Configuration而不是普通的配置。请参阅实体管理器文档,在hibernate文档的引导部分结束时,链接为bootstrapping section
Ejb3Configuration cfg = new Ejb3Configuration();
EntityManagerFactory emf = 
  cfg.addProperties(properties)                  // add some properties
     .setInterceptor(myInterceptorImpl)          // set an interceptor
     .addAnnotatedClass(MyAnnotatedClass.class)  // add a class to be mapped
     .addClass(NonAnnotatedClass.class)          // add an hbm.xml file using the Hibernate convention
     .addResource("mypath/MyOtherCLass.hbm.xml") // add an hbm.xml file
     .addResource("mypath/orm.xml" )             // add an EJB3 deployment descriptor
     .configure("/mypath/hibernate.cfg.xml")     // add a regular hibernate.cfg.xml
     .buildEntityManagerFactory();               // create the entity manager factory

如您所见,您可以混合使用许多不同类型的配置。

如果只是用于模式更新部分,您可以在持久性xml中设置一个属性:hibernate.hbm2ddl.auto

<persistence-unit name="app1">
   <provider>org.hibernate.ejb.HibernatePersistence</provider>
   <properties><property name="hibernate.hbm2ddl.auto" value="update"/>
   </properties>
</properties>

请参考这里获取更多相关信息。


1
非常感谢Peter,您的回复很有效。这是我们SchemaUpdater类的完整代码:
package reformyourcountry.dbupdate;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;

import reformyourcountry.misc.DateUtil;

/** Small utility to be run by a developer to identify the difference between
 * its entities and its DB schema. It produces an SQL to be copy/pasted and applied
 * on the DB manually. Each developers having its own DB, when a developer commits its
 * Java code with new entity attributes (needing new DB columns), he also commits
 * an updated SQL file with the SQL that other developers need to apply on their local DB.
 * Later, when deploying the next version of the application in production,
 * this SQL file with cumulated changes will be applied onto the production DB.  
 * 
 * Limitations: 
 * 1. the Hibernate schema update does not detect removed attributes. 
 * If you have to delete a column, you need to write the SQL manually;
 * 
 * 2. the Hibernate schema update does not detect changes on existing columns.
 * for example, if you add @Column(nullable=false), it will not generates an 
 * additional DB constraint.
 * 
 * @author Cédric Fieux & John Rizzo & Aymeric Levaux
 *
 */
public class SchemaUpdater  {

    @SuppressWarnings({ "deprecation", "unchecked" })
    public static void main(String[] arg) throws IOException {

        ////// 1. Prepare the configuration (connection parameters to the DB, ect.)
        // Empty map. We add no additional property, everything is already in the persistence.xml
        Map<String,Object> map=new HashMap<String,Object>();   
        // Get the config from the persistence.xml file, with the unit name as parameter.
        Ejb3Configuration conf =  new Ejb3Configuration().configure("ConnectionPostgres",map);
        SchemaUpdate schemaUpdate =new SchemaUpdate(conf.getHibernateConfiguration());

        /////// 2. Get the SQL
        // Before we run the update, we start capturing the console output (to add ";" later)
        PrintStream initOut = System.out;
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
        PrintStream newOut = new PrintStream(outputStream);
        System.setOut(newOut);

        //The update is executed in script mode only
        schemaUpdate.execute(true, false);

        //We reset the original out
        System.setOut(initOut);

        ////// 3. Prints that SQL at the console with a good format (adding a ";" after each line).
        System.out.println("--*******************************************Begin of SQL********************************************");
        System.out.println("-- "+DateUtil.formatyyyyMMdd(new Date()));
        BufferedReader ouReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(outputStream.toByteArray())));
        String str = ouReader.readLine();
        while(str != null){  // For each (sometimes multiline) SQL statement
            // now, str equals "".
            str = ouReader.readLine();  // 
            while (str != null && !str.trim().equals("")) { // for each line of the same statement
                System.out.println();  // previous line is finished.
                System.out.print(str.toLowerCase());
                str = ouReader.readLine();
            }
            // Statement is now finished
            System.out.println(";");
        }
        System.out.println("--*******************************************End of SQL********************************************");

        ////// 4. Print eventual exceptions.
        //If some exception occurred we display them
        if(!schemaUpdate.getExceptions().isEmpty()){
            System.out.println();
            System.out.println("SOME EXCEPTIONS OCCURED WHILE GENERATING THE UPDATE SCRIPT:");
            for (Exception e: (List<Exception>)schemaUpdate.getExceptions()) {
                System.out.println(e.getMessage());
            }
        }
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接