基本映射
一、 @Table
@javax.persistence.Table 注解可以改变实体类默认映射的表名
把 book 实体映射给 T_BOOK 表
@Entity @Table(name = "t_book") public class Book { @Id private Long id; private String title; private Float price; private String description; private String isbn; private Integer nbOfPage; private Boolean illustrations; public Book() { } // Getters, setters }
注意,根据数据库的不同,实体类默认映射到数据库的表名,有可能全大写,有可能全小写。
二、 @SecondaryTable
我们可以用该注解定义实体关联的一个或多个次表,用 @Column(table = "XXX") 指定属性指向的次表,看下面的例子:
@Entity @SecondaryTables({ @SecondaryTable(name = "city"), @SecondaryTable(name = "country") }) public class Address { @Id private Long id; private String street1; private String street2; @Column(table = "city") private String city; @Column(table = "city") private String state; @Column(table = "city") private String zipcode; @Column(table = "country") private String country; // Constructors, getters, setters }
该实体映射图:
每个表都有相同的主键。
注意:当使用次表时,你应该考虑性能问题。每次你访问这样的一个实体,持久化实现类访问多个表,用 join 的方式将他们关联。当你有大数据对象 (BLOBs), 用次表将大数据对象隔离是很好的。
三、主键
@javax.persistence.Id 注释属性可以是以下类型:
1. 基本 Java 类型: byte,int,short,long,char 。
2. 包装的基本 Java 类型: Byte,Integer,Short,Long,Character 。
3. 基本 Java 类型或包装的基本 Java 类型数组 :int[],Integer[] 等等。
4. 字符串,数字类型和日期 :java.lang.String,java.math.BigInteger,java.util.Date,java.sql.Date
主键值可以手动赋值,也可以通过 @GeneratedValue 注解自动赋值。该注解有 4 个值:
-
SEQUENCE 和 IDENTITY 是根据数据库的 sequence 或 identity 自增主键值
-
TABLE 是用数据库表来储存主键 ( 主键名和主键值 )
-
AUTO 是默认值,根据特定数据库选择相应的主键生成策略
四、复合主键
在 JPA 里我们有 2 种方式定义主键: @EmbeddedId 和 @IdClass
通常将复合主键相关属性,单独抽取出来,建立一个独立的类,这个类就是主键类,要求:
1. 复合主键必须重写 equals 和 hashcode 方法 (JPA 查找缓存的持久化对象 )
2. 必须实现 Serializable 接口
@EmbeddedId
查看下例:
@Embeddable public class NewsId implements Serializable{ private String title; private String language; // Constructors, getters, setters, equals, and hashcode }
@Entity public class News { @EmbeddedId private NewsId id; private String content; // Constructors, getters, setters }
看看我们怎么用复合主键查询:
NewsId pk = new NewsId("Richard Wright has died", "EN")
News news = em.find(News.class, pk);
@IdClass
以这种方式的复合主键类不需要任何注解:
public class NewsId implements Serializable{ private String title; private String language; // Constructors, getters, setters, equals, and hashcode }
@Entity @IdClass(NewsId.class) public class News { @Id private String title; @Id private String language; private String content; // Constructors, getters, setters, equals, and hashcode }
@EmbeddedId 和 @IdClass 这两种方式都被映射为同一个表结构
CREATE TABLE `news` ( `language` varchar(255) NOT NULL, `title` varchar(255) NOT NULL, `content` varchar(255) DEFAULT NULL, PRIMARY KEY (`language`,`title`) )
明显的不同是 JPQL 查询:
用 @IDClass 时:
select n.title from News n
用 @EmbeddedID 时:
select n.newsId.title from News n
五、属性
实体属性可以是以下类型:
-
Java 基本数据类型 (int,double,float 等 ) 及其包装类 (Integer,Double,Float 等 )
-
字节和字符数组 (byte[],Byte[],char[],Character[])
-
字符串,大数据类型,时间类型 (java.lang.String,java.math.BigInteger,java.math.BigDecimal,java.util.Date,java.util.Calendar,java.sql.Date,java.sql.Time,java.sql.Timestamp)
-
枚举类和用户自定义实现 Serialiable 接口类型
-
基础集合类和嵌入类型
六、 @Basic
可选注解 @javax.persistence.Basic 是映射数据库列的最基本类型。
@Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface Basic { FetchType fetch() default EAGER; boolean optional() default true; }
这个注解有 2 个参数: optional 和 fetch.
optional 元素指定属性的值是否为空 ( 忽略基本类型,因为基本类型是非空类型 )
fetch 元素有 2 个值: LAZY 或 EAGER 。指定属性数据是否是懒加载或立即加载。
比如我们有一个 Track( 音轨 ) 实体,有一个 WAV 属性 (WAV 文件是一个 BLOB ,可能有几兆 ) ,当我们访问 Track 实体时,我们不想立即加载 WAV 文件。
@Entity public class Track { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String title; private float duration; @Basic(fetch = FetchType.LAZY) @Lob private byte[] wav; private String description; // Constructors, getters, setters }
七、 @Column
@Column 注解元素
@Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface Column { String name() default ""; /** * (Optional) Whether the column is a unique key. This is a * shortcut for the <code>UniqueConstraint</code> annotation at the table * level and is useful for when the unique key constraint * corresponds to only a single column. This constraint applies * in addition to any constraint entailed by primary key mapping and * to constraints specified at the table level. */ boolean unique() default false; /** * (Optional) Whether the database column is nullable. */ boolean nullable() default true; /** * (Optional) Whether the column is included in SQL INSERT * statements generated by the persistence provider. */ boolean insertable() default true; /** * (Optional) Whether the column is included in SQL UPDATE * statements generated by the persistence provider. */ boolean updatable() default true; /** * (Optional) The SQL fragment that is used when * generating the DDL for the column. * <p> Defaults to the generated SQL to create a * column of the inferred type. */ String columnDefinition() default ""; /** * (Optional) The name of the table that contains the column. * If absent the column is assumed to be in the primary table. */ String table() default ""; /** * (Optional) The column length. (Applies only if a * string-valued column is used.) */ int length() default 255; /** * (Optional) The precision for a decimal (exact numeric) * column. (Applies only if a decimal column is used.) * Value must be set by developer if used when generating * the DDL for the column. */ int precision() default 0; /** * (Optional) The scale for a decimal (exact numeric) column. * (Applies only if a decimal column is used.) */ int scale() default 0; }
你可以通过该注解修改列名,列字段大小,是否为空, unique( 唯一 ) ,允许它的值被更新、插入。
我们重新定义原来的 Book 实体
@Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(name = "book_title", nullable = false, updatable = false) private String title; private Float price; @Column(length = 2000) private String description; private String isbn; @Column(name = "nb_of_page", nullable = false) private Integer nbOfPage; private Boolean illustrations; // Constructors, getters, setters }
BOOK 表 DDL :
CREATE TABLE `book` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `description` longtext, `illustrations` bit(1) DEFAULT NULL, `isbn` varchar(255) DEFAULT NULL, `nb_of_page` int(11) NOT NULL, `price` float DEFAULT NULL, `book_title` varchar(255) NOT NULL, PRIMARY KEY (`id`) )
updatable 和 insertable 默认值是true ,当他们的值是 false 时,产生的 SQL 语句将不包含相应的列。
八、 @Temporal
@javax.persistence.Temporal 注解用来表示时间日期,可以是 :DATE,TIME,TIMESTAMP.
看下例:
@Entity public class Customer { @Id @GeneratedValue private Long id; private String firstName; private String lastName; private String email; private String phoneNumber; @Temporal(TemporalType.DATE) private Date dateOfBirth; @Temporal(TemporalType.TIMESTAMP) private Date creationDate; // Constructors, getters, setters }
九、 @Transient
JPA 中,注解 @Entity 的类,所有的属性都会被自动映射到相应的表中。如果你不需映射类中的某个属性,可以使用 @javax.persistence.Transient 注解。
@Entity public class Customer { @Id @GeneratedValue private Long id; private String firstName; private String lastName; private String email; private String phoneNumber; @Temporal(TemporalType.DATE) private Date dateOfBirth; @Transient private Integer age; @Temporal(TemporalType.TIMESTAMP) private Date creationDate; // Constructors, getters, setters }
age 属性映射被忽略
十、 @Enumerated
我们看一下 CreditCardType 枚举类
public enum CreditCardType { VISA, MASTER_CARD, AMERICAN_EXPRESS }
枚举类的值是常量,并且以声明的顺序赋予 int 值。编译时, VISA 赋予 0 , MASTER_CARD 赋予 1 , AMERICAN_EXPRESS 赋予 2. 持久化实现默认将枚举类型映射为 Integer 。
@Entity @Table(name = "credit_card") public class CreditCard { @Id private String number; private String expiryDate; private Integer controlNumber; private CreditCardType creditCardType; // Constructors, getters, setters }
如果从中加入新的枚举常量,保存在数据库中的一些值将不再匹配枚举。一个好的办法是保存字符值,而不是顺序值。通过 @Enumerated(EnumType.STRING) ,顺序值 (ORDINAL 是默认值 ) :
@Entity @Table(name = "credit_card") public class CreditCard { @Id private String number; private String expiryDate; private Integer controlNumber; @Enumerated(EnumType.STRING) private CreditCardType creditCardType; // Constructors, getters, setters }
十一、访问类型
到现在为止,我们标注类 (@Entity,@Table) 和属性 (@Basic,@Column,@Temporal 等 ) ,我们将注解应用在字段上 (field access) 也可以注解在相应的属性上 (property access:getter method). 例:我们将注解 @Id 标注在 id 字段上,同样也可以标注在 getId() 的方法上。这很大程度上是个人偏好。我趋向于注解在属性上 ( 注解 getters) ,这样可以很容易阅读实体类拥有的字段。在这个教程里,为了可读性,我们把注解标注在字段上。
当我们把注解标注在字段上,实体类的访问类型就为字段类型,持久化实现将映射所有的字段 ( 没有标注 @Transient) 并将其持久化。
当我们把注解标注在属性 ( 注解 getters) 上,实体类的访问类型就为属性类型,持久化实现将映射所有的属性 ( 没有标注 @Transient) 并将其持久化。
如果没有通过显示指定访问类型,我们不能既标注字段又标注属性,否则会报错。
例:
标注字段:
@Entity public class Customer { @Id @GeneratedValue private Long id; @Column(name = "first_name", nullable = false, length = 50) private String firstName; @Column(name = "last_name", nullable = false, length = 50) private String lastName; private String email; @Column(name = "phone_number", length = 15) private String phoneNumber; // Constructors, getters, setters }
标注属性:
@Entity public class Customer { private Long id; private String firstName; private String lastName; private String email; private String phoneNumber; // Constructors @Id @GeneratedValue public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Column(name = "first_name", nullable = false, length = 50) public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } @Column(name = "last_name", nullable = false, length = 50) public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Column(name = "phone_number", length = 15) public String getPhoneNumber() { return phoneNumber; } public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } }
通过注解 @Access 可以指定标注类型,有 2 种参数值: AccessType.FIELD,AccessType.PROPERTY
@Entity @Access(AccessType.FIELD) public class Customer { @Id @GeneratedValue private Long id; @Column(name = "first_name", nullable = false, length = 50) private String firstName; @Column(name = "last_name", nullable = false, length = 50) private String lastName; private String email; @Column(name = "phone_number", length = 15) private String phoneNumber; // Constructors, getters, setters @Access(AccessType.PROPERTY) @Column(name = "phone_number", length = 555) public String getPhoneNumber() { return phoneNumber; } public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } }
标注在属性上的 @Access 将覆盖实体类级别的访问类型。所以最后 "phone_number" 的列上为 555(VARCHAR(555)).
十二、基本类型集合映射
在 JPA2.0 中, @ElementCollection 注解指定下列基本类型集合:
-
java.util.Collection
-
java.util.Set
-
java.util.List
持久化实现默认会生成一个 " 实体类名 _ 集合属性名 " 的集合表来储存集合值。
我们可以通过 @CollectionTable 注解来修改集合表名,通过 @Column 来修改集合表列名字 ( 默认是 " 集合的属性名 ")
例:
@Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String title; private Float price; private String description; private String isbn; private Integer nbOfPage; private Boolean illustrations; @ElementCollection(fetch = FetchType.LAZY) @CollectionTable(name = "Tag") @Column(name = "Value") private List<String> tags = new ArrayList<String>(); // Constructors, getters, setters }
映射表:
十三、基本类型 Map 映射
在 JPA1.0 中, Map 映射中的 Keys 必须是基本类型, Values 必须是实体。现在,无论是 Keys 还是 Values 都可以包含基本数据类型,嵌入对象,和实体。
和基本类型集合映射一样,我们用 @ElementCollection 注解标注属性类型是 Map 类型。
通过 @CollectionTable 注解来修改 Map 表名 ( 默认是 " 实体类名 _Map 的属性名 ") ,
通过 @Column 来修改 Map 表 value 列名字 ( 默认是 "Map 的属性名 ")
通过 @MapKeyColumn 来修改 Map 表 key 列名字 ( 默认是 "Map 的属性名 _KEY")
例:
@Entity public class CD { @Id @GeneratedValue private Long id; private String title; private Float price; private String description; @Lob private byte[] cover; @ElementCollection @CollectionTable(name = "track") @MapKeyColumn(name = "position") @Column(name = "title") private Map<Integer, String> tracks = new HashMap<Integer, String>(); // Constructors, getters, setters }
映射表:
相关推荐
而Hibernate作为持久层框架,简化了数据库操作,提供了ORM(对象关系映射)功能。 SSH框架的整合使得开发者能够更有效地管理应用程序的各个层次,实现松耦合、高复用的设计。例如,通过Spring的DI,可以轻松地更换...
3. 实体类与对象关系映射:讲解如何定义Java实体类,并使用注解或XML文件进行对象关系映射,包括基本类型映射、关联映射(一对一、一对多、多对一、多对多)和继承映射。 4. Session与Transaction:介绍Hibernate的...
- **数据访问集成(Data Access/Integration)**:Spring提供了JDBC抽象层,简化了数据库操作,同时支持ORM(对象关系映射)框架如Hibernate和MyBatis。 - **MVC框架(Model-View-Controller)**:Spring MVC是...
这部分内容主要包含Part07和Part09两个部分,旨在帮助开发者提升在数据库操作和对象关系映射方面的技能。 Part07可能涉及的主题包括: 1. **持久化策略**:讲解了Hibernate的各种持久化策略,如懒加载(Lazy ...
总结来说,“Linq-To-Sql-Part_2-Define-Data-Model-Class”这个主题将指导你如何使用LINQ to SQL创建数据模型类,理解对象关系映射原理,以及如何编写查询和管理数据库交互。了解这些知识点后,你可以更有效地在...
3. **映射文件详解**:详细讲解XML或注解方式的实体映射,包括属性映射、关系映射(一对一、一对多、多对多)、继承映射等。 4. **HQL(Hibernate Query Language)**: Hibernate自己的查询语言,类似于SQL,但更...
5. **多对多关系映射**:详述如何配置和处理多对多关联,包括中间表的管理,以及集合的懒加载和级联操作。 6. **一对一关系映射**:深入讨论一对一关系的配置,包括外键约束、主键共享以及一对一关系的级联操作。 ...
本文件《ASAM_XCP_Part2-Protocol-Layer-Specification_V1-1-0》是ASAM XCP协议族中第二部分的内容,专注于协议层的规范说明。 XCP协议族是基于主从结构的通信协议,用于实现从主站(例如上位机软件或测试设备)对...
B.2 运用反射机制来持久化Java对象 附录C 用XDoclet工具生成映射文件 C.1 创建带有@hibernate标记的Java源文件 C.2 建立项目的目录结构 C.3 运行XDoclet工具 附录D 发布和运行netstore应用 D.1 运行...
通过ORM(对象关系映射),它将Java对象映射到数据库表,使得开发者可以使用面向对象的方式来操作数据库。 - Spring:是Java企业级应用开发的核心框架,提供依赖注入、AOP(面向切面编程)、事务管理等功能,使得...
Hibernate是一个流行的开源对象关系映射(ORM)框架,它允许Java开发者在处理数据库时使用面向对象的方式,极大地简化了数据库操作。在这个版本中,我们可能会发现一系列用于数据库交互的API、配置文件、示例代码和...
在Java世界中,ORM(对象关系映射)框架如Hibernate极大地简化了数据库操作。本篇文章主要探讨的是Hibernate中的一对多关联关系映射,这是在实际项目开发中非常常见的一种关系映射类型。通过理解并掌握一对多关联,...
Hibernate是Java领域中一款广泛应用的关系对象映射框架,它允许开发者使用面向对象的方式来操作数据库,大大简化了数据访问层的编码工作。这个压缩包“hibernate4.2.3-part01”很可能是Hibernate 4.2.3版本的一部分...
Hibernate是一个广泛使用的Java库,用于将对象关系映射(ORM)到关系数据库,简化数据库操作,让开发者可以使用面向对象的方式来处理数据库。 在Java世界中,ORM工具如Hibernate消除了手动编写SQL语句的需要,使得...
Hibernate作为Java领域中最流行的ORM(对象关系映射)工具,它允许开发者以面向对象的方式处理数据库操作,简化了数据库与Java应用程序之间的交互。一对一关系映射是数据库设计中常见的一种关联类型,表示一个实体与...
Hibernate,作为一个流行的开源对象关系映射(ORM)框架,为Java开发者提供了一种简单而强大的方式来管理数据库操作。在Java应用中,Hibernate使得开发人员可以将业务逻辑与数据库操作解耦,从而更加专注于应用程序...