Hibernate模型类配置在CREATE TABLE查询中没有反映“hibernate.hbm2ddl.auto = update”

时间:2017-07-25 06:02:48

标签: java mysql hibernate

我正在开发一个Spring(4.x)-Hibernate(5.2.x)Web应用程序项目。

模型类

@Entity
@Table( name = "users" )
public class User {

    @Id
    @Column( name="ID" )
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    private Long id;

    @Temporal( TemporalType.TIMESTAMP )
    @Column( name="CREATED_AT", insertable=false, nullable=false )
    @Generated( GenerationTime.INSERT )
    private Date createdAt;

    @Temporal( TemporalType.TIMESTAMP )
    @Column( name="UPDATED_AT", insertable=false, updatable=false, nullable=false )
    @Generated( GenerationTime.ALWAYS )
    private Date updatedAt;

    public enum Role {
        ADMIN,
        USER,
        GUEST
    }
    @NotNull
    @Column( name="ROLE" )
    @Enumerated( EnumType.STRING )
    private Role role;

    //getters & setters
}

Hibernate属性

hibernate.dialect = org.hibernate.dialect.MySQLDialect
hibernate.show_sql = true
hibernate.format_sql = true
hibernate.hbm2ddl.auto = update

自动生成查询

create table users (
    ID bigint not null auto_increment,
    CREATED_AT datetime not null,
    UPDATED_AT datetime not null,
    ROLE varchar(255) not null,
    primary key (id)
)

我希望查询

  • CREATED_AT DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
  • UPDATED_AT DATETIME NOT NULL ON UPDATE CURRENT_TIMESTAMP
  • ROLE ENUM('ADMIN','USER','GUEST') VARCHAR(255) NOT NULL

这是它的工作方式还是我在配置中的错误?完成了一些搜索,但没有找到明确的解决方案,除了这些,

  • @Column(name="CREATED_AT", nullable = false,columnDefinition="TIMESTAMP default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP")
  • @ColumnDefault( "NOW()" )

但是这些定义取决于底层数据库,这就是我的想法。需要一个更像java / hibernate的配置,就像我使用的那样,但不起作用!

3 个答案:

答案 0 :(得分:2)

对于当前版本的jpa(休眠提供程序),

{
  "settings": {
    "x-powered-by": true,
    "etag": "weak",
    "env": "development",
    "query parser": "extended",
    "subdomain offset": 2,
    "trust proxy": false,
    "views": "/Users/filipeferminiano/MEGA/altcoin-site/views",
    "jsonp callback name": "callback",
    "view engine": "ejs"
  },
  "message": [],
  "_locals": {},
  "cache": false
}

标识DEFAULT值,以通过DDL(数据定义语言)应用于关联的列。

因此,似乎无法像预期的那样基于Java生成具有默认值的列的表

columnDefinition and @ColumnDefault

如果由于DDL语法可能不同,我们要切换到其他数据库服务器(oracle-> mysql),这将带来很多不便。但是jpa将来可能会具有此功能

解决方法针对您的问题,您必须对DDL使用默认值。

另一种方法,开发人员经常用来确保列始终在插入之前初始化。但这不会为数据库中的列生成默认值。

CREATED_AT DATETIME NOT NULL DEFAULT CURRENT_TIMESTAM

,如果其他开发人员使用本机sql查询,可能会失败。

如果找到其他解决方案并希望对您有所帮助,请更正!

答案 1 :(得分:2)

有一些方法可以解决您的问题。

  1. 使用@PrePersist
  2. 使用@CreationTimestamp和@UpdateTimestamp Detail here
  3. 使用上述解决方案组合DDL。

P / s:您应该使用Flyway,Liquibase等数据库迁移工具。这些工具将为您带来很大帮助。

答案 2 :(得分:0)

DDL通常是特定于数据库的。要使用其他DDL,您可能需要研究Flyway,Liquibase等。

java / hibernate中的另一种方法是:

  

@Generated已被改装为使用@ValueGenerationType   元注释。使用@ValueGenerationType元注释   声明用于标记实体的自定义注释时   需要特定生成策略的属性。实际上   生成逻辑必须添加到实现   AnnotationValueGeneration界面。

如果需要在内存中生成时间戳记值,则必须使用以下映射:

实体:

@Entity(name = "Event")
public static class Event {

@Id
@GeneratedValue
private Long id;

@Column(name = "`timestamp`")
@FunctionCreationTimestamp
private Date timestamp;

//Constructors, getters, and setters are omitted for brevity
}

时间戳生成类:

@ValueGenerationType(generatedBy = FunctionCreationValueGeneration.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface FunctionCreationTimestamp {}

public static class FunctionCreationValueGeneration
    implements AnnotationValueGeneration<FunctionCreationTimestamp> {

@Override
public void initialize(FunctionCreationTimestamp annotation, Class<?> propertyType) {
}

/**
 * Generate value on INSERT
 * @return when to generate the value
 */
public GenerationTiming getGenerationTiming() {
    return GenerationTiming.INSERT;
}

/**
 * Returns the in-memory generated value
 * @return {@code true}
 */
public ValueGenerator<?> getValueGenerator() {
    return (session, owner) -> new Date( );
}

/**
 * Returns false because the value is generated by the database.
 * @return false
 */
public boolean referenceColumnInSql() {
    return false;
}

/**
 * Returns null because the value is generated in-memory.
 * @return null
 */
public String getDatabaseGeneratedReferencedColumnValue() {
    return null;
}
}

持久存储事件实体时,Hibernate生成以下SQL语句:

INSERT INTO Event ("timestamp", id)
VALUES ('Tue Mar 01 10:58:18 EET 2016', 1)

如您所见,new Date()对象值用于分配时间戳记列值。

参考:http://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/Hibernate_User_Guide.html#mapping-database-generated-value-example

PS :(只是想想),您甚至可以使用if-else子句进行特定于数据库的实现。