严格来说,应该在 basic type 的 persistent attributes 上添加 @javax.persistence.Basic 注解,但实际不需要,因为 @Basic 是默认值,因此可以省略。

JPA specification 限制只有下面类型可以被标记为 @javax.persistence.Basic

  • Java primitive types and wrappers
  • java.lang.String
  • java.math.BigInteger
  • java.math.BigDecimal
  • java.util.Date
  • java.util.Calendar
  • java.sql.Date
  • java.sql.Time
  • java.sql.Timestamp
  • byte[] or Byte[]
  • char[] or Character[]
  • enums
  • any other type that implements Serializable (JPA's "support" for Serializable types is to directly serialize their state to the database).

即 Hibernate basic type 比 JPA 允许 @Basic 的类型多了

  • java.util.Currency
  • java.util.Locale
  • java.util.TimeZone
  • java.net.URL
  • java.lang.Class
  • java.sql.Blob
  • java.sql.Clob
  • java.util.UUID
  • java.sql.NClob
  • java.time.Duration
  • java.time.Instant
  • java.time.LocalDateTime
  • java.time.LocalDate
  • java.time.LocalTime
  • java.time.OffsetDateTime
  • java.time.OffsetTime
  • java.time.ZonedDateTime
  • com.vividsolutions.jts.geom.Geometry
  • org.geolatte.geom.Geometry

另外 JPA 2.1 添加 javax.persistence.AttributeConverter 参见 JPA 2.1 AttributeConverters

@Basic 有两个属性

  • optional - 默认 true ,表示此 attribute 是否可以是 null 。 Hibernate 使用此属性表示数据库 column 是否是 nullable
  • fetch - 默认 javax.persistence.FetchType.EAGER 。 JPA 的 EAGER 表示当 fetch Entity 时同时 fetch 此属性,另有 LAZY 表示只有当访问此属性时才 fetch 此属性。但 Hibernate 忽略 basic types 的 fetch 属性,除非使用了 bytecode enhancement
package org.example.demo.hibernate;

import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Persistence;

public class Test {
    public static void main(String[] args) {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
        factory.close();
    }

    @Entity(name = "Person")
    public static class Person {
        @Id
        @GeneratedValue
        Long id;
        @Basic(optional = false)
        String name;
    }
}

生成的 SQL

drop table if exists Person cascade
drop sequence if exists hibernate_sequence

create sequence hibernate_sequence start 1 increment 1
create table Person (id int8 not null, name varchar(255) not null, primary key (id))

如果先生成表

drop table if exists Person cascade;
drop sequence if exists hibernate_sequence;

create sequence hibernate_sequence start 1 increment 1;
create table Person (id int8 not null, name varchar(255), primary key (id));

然后修改 src/main/resources/META-INF/persistence.xml 去除 javax.persistence.schema-generation.database.action

<persistence 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"
  version="2.1">
  <persistence-unit name="test">
    <properties>
      <property name="javax.persistence.jdbc.url" value="jdbc:p6spy:postgresql://localhost:5432/test" />
      <property name="javax.persistence.jdbc.user" value="postgres" />
      <property name="javax.persistence.jdbc.password" value="postgres" />
    </properties>
  </persistence-unit>
</persistence>

然后执行

package org.example.demo.hibernate;

import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Persistence;

public class Test {
    public static void main(String[] args) {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
        EntityManager em = factory.createEntityManager();

        em.getTransaction().begin();
        em.persist(new Person());
        em.getTransaction().commit();

        em.close();
        factory.close();
    }

    @Entity(name = "Person")
    public static class Person {
        @Id
        @GeneratedValue
        Long id;
        @Basic(optional = false)
        String name;
    }
}

在 17 行依然报异常 javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value : org.example.demo.hibernate.Test$Person.name

即 Hibernate 不管数据库是否有 not null 约束,只要 @Basic.optional = false 则会检查是否 null

results matching ""

    No results matching ""