如何让Hibernate仅在表不存在时创建表?

3

如何让Hibernate仅在表不存在时创建表?我将“hibernate.hbm2ddl.auto”设置为“update”,但重新启动服务器时出现错误,例如“关系已经存在”。

我的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_2_0.xsd"
         version="2.0">
<persistence-unit name="com.adwork">
    <description>Adwork</description>
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <!-- <class>com.mkyong.bean.User</class>  -->
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
        <property name="hibernate.hbm2ddl.auto" value="update"/>
        <property name="show_sql" value="true"/>
        <property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>

        <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>
        <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/adwork"/>
        <property name="javax.persistence.jdbc.user" value="root"/>
        <property name="javax.persistence.jdbc.password" value="root"/>
    </properties>
</persistence-unit>

please help. thanks

Here is the error :-

ERROR: org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'applicationStartUp' defined in ServletContext resource [/WEB-INF/spring/root-context.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: com.adwork] Unable to build Hibernate SessionFactory
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1578)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:775)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:444)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:326)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4727)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5189)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:724)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:700)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:734)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:596)
at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1805)
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: com.adwork] Unable to build Hibernate SessionFactory
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:877)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:805)
at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:58)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:39)
at com.adwork.survey.config.ApplicationStartUp.initIt(ApplicationStartUp.java:27)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1706)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1645)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
... 25 more
Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Unable to execute schema management to JDBC target [alter table person add column createdDate timestamp not null]
at org.hibernate.tool.schema.internal.TargetDatabaseImpl.accept(TargetDatabaseImpl.java:59)
at org.hibernate.tool.schema.internal.SchemaMigratorImpl.applySqlString(SchemaMigratorImpl.java:420)
at org.hibernate.tool.schema.internal.SchemaMigratorImpl.applySqlStrings(SchemaMigratorImpl.java:438)
at org.hibernate.tool.schema.internal.SchemaMigratorImpl.migrateTable(SchemaMigratorImpl.java:247)
at org.hibernate.tool.schema.internal.SchemaMigratorImpl.doMigrationToTargets(SchemaMigratorImpl.java:170)
at org.hibernate.tool.schema.internal.SchemaMigratorImpl.doMigration(SchemaMigratorImpl.java:60)
at org.hibernate.tool.hbm2ddl.SchemaUpdate.execute(SchemaUpdate.java:129)
at org.hibernate.tool.hbm2ddl.SchemaUpdate.execute(SchemaUpdate.java:97)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:481)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:802)
... 36 more
Caused by: org.postgresql.util.PSQLException: ERROR: column "createddate" of relation "person" already exists
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2270)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1998)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:570)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:406)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:334)
at org.hibernate.tool.schema.internal.TargetDatabaseImpl.accept(TargetDatabaseImpl.java:56)
... 46 more

我的领域类:

@Entity
@Table(name = "person")
public class Person implements Serializable
{
/**
 * 
 */
private static final long serialVersionUID = 5129388836708407722L;

@Id
private Long id;

@OneToOne
@JoinColumn(name = "userId")
private Users user;

@Column(name = "firstName",nullable = false)
private String firstName;

@Column(name = "middleName",nullable = false)
private String middleName;

@Column(name = "lastName",nullable = false)
private String lastName;

@Column(name = "gender",nullable = false)
private String gender;

@Column(name = "dateOfBirth",nullable = false)
private Date dateOfBirth;

@Column(name = "age",nullable = false)
private Byte age;

@Column(name = "createdDate",nullable = false)
private Timestamp createdDate;

@Column(name = "lastUpdatedDate",nullable = false)
private Timestamp lastUpdateDate;

public Person() 
{
    // TODO Auto-generated constructor stub
}
//and setters / getters 
}

创建数据库表的脚本:

CREATE TABLE person
(
  id bigint NOT NULL,
  age smallint NOT NULL,
  createddate timestamp without time zone NOT NULL,
  dateofbirth date NOT NULL,
  firstname character varying(255) NOT NULL,
  gender character varying(255) NOT NULL,
  lastname character varying(255) NOT NULL,
  lastupdateddate timestamp without time zone NOT NULL,
  middlename character varying(255) NOT NULL,
  userid bigint,
  CONSTRAINT person_pkey PRIMARY KEY (id),
  CONSTRAINT fkd8ja1o2m8k25sf0mxvhu4c0ti FOREIGN KEY (userid)
  REFERENCES users (user_id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
  OIDS=FALSE
);
ALTER TABLE person
  OWNER TO root;

更改列名后的表格:

CREATE TABLE person
(
  id bigint NOT NULL,
  age smallint NOT NULL,
  "createdDate" timestamp without time zone NOT NULL,
  dateofbirth date NOT NULL,
  firstname character varying(255) NOT NULL,
  gender character varying(255) NOT NULL,
  lastname character varying(255) NOT NULL,
  lastupdateddate timestamp without time zone NOT NULL,
  middlename character varying(255) NOT NULL,
  userid bigint,
  CONSTRAINT person_pkey PRIMARY KEY (id),
  CONSTRAINT fkd8ja1o2m8k25sf0mxvhu4c0ti FOREIGN KEY (userid)
  REFERENCES users (user_id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
  OIDS=FALSE
);
ALTER TABLE person
  OWNER TO root;

现在我重新启动服务器,出现了新的错误:-
Feb 21, 2017 11:26:07 AM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 1572 ms
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/D:/sts-bundle/pivotal-tc-server- developer-3.2.2.RELEASE/base-instance/wtpwebapps/FeePaymentPortal/WEB-INF/lib/slf4j-log4j12-1.6.6.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/D:/sts-bundle/pivotal-tc-server-developer-3.2.2.RELEASE/base-instance/wtpwebapps/FeePaymentPortal/WEB-INF/lib/slf4j-simple-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization started
INFO : org.springframework.web.context.support.XmlWebApplicationContext - Refreshing Root WebApplicationContext: startup date [Tue Feb 21 11:26:11 IST 2017]; root of context hierarchy
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/spring/root-context.xml]
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/spring/security-context.xml]
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
WARN : org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl - HHH000402: Using Hibernate built-in connection pool (not for production use!)
ERROR: org.hibernate.tool.hbm2ddl.SchemaExport - HHH000389: Unsuccessful: alter table role drop constraint FKgg3583634e0ydkacyk8wbbm19
ERROR: org.hibernate.tool.hbm2ddl.SchemaExport - ERROR: relation "role" does not exist
ERROR: org.hibernate.tool.hbm2ddl.SchemaExport - HHH000389: Unsuccessful: alter table user_roles drop constraint FKhfh9dx7w3ubf1co1vdev94g3f
ERROR: org.hibernate.tool.hbm2ddl.SchemaExport - ERROR: relation "user_roles" does not exist
INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 7665 ms
INFO : org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'appServlet': initialization started
INFO : org.springframework.web.context.support.XmlWebApplicationContext -  Refreshing WebApplicationContext for namespace 'appServlet-servlet': startup date [Tue Feb 21 11:26:18 IST 2017]; parent: Root WebApplicationContext
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/spring/appServlet/servlet-context.xml]
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/],methods=[GET]}" onto public java.lang.String org.giks.controllers.HomeController.home(org.springframework.ui.ModelMap)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/payment-month],methods=[GET]}" onto public java.lang.String org.giks.controllers.HomeController.paymentMonth(org.springframework.ui.ModelMap)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/payment-type],methods=[GET]}" onto public java.lang.String org.giks.controllers.HomeController.paymentMethod(org.springframework.ui.ModelMap)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/payment-verified],methods=[GET]}" onto public java.lang.String org.giks.controllers.HomeController.paymentVerified(org.springframework.ui.ModelMap)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/student-fees],methods=[GET]}" onto public java.lang.String org.giks.controllers.HomeController.getStudentFees(org.springframework.ui.ModelMap)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/student-details],methods=[GET]}" onto public java.lang.String org.giks.controllers.HomeController.getStudentDetails(org.springframework.ui.ModelMap)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter - Looking for @ControllerAdvice: WebApplicationContext for namespace 'appServlet-servlet': startup date [Tue Feb 21 11:26:18 IST 2017]; parent:  Root WebApplicationContext
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter - Looking for @ControllerAdvice: WebApplicationContext for namespace 'appServlet-servlet': startup date [Tue Feb 21 11:26:18 IST 2017]; parent: Root WebApplicationContext
INFO : org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapped URL path [/resources/**] onto handler 'org.springframework.web.servlet.resource.ResourceHttpRequestHandler#0'
INFO : org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'appServlet': initialization completed in 2426 ms
Feb 21, 2017 11:26:21 AM org.apache.catalina.startup.Catalina start
INFO: Server startup in 14090 ms

这个 <property name="hibernate.hbm2ddl.auto" value="update"/> 已经确保了这一点。发生了什么?你能展示一下日志吗? - Jorge Campos
你能发布实体类吗?根据日志显示,该列似乎正在重复。 - Apollo
请查找更改。 - Aman Nagarkoti
只是出于好奇,将数据库中的列名更改为“createdDate”(大写D),然后再试一次,看看错误是否移动到其他列。 - Jason C
@AmanNagarkoti 直接在数据库上操作。所以直接将该列重命名为“createdDate”,并保持您的域类与现在的状态不变。这只是一个实验。 - Jason C
显示剩余6条评论
1个回答

3
我认为主要问题在于PostgreSQL列名不区分大小写(默认情况下将未引用的列名转换为小写),但Hibernate区分大小写。
例如,对于您原始的createddate列:
- 您的域类指定了createdDate,大写D。 - 您的表使用createddate,小写D。 - 当Hibernate尝试更新模式(hibernate.hbm2ddl.auto=update)时,它会查找与域类中指定的createdDate相同的列名,因为"createddate" != "createdDate"是区分大小写的,所以它认为需要添加该列并尝试执行该操作。 - 添加操作失败,因为根据PostgreSQL(不区分大小写)的等效名称已存在一个列。
因此,您有以下选项:
1. 在域类中指定小写列名。 2. 确保表中的列名使用匹配的大小写,注意在列创建语句中必须引用列名以使其保留大小写。
正如你所看到的,当你手动更改表列名称为createdDate时,解决了第一个错误(从而暴露出一个新错误)。
至于你的新错误“relation ... does not exist”,我不是完全确定,但我认为this is also connected to case-sensitivity issues in table names,你需要进一步调查。至少,这是一个可能性。
我没有经常使用Hibernate与PostgreSQL,因此不知道是否有任何更简单的选项,例如某些方言选项或其他地方可以使它们协同工作的东西。

但是有一个问题..这个大小写敏感的问题只存在于PGadmin中还是所有关系型数据库管理系统都有这个问题? - Aman Nagarkoti

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