在jpa / EclipseLink创建表后执行sql脚本?

时间:2010-04-28 15:06:09

标签: java orm jpa eclipselink jpa-2.0

在EclipseLink生成ddl后,是否有可能执行sql脚本? 换句话说,是否可能使用带有“drop-and-create-tables”的EclipseLink属性“eclipselink.ddl-generation”,并且EclipseLink在创建后执行另一个sql文件(将一些数据插入到刚创建的某些表中)表定义?

我正在使用带有GlassFish v3的EclipseLink 2.x和JPA 2.0。

或者我可以在项目中调用的java方法(与ejb3一起战争)中初始化表吗?

6 个答案:

答案 0 :(得分:17)

我出于同样的原因遇到了这个问题,试图找到一种在DDL生成后运行初始化脚本的方法。我提出这个问题的答案,希望缩短那些寻求相同解决方案的人的“文学研究”数量。

我正在使用GlassFish 4及其默认的EclipseLink 2.5 JPA实现。 JPA 2.1下新的Schema Generation功能使得在DDL生成完成后指定“初始化”脚本非常简单。

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="cbesDatabase" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>java:app/jdbc/cbesPool</jta-data-source>
        <properties>
            <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
            <property name="javax.persistence.schema-generation.create-source" value="metadata"/>
            <property name="javax.persistence.schema-generation.drop-source" value="metadata"/>
            <property name="javax.persistence.sql-load-script-source" value="META-INF/sql/load_script.sql"/>
            <property name="eclipselink.logging.level" value="FINE"/> 
        </properties>
    </persistence-unit>
</persistence>

上述配置从元数据(即注释)生成DDL脚本,之后运行META-INF/sql/load_script.sql脚本来填充数据库。在我的例子中,我使用测试数据为几个表格生成并生成其他视图。

有关EclipseLink使用JPA属性的更多信息,请参见EclipseLink/Release/2.5/JPA21的DDL生成部分。同样,Oracle Java EE 7教程中的Section 37.5 Database Schema CreationTOTD #187也提供了快速介绍。

答案 1 :(得分:15)

查看Running a SQL Script on startup in EclipseLink,其中描述的解决方案与Hibernate的import.sql功能 1 等效。 Shaun Smith的致谢:

  

Running a SQL Script on startup in EclipseLink

     

有时,使用DDL时   生成它对运行脚本很有用   首先清理数据库。在   如果你把一个文件叫做Hibernate   你的classpath上的“import.sql”   内容将被发送到数据库。   就个人而言,我不是魔术迷   文件名,但这可能是有用的   特征

     

没有内置的支持   在EclipseLink中,但它很容易做到   感谢EclipseLink的高度   可扩展性。这是一个快速的解决方案   我想出来了:我只是注册了一个   会话的事件侦听器   postLogin事件和处理程序中的I   读取文件并发送每个SQL   对数据库的声明 - 很好,而且   清洁。我走得更远了   支持设置文件名   作为持久性单元属性。您   可以在代码中或在。中指定全部   persistence.xml中。

     

ImportSQL类配置为   a SessionCustomizer到   持久性单位属性,在   postLogin事件,读取文件   由“import.sql.file”标识   属性。这个属性也是   指定为持久性单元   传递给的财产   createEntityManagerFactory。这个   示例还显示了如何定义   并使用您自己的持久性单元   属性。

import org.eclipse.persistence.config.SessionCustomizer;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.SessionEvent;
import org.eclipse.persistence.sessions.SessionEventAdapter;
import org.eclipse.persistence.sessions.UnitOfWork;

public class ImportSQL implements SessionCustomizer {

    private void importSql(UnitOfWork unitOfWork, String fileName) {
        // Open file
        // Execute each line, e.g.,
        // unitOfWork.executeNonSelectingSQL("select 1 from dual");
    }

    @Override
    public void customize(Session session) throws Exception {
        session.getEventManager().addListener(new SessionEventAdapter() {
            @Override
            public void postLogin(SessionEvent event) {
                String fileName = (String) event.getSession().getProperty("import.sql.file");
                UnitOfWork unitOfWork = event.getSession().acquireUnitOfWork();
                importSql(unitOfWork, fileName);
                unitOfWork.commit() 
            }    
        });
    }
     
public static void main(String[] args) {
    Map<String, Object> properties = new HashMap<String, Object>();

    // Enable DDL Generation
    properties.put(PersistenceUnitProperties.DDL_GENERATION, PersistenceUnitProperties.DROP_AND_CREATE);
    properties.put(PersistenceUnitProperties.DDL_GENERATION_MODE, PersistenceUnitProperties.DDL_DATABASE_GENERATION);
    // Configure Session Customizer which will pipe sql file to db before DDL Generation runs
    properties.put(PersistenceUnitProperties.SESSION_CUSTOMIZER, "model.ImportSQL");
    properties.put("import.sql.file","/tmp/someddl.sql");

    EntityManagerFactory emf = Persistence
            .createEntityManagerFactory("employee", properties);
}

我不确定它是一个严格的等价物,但我不确定脚本会在数据库生成后运行。需要测试。如果没有,也许它可以适应。

1 Hibernate有一个整洁的小功能,严重缺乏记录和未知。您可以在生成数据库模式之后立即在SessionFactory创建期间执行SQL脚本,以在新数据库中导入数据。您只需在类路径根目录中添加名为import.sql的文件,并将create或create-drop设置为hibernate.hbm2ddl.auto属性。

答案 2 :(得分:1)

这可能会有所帮助,因为这里有一个混乱: 使用完全相同的属性集(记录器除外)进行数据播种。

请勿使用:

<property name="eclipselink.ddl-generation" value="create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>

DO USE:

<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
<property name="javax.persistence.schema-generation.create-source" value="metadata"/>
<property name="javax.persistence.schema-generation.drop-source" value="metadata"/>

我确认这对我有用。

答案 3 :(得分:0)

它被称为BEFORE ddl-execution。似乎没有很好的方法来适应它,因为没有合适的事件可以使用。

答案 4 :(得分:0)

此过程在DDL语句之前提供执行sql,而最好的(例如,插入种子数据)是在DDL语句之后执行的操作。如果我在这里错过了什么,我不会。有人可以告诉我如何在eclipselink创建表后执行sql(当create-tables属性设置为tru时)

答案 5 :(得分:0)

:)只需替换你的数据

<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
<property name="javax.persistence.schema-generation.create-source" value="metadata-then-script"/>
<property name="javax.persistence.sql-load-script-source" value="META-INF/seed.sql"/>