1.@Entity 

 通过注释@Entity或者(@Entity())表示被标示的类对应数据库中的一张表。 

 } 

@Entity 

public class TravelProfile { 

... 

} 

 上面的例子告诉O/R映射引擎,类TravelProfile是可以持久化的,同时它对应数据库中的一张表。但是它没有指明对应哪个数据库中的哪张表。 

2.元数据映射标记 

2.1 @Table 

@Table()标记为实体初始化一张表,定义如下: 

@Target({TYPE}) @Retention(RUNTIME) 

public @interface Table { 

String name() default ""; 

String catalog() default ""; 

String schema() default ""; 

UniqueConstraint[] uniqueConstraints() default {}; 

} 

Name:指明表的名字。(可选) 

Catalog:表示表的catalog.(可选) 

Schema:表示表的schema.(可选) 

uniqueConstraints:制定表的唯一约束。(可选) 

因为所有的属性都是可选的,也就是说@Table可以在进行映射的时候可以不标明。当不标明的情况下表的名字就是实体的类名。表属于的schema就是所属实体单元集的schema(就是当前连接数据库的用户)。 

下面给出的例子中,指明表为CUST,所属的schema为RECORDS: 

@Entity 

@Table(name="CUST", schema="RECORDS") 

public class Customer { ... } 


2.2 @UniqueConstraint标记 

@UniqueConstraint用来指定表字段的唯一约束,定义如下: 

@Target({}) @Retention(RUNTIME) 

public @interface UniqueConstraint { 

String[] columnNames(); 

} 

columnNames:制定唯一约束的字段。 


@Entity 

@Table( 

name="EMPLOYEE", 

uniqueConstraints= 

@UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"}) 

) 

public class Employee { ... } 

上面的例子,唯一约束标记指定字段EMP_ID和字段EMP_NAME在表中EMPLOYEE中是唯一的。 

2.3@Column标记 

@Column标记把实体的属性或域映射到表的字段,当没有在实体的属性或域中使用该标记那数据库的对应表的字段名就是实体的属性名或域名。其定义为: 

@Target({METHOD, FIELD}) @Retention(RUNTIME) 

public @interface Column { 

String name() default ""; 

boolean unique() default false; 

boolean nullable() default true; 

boolean insertable() default true; 

boolean updatable() default true; 

String columnDefinition() default ""; 

String table() default ""; 

int length() default 255; 

int precision() default 0; // decimal precision 

int scale() default 0; // decimal scale 

} 

 Name:指定字段名。 

 Unique:指明该字段是否唯一,默认为false。 

 Nullable:指明是否可以为空,默认是true。 

 Insertable:指明该字段在产生SQL INSERT语句中是否产生该字段。 

Updatable:指明该字段在产生SQL INSERT语句中是否产生该字段。 

columnDefinition:指定产生表的时候,使用它指定该字段一些属性。 

Table:当一个实体对应多个表的时候,指定该字段属于哪个表。 

Length:制定该字段的长度(只有在字段为字符类型的才有用),默认是255。 

Precision: 指明字段的精度(在字段为decimal类型的时候使用),默认是0 

Scale:为字段为number型指定标量,默认为0。 

下面给出例子: 

@Column(name="DESC", nullable=false, length=512) 

public String getDescription() { return description; } 


@Column(name="DESC", 

columnDefinition="CLOB NOT NULL", 

table="EMP_DETAIL") 

@Lob 

public String getDescription() { return description; } 


@Column(name="ORDER_COST", updatable=false, precision=12, scale=2) 

public BigDecimal getCost() { return cost; } 


2.4@JoinColumn标记 

@JoinColumn标记用来映射实体之间的关联关系,定义如下: 

@Target({METHOD, FIELD}) @Retention(RUNTIME) 

public @interface JoinColumn { 

String name() default ""; 

String referencedColumnName() default ""; 

boolean unique() default false; 

boolean nullable() default true; 

boolean insertable() default true; 

boolean updatable() default true; 

String columnDefinition() default ""; 

String table() default ""; 

} 

Name:指定外键字段名,缺省的名字是被引用实体在引用实体内部的属性标量名或域名加上下划线”_”,再加上被引用实体的主键字段名构成。 

ReferencedColumnName:被引用表的字段,如果没有那缺省的就是该表的主键。 

 Unique:指明该字段是否唯一,默认为false。 

 Nullable:外键是否可以为空,默认是true。 

 Insertable:指明该字段在产生SQL INSERT语句中是否产生该字段。 

Updatable:指明该字段在产生SQL INSERT语句中是否产生该字段。 

columnDefinition:指定产生表的时候,使用它指定该字段一些属性。 

Table:当一个实体对应多个表的时候,指定该字段属于哪个表。 

下面例子的多对一关系中,指明了被引用实体在本实体的外键为ADDR_ID。 

@ManyToOne 

@JoinColumn(name="ADDR_ID") 

public Address getAddress() { return address; } 


2.5@JoinColumns标记 

@JoinColumns标记用在符合外键的时候,这个时候属性name和referencedColumnName必须在@JoinColumn中进行初始化。例如: 

@ManyToOne 

@JoinColumns({ 

@JoinColumn(name="ADDR_ID", referencedColumnName="ID"), 

@JoinColumn(name="ADDR_ZIP", referencedColumnName="ZIP") 

}) 

public Address getAddress() { return address; } 


2.6@Id标记 

@Id标记把实体属性或域映射到表的主键。其定义如下: 

@Target({METHOD, FIELD}) @Retention(RUNTIME) 

public @interface Id {} 

下面例子通过标记@Id初始化实体的主键为id,也可以通过加上标记@Column(name=”PrimaryKey”)自定义表的主键。 

@Id 

public Long getId() { return id; } 


2.7@GeneratedValue标记 

提供产生主键的策略,这就意味着它只能在出现标记@Id的情况下使用。其定义如下: 

@Target({METHOD, FIELD}) @Retention(RUNTIME) 

public @interface GeneratedValue { 

GenerationType strategy() default AUTO; 

String generator() default ""; 

} 


public enum GenerationType { TABLE, SEQUENCE, IDENTITY, AUTO }; 

策略类型为枚举类型,共有四种类型分别为:TABLE, SEQUENCE, IDENTITY, AUTO。 

TABLE:提示持久化引擎实现者,使用数据库的表来产生和维护主键。 

SEQUENCE和IDENTITY:分别指定使用当前数据库的序列号和标识字段来产生唯一表识。 

AUTO:制定持久化引擎实现者,为不同的数据库选择合适的策略产生唯一标识。 


Generator:制定主键产生器,默认有持久化实现者提供。例如: 

@Id 

@GeneratedValue(strategy=SEQUENCE, generator="CUST_SEQ") 

@Column(name="CUST_ID") 

public Long getId() { return id; } 


@Id 

@GeneratedValue(strategy=TABLE, generator="CUST_GEN") 

@Column(name="CUST_ID") 

Long id; 


2.8@IdClass标记 

 这个标记用来指定一个实体类作为一个另外一个实体的主键。这个时候要求实体的复合主键的每个属性或域必须和复合主键类对应的属性或域是一样的。其定义如下: 

@Target({TYPE}) @Retention(RUNTIME) 

public @interface IdClass { 

Class value(); 

} 

下面例子中,复合主键类为EmployeePK,包含域empName和birthday类型分别为String,Date。 

@IdClass(com.jl.hr.EmployeePK.class) 

@Entity 

public class Employee { 

@Id String empName; 

@Id Date birthDay; 


2.9@Transient标记 

标记指示实体的属性或域是非持久化的。其定义如下: 

@Target({METHOD, FIELD}) @Retention(RUNTIME) 

public @interface Transient {} 


下面的例子说明实体 Employee的域currentUser是非持久化的。 

@Entity 

public class Employee { 

@Id int id; 

@Transient User currentUser; 

... 

} 


2.10@Version标记 

初始化实体的乐观锁的值,这个标记在大量并发访问的实体中非常有用。如果要对实体使用这个标记那最好的策略是一个实体使用一个@Version标记,同时这个标记对应字段的类型一般为:int,Integer,short,Short,long,Long,Timestamp中的一种。其定义如下: 

@Target({METHOD, FIELD}) @Retention(RUNTIME) 

public @interface Version {} 


给出相关的例子如下: 

@Version 

@Column(name="OPTLOCK") 

protected int getVersionNum() { return versionNum; } 


2.11@Lob标记 

 此标记初始化实体的属性或域映射成数据库支持的大对象类型。大对象可以是字符也可以是二进制类型。除了字符串和字符类型的默认映射成Blob类型,其它的类型根据实体属性或域的类型来决定数据库大对象的类型。例如: 

@Lob 

@Column(name="REPORT") 

protected String report; 


@Lob @Basic(fetch=LAZY) 

@Column(name="EMP_PIC", columnDefinition="BLOB NOT NULL") 

protected byte[] pic; 


2.12@Enumerated标记 

 用来指定实体持久化属性的为枚举类型,其定义如下: 

@Target({METHOD, FIELD}) @Retention(RUNTIME) 

public @interface Enumerated { 

EnumType value() default ORDINAL; 

} 


public enum EnumType { 

ORDINAL, 

STRING 

} 

如果标记没有显性给出或者EnumType没有指定,那枚举类型默认为ORDINAL数字标识。例如: 

public enum EmployeeStatus {FULL_TIME, PART_TIME, CONTRACT} 

public enum SalaryRate {JUNIOR, SENIOR, MANAGER, EXECUTIVE} 

@Entity public class Employee { 

... 

public EmployeeStatus getStatus() {...} 

@Enumerated(STRING) 

public SalaryRate getPayScale() {...} 

... 

} 

上面例子中,定义了两个枚举类型EmployeeStatus和SalaryRate。在实体两个属性status类型为EmployeeStatus,而payScale为SalaryRate类型。其中一个显性给出了标记@Enumerated(STRING)来说明枚举类型的值当成字符串使用,而默认的是从1开始的数字来标识的。也可以通过标记@Enumerated(ORDINAL)指示枚举里面类型的值是数字类型的。例如在EmployeeStatus 

中的FULL_TIME, PART_TIME, CONTRACT分别代表的数字是1,2,3,4而SalaryRate 

中的JUNIOR, SENIOR, MANAGER, EXECUTIVE代表的分别是字符串“JUNIOR”, “SENIOR”, “MANAGER”, “EXECUTIVE”。 


2.13@ManyToOne标记 

 当实体之间的关系是多对一的时候,该标记定义一个单值的字段与其它实体相关联。其定义如下: 

@Target({METHOD, FIELD}) @Retention(RUNTIME) 

public @interface ManyToOne { 

Class targetEntity() default void.class; 

CascadeType[] cascade() default {}; 

FetchType fetch() default EAGER; 

boolean optional() default true; 

} 


public enum CascadeType { ALL, PERSIST, MERGE, REMOVE, REFRESH}; 


targetEntity:表示相关联的实体类。 

Cascade:级联操作选项,PERSIST, MERGE, REMOVE, REFRESH分别对应增加,更新,删除和查找的联级设置选项。如果选择ALL就使得前面这些联级都生效,也就是cascade=ALL 等同于cascade={PERSIST, MERGE, REMOVE,REFRESH} 

Fetch:制定关联实体的加载方式,包括EAGER和LAZY两种方式。当为EAGER选选项的时候,当查询实体的时候会把它相关联的实体实例也加载。当为LAZY的时候加载实体实例的时候与之相关联的实体实例不会加载,默认为EAGER。 

Optional:指定关联实体关系是否可以为空,默认是为true。当为false的时候,那当有实体实例的存在总会有与之相关实体实例的存在。 

例如: 

@ManyToOne(optional=flase) 

@JoinColumn(name="CUST_ID", nullable=false, updatable=false) 

public Customer getCustomer() { return customer; } 


2.14@OneToOne标记 

标记定义实体一对一关系的联系,通过一个字段来进行关联。其定义如下: 

@Target({METHOD, FIELD}) @Retention(RUNTIME) 

public @interface OneToOne { 

Class targetEntity() default void.class; 

CascadeType[] cascade() default {}; 

FetchType fetch() default EAGER; 

boolean optional() default true; 

String mappedBy() default ""; 

} 

前面四个选项和8.2.13中的意义是一样的。 

mappedBy:代表这个属性或域是关系的拥有者,也就是说mappedBy选择应该是在非关系拥有者方才会出现。所谓关系的拥有者就是在表中包含了关系字段的那张表。 

现在假设有实体Customer和实体CustomerRecoder它们之间是一对一的关系,同时实体Customer是关系的拥有者。这个时候通过标记@OneToOne来完成关联,在实体Customer相关代码如下: 

@OneToOne(optional=false) 

@JoinColumn( 

name="CUSTREC_ID", unique=true, nullable=false, updatable=false) 

public CustomerRecord getCustomerRecord() { return customerRecord; } 

在实体CustomerRecord相关代码如下: 

@OneToOne(optional=false, mappedBy="customerRecord") 

public Customer getCustomer() { return customer; } 

因为CustomerRecord是关系的非拥有者所有mappedBy只能在这边出现。 



2.15@OneToMany标记 

用来标记实体之间的一对多的关系,其定义如下: 

@Target({METHOD, FIELD}) @Retention(RUNTIME) 

public @interface OneToMany { 

Class targetEntity() default void.class; 

CascadeType[] cascade() default {}; 

FetchType fetch() default LAZY; 

String mappedBy() default ""; 

} 

值得注意的是表示关联实体的集合要使用范形来制定集合内部的关联实体,否则必须要指定targetEntity的实体类型。Fetch类型默认为LAZY而@OneToOne和ManyToOne则默认的为EAGER。 

假设现在有实体Customer和Order它们之间的关系是一对多的关系,同时Order是关系的拥有者。 

在实体Customer中的代码为: 


@OneToMany(cascade=ALL, mappedBy=”customer”) 

public Set<Order> getOrders() { return orders; } 


在实体Order中的代码为: 


@ManyToOne 

@JoinColumn(name="CUST_ID", nullable=false) 

public Customer getCustomer() { return customer; } 


2.16@JoinTable标记 

用来映射多对多和单项的一对多关系,当不是用该标记的时候会根据默认的映射原则产生关系连接表。其定义如下: 

public @interface JoinTable { 

String name() default ""; 

String catalog() default ""; 

String schema() default ""; 

JoinColumn[] joinColumns() default {}; 

JoinColumn[] inverseJoinColumns() default {}; 

UniqueConstraint[] uniqueConstraints() default {}; 

} 

Name:指定连接表的名字。 

Catalog:指定表所属的catalog。 

Schema:指定表所属的schema。 

joinColumns:指定关系拥有方作为外键的主键。 

inverseJoinColumns:指定关系非拥有方作为外键的主键。 

uniqueConstraints:指定表中的唯一约束。 

例如: 

@JoinTable( 

name="CUST_PHONE", 

joinColumns= 

@JoinColumn(name="CUST_ID", referencedColumnName="ID"), 

inverseJoinColumns= 

@JoinColumn(name="PHONE_ID", referencedColumnName="ID") 

) 

上面例子,连接表的名字为CUST_PHONE里面有两个外键,一个来自关系拥有方的主键ID对应外键为CUST_ID;另一个是来自于关系的非拥有方的主键ID对应外键为PHONE_ID。 

2.17@ManyToMany标记 

标记实体之间的多对多的关系,如果不通过范形来制定集合中的关联实体类型那必须指定相应的关联实体类型。其定义如下: 

@Target({METHOD, FIELD}) @Retention(RUNTIME) 

public @interface ManyToMany { 

Class targetEntity() default void.class; 

CascadeType[] cascade() default {}; 

FetchType fetch() default LAZY; 

String mappedBy() default ""; 

} 

各个属性的意义和标记@OneToMany是一样的,请参照8.2.1.15。 

如果关联是双向的两边都可以是关系的拥有方,可以通过标记@JoinTable来制定关系拥有方,请参照2.16。 

设有实体Customer和PhoneNumber,则它们的关系映射代码如下: 

在实体Customer中为: 

@ManyToMany 

@JoinTable(name="CUST_PHONES") 

public Set<PhoneNumber> getPhones() { return phones; } 

在实体PhoneNumber中为: 

@ManyToMany(mappedBy="phones") 

public Set<Customer> getCustomers() { return customers; } 

在实际开发中,对于多对多关系我们经常使用标记@JoinTable来制定关系的拥有方,则对于上面的映射为: 

@ManyToMany 

@JoinTable( 

name="CUST_PHONE", 

joinColumns= 

@JoinColumn(name="CUST_ID", referencedColumnName="ID"), 

inverseJoinColumns= 

@JoinColumn(name="PHONE_ID", referencedColumnName="ID") 

) 

public Set<PhoneNumber> getPhones() { return phones; } 


@ManyToMany(mappedBy="phones") 

public Set<Customer> getCustomers() { return customers; } 


2.18@OrderBy标记 

指定批量查询实例实例的时候指定排序的属性或域,其定义如下: 

@Target({METHOD, FIELD}) @Retention(RUNTIME) 

public @interface OrderBy { 

String value() default ""; 

} 

对于使用该标记对应的字段必须是可以比较的,默认的使用的是ASC也可以根据需求改变成DESC。当没有指定value的时候,那默认的就是对实体的主键进行排序,例如: 

@Entity public class Course { 

... 

@ManyToMany 

@OrderBy("lastname ASC") 

public List<Student> getStudents() {...}; 

... 

} 

@Entity public class Student { 

... 

@ManyToMany(mappedBy="students") 

@OrderBy // PK is assumed 

public List<Course> getCourses() {...}; 

... 

}