JPA JavaSE проект с более чем одним постоянным модулем не работает как задумано - PullRequest
0 голосов
/ 01 июля 2019

Я пытаюсь изучить JPA, поэтому я создал простой JavaSE-JPA проект (без Spring).Я хотел, чтобы таблицы БД создавались при запуске приложения с помощью моих сопоставлений аннотаций.И я смог достичь этого.

Затем я решил сделать некоторые таблицы уже существующими и доступными только для чтения, в то время как другие будут создаваться при запуске.Но не смог этого сделать.

Я сделал следующее.

  • Сделал некоторые из моих сущностей неизменными.
  • Вручную создавать и заполнять таблицы в БД для этих неизменяемых объектов.
  • Создал 2 постоянных модуля и использовал «validate» для readOnlyPU и «create» для основного PU в свойствах гибернации.

Не сработало.Таблицы удалялись и создавались заново при запуске.Я думаю, потому что один из моих постоянных юнитов создал, и я не смог найти, чтобы сообщить этому PU о том, какую сущность игнорировать при создании.

Я не хочу упоминатьклассы или имя пакета в XML под постоянным модулем.Может быть, это будет работать, но не элегантное решение

Итак

  • Я создал другую схему в БД и поместил свои таблицы только для чтения и данные в эту новую схему.
  • Обновлен мой постоянный модуль readOnly с этой схемой.
  • Упоминается соответствующий атрибут схемы во всех изменяемых и неизменяемых аннотациях JPA @table.

Но при запуске приложения проверка гибернации не выполняется.Ниже приведен соответствующий фрагмент кода.

@Entity
@Table(name = "CONTINENTS",schema = "readOnlySchema")
public class Continent {
    @Id
    private int id;
    private String continentName;
    private String continent;
    private Continent() {}
       .........
       ............
}   
@Entity 
@Table(name = "COUNTRIES",schema = "readOnlySchema")
  public class Country {
    @Id
    private int id;
    private String countryCode;
    private String countryName;
    private String currencyCode;
    private String capital;

    @ManyToOne
    private Continent continent;
    ...........
    ............
    private Country() {}
}
@Entity 
@Table(name = "ADDRESS", schema = "schema1")
public class Address {

    @Id
    @GeneratedValue
    private long id;
    ...........
    ............
    @ManyToOne
    private Country country;
 }


    <persistence-unit name="pu">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <properties>
        <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/schema1?serverTimezone=EST"/>
        <property name="javax.persistence.jdbc.user" value="....."/>
        <property name="javax.persistence.jdbc.password" value="....."/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.hbm2ddl.auto" value="create"/>
        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />         
   </properties>
</persistence-unit>


<persistence-unit name="ReadOnlyPU">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <properties>
        <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/readOnlySchema?serverTimezone=EST"/>
        <property name="javax.persistence.jdbc.user" value="...."/>
        <property name="javax.persistence.jdbc.password" value="...."/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.hbm2ddl.auto" value="validate"/>
        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
    </properties>
 </persistence-unit>

Все таблицы создаются в моей основной схеме схемы1, и ниже выдается исключение.

        Program started
        Jul 01, 2019 10:07:47 AM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
        INFO: HHH000204: Processing PersistenceUnitInfo [
            name: pu
            ...]
        Jul 01, 2019 10:07:48 AM org.hibernate.Version logVersion
        INFO: HHH000412: Hibernate Core {5.3.10.Final}
        Jul 01, 2019 10:07:48 AM org.hibernate.cfg.Environment <clinit>
        INFO: HHH000206: hibernate.properties not found
        Jul 01, 2019 10:07:48 AM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
        INFO: HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
        Jul 01, 2019 10:07:48 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
        WARN: HHH10001002: Using Hibernate built-in connection pool (not for production use!)
        Jul 01, 2019 10:07:48 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
        INFO: HHH10001005: using driver [com.mysql.cj.jdbc.Driver] at URL [jdbc:mysql://localhost:3306/schema1?serverTimezone=EST]
        Jul 01, 2019 10:07:48 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
        INFO: HHH10001001: Connection properties: {user=mps, password=****}
        Jul 01, 2019 10:07:48 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
        INFO: HHH10001003: Autocommit mode: false
        Jul 01, 2019 10:07:48 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
        INFO: HHH000115: Hibernate connection pool size: 20 (min=1)
        Jul 01, 2019 10:07:49 AM org.hibernate.dialect.Dialect <init>
        INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL5InnoDBDialect
        Hibernate: alter table COUNTRIES drop foreign key FK4hiubsv31sjivffus7ohgj9ws
        Jul 01, 2019 10:07:50 AM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
        INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@4a31c2ee] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
        Jul 01, 2019 10:07:50 AM org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl handleException
        WARN: GenerationTarget encountered exception accepting command : Error executing DDL "alter table COUNTRIES drop foreign key FK4hiubsv31sjivffus7ohgj9ws" via JDBC Statement
        org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "alter table COUNTRIES drop foreign key FK4hiubsv31sjivffus7ohgj9ws" via JDBC Statement
            at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67)
            at org.hibernate.tool.schema.internal.SchemaDropperImpl.applySqlString(SchemaDropperImpl.java:375)
            at org.hibernate.tool.schema.internal.SchemaDropperImpl.applySqlStrings(SchemaDropperImpl.java:359)
            at org.hibernate.tool.schema.internal.SchemaDropperImpl.applyConstraintDropping(SchemaDropperImpl.java:331)
            at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:230)
            at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:154)
            at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:126)
            at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:112)
            at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:144)
            at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:72)
            at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:310)
            at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:467)
            at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:939)
            at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)
            at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
            at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
            at com.mps.jpa.PersistenceManager$SingletonClassHolder.<clinit>(PersistenceManager.java:18)
            at com.mps.jpa.PersistenceManager.getEntityManagerFactory(PersistenceManager.java:24)
            at com.mps.jpa.PersistenceManager.getEntityManager(PersistenceManager.java:27)
            at com.mps.jpa.App.main(App.java:21)
        Caused by: java.sql.SQLSyntaxErrorException: Table 'schema1.countries' doesn't exist
            at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
            at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
            at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
            at com.mysql.cj.jdbc.StatementImpl.executeInternal(StatementImpl.java:782)
            at com.mysql.cj.jdbc.StatementImpl.execute(StatementImpl.java:666)
            at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:54)
            ... 19 more

        Hibernate: drop table if exists CONTINENTS
        Hibernate: drop table if exists COUNTRIES
        Hibernate: alter table ADDRESS drop foreign key FK1prteh5rw6mdmeh06djuevhg4
        Jul 01, 2019 10:07:50 AM org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl handleException
        WARN: GenerationTarget encountered exception accepting command : Error executing DDL "alter table ADDRESS drop foreign key FK1prteh5rw6mdmeh06djuevhg4" via JDBC Statement
        org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "alter table ADDRESS drop foreign key FK1prteh5rw6mdmeh06djuevhg4" via JDBC Statement
            at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67)
            at org.hibernate.tool.schema.internal.SchemaDropperImpl.applySqlString(SchemaDropperImpl.java:375)
            at org.hibernate.tool.schema.internal.SchemaDropperImpl.applySqlStrings(SchemaDropperImpl.java:359)
            at org.hibernate.tool.schema.internal.SchemaDropperImpl.applyConstraintDropping(SchemaDropperImpl.java:331)
            at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:230)
            at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:154)
            at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:126)
            at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:112)
            at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:144)
            at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:72)
            at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:310)
            at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:467)
            at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:939)
            at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)
            at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
            at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
            at com.mps.jpa.PersistenceManager$SingletonClassHolder.<clinit>(PersistenceManager.java:18)
            at com.mps.jpa.PersistenceManager.getEntityManagerFactory(PersistenceManager.java:24)
            at com.mps.jpa.PersistenceManager.getEntityManager(PersistenceManager.java:27)
            at com.mps.jpa.App.main(App.java:21)
        Caused by: java.sql.SQLSyntaxErrorException: Table 'schema1.address' doesn't exist
            at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
            at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
            at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
            at com.mysql.cj.jdbc.StatementImpl.executeInternal(StatementImpl.java:782)
            at com.mysql.cj.jdbc.StatementImpl.execute(StatementImpl.java:666)
            at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:54)
            ... 19 more

        Hibernate: drop table if exists ADDRESS
        Hibernate: drop table if exists hibernate_sequence
        Hibernate: create table CONTINENTS (id integer not null, continent varchar(255), continentName varchar(255), primary key (id)) engine=InnoDB
        Jul 01, 2019 10:07:50 AM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
        INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@2e1792e7] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
        Hibernate: create table COUNTRIES (id integer not null, capital varchar(255), countryCode varchar(255), countryName varchar(255), currencyCode varchar(255), continent_id integer, primary key (id)) engine=InnoDB
        Hibernate: create table ADDRESS (id bigint not null, addressLine1 varchar(255), city varchar(255), state varchar(255), street varchar(255), zip varchar(255), country_id integer, primary key (id)) engine=InnoDB
        Hibernate: create table hibernate_sequence (next_val bigint) engine=InnoDB
        Hibernate: insert into hibernate_sequence values ( 1 )
        Hibernate: alter table COUNTRIES add constraint FK4hiubsv31sjivffus7ohgj9ws foreign key (continent_id) references CONTINENTS (id)
        Hibernate: alter table ADDRESS add constraint FK1prteh5rw6mdmeh06djuevhg4 foreign key (country_id) references COUNTRIES (id)
        Jul 01, 2019 10:07:50 AM org.hibernate.tool.schema.internal.SchemaCreatorImpl applyImportSources
        INFO: HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@796d3c9f'
        Jul 01, 2019 10:07:50 AM org.hibernate.hql.internal.QueryTranslatorFactoryInitiator initiateService
        INFO: HHH000397: Using ASTQueryTranslatorFactory
        Jul 01, 2019 10:07:50 AM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
        INFO: HHH000204: Processing PersistenceUnitInfo [
            name: ReadOnlyPU
            ...]
        Jul 01, 2019 10:07:50 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
        WARN: HHH10001002: Using Hibernate built-in connection pool (not for production use!)
        Jul 01, 2019 10:07:50 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
        INFO: HHH10001005: using driver [com.mysql.cj.jdbc.Driver] at URL [jdbc:mysql://localhost:3306/readOnlySchema?serverTimezone=EST]
        Jul 01, 2019 10:07:50 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
        INFO: HHH10001001: Connection properties: {user=mps, password=****}
        Jul 01, 2019 10:07:50 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
        INFO: HHH10001003: Autocommit mode: false
        Jul 01, 2019 10:07:50 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
        INFO: HHH000115: Hibernate connection pool size: 20 (min=1)
        Jul 01, 2019 10:07:50 AM org.hibernate.dialect.Dialect <init>
        INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL5InnoDBDialect
        Jul 01, 2019 10:07:50 AM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
        INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@66e889df] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
        Jul 01, 2019 10:07:50 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
        INFO: HHH10001008: Cleaning up connection pool [jdbc:mysql://localhost:3306/readOnlySchema?serverTimezone=EST]
        Exception in thread "main" java.lang.ExceptionInInitializerError
            at com.mps.jpa.PersistenceManager.getEntityManagerFactory(PersistenceManager.java:24)
            at com.mps.jpa.PersistenceManager.getEntityManager(PersistenceManager.java:27)
            at com.mps.jpa.App.main(App.java:21)
        Caused by: javax.persistence.PersistenceException: [PersistenceUnit: ReadOnlyPU] Unable to build Hibernate SessionFactory
            at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:1016)
            at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:942)
            at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)
            at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
            at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
            at com.mps.jpa.PersistenceManager$SingletonClassHolder.<clinit>(PersistenceManager.java:19)
            ... 3 more
        Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [schema1.ADDRESS]
            at org.hibernate.tool.schema.internal.AbstractSchemaValidator.validateTable(AbstractSchemaValidator.java:121)
            at org.hibernate.tool.schema.internal.GroupedSchemaValidatorImpl.validateTables(GroupedSchemaValidatorImpl.java:42)
            at org.hibernate.tool.schema.internal.AbstractSchemaValidator.performValidation(AbstractSchemaValidator.java:89)
            at org.hibernate.tool.schema.internal.AbstractSchemaValidator.doValidation(AbstractSchemaValidator.java:68)
            at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:191)
            at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:72)
            at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:310)
            at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:467)
            at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:939)
            ... 7 more

1 Ответ

0 голосов
/ 02 июля 2019

Ну, вы никогда не говорили Hibernate , какие сущности принадлежат , что единица персистентности.

Это можно сделать, поместив <exclude-unlisted-classes>true</exclude-unlisted-classes> внутри каждой единицы персистентности вместе с явным списком включаемых классов (указывается с помощью тега <class>).

Вопрос в том, зачем вам это делать? Вы понимаете, что в такой настройке сущности не могут совместно использоваться двумя единицами постоянства, верно?

Если вы хотите предотвратить изменения в таблицах только для чтения, то, возможно, вам следует вместо этого рассмотреть возможность отзыва соответствующих разрешений DDL на readOnlySchema у пользователя БД, который использует Hibernate. Как только это будет сделано, вы все равно сможете использовать режим hbm2dddl create, так как я считаю, что ошибки генератора схемы не считаются фатальными в Hibernate, поэтому выполнение будет продолжено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...