严格来说,应该在 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