jpa学习(个人整理,非转帖)详细请下载 http://download.csdn.net/source/1995131

第一部分:实现域模型

1.一些基本理论

域模型是和持久化是密不可分的概念。通常,开发企业项目的第一个步大都就是创建域模型,即列出域中的实体并且定义实体之间的关系。(当然这基本说的是领域建模,好多公司的项目还是采用的数据库建模的形式。)

1.1域模型的相关概念

域模型的四个参与者:对象、关系、关系多样性和关系的可选性。

1》  对象

java对象一样,域模型可以同时具有行为(在java在的方法)和状态(java的实体变量)

2》  关系

java角度来看,关系表现为一个对象引用另一个对象。

充血域模型与贫血域模型

域模型实际上被持久化到数据库中,数据库建模经常和域建模是同义的,域对象包含属性(映射到数据库表的列)而非行为,这种类型的建模被称为贫血模型。

充血模型封装对象的属性、行为,并且利用面向对象实用程序设计方法。(比如继承、多态和封装)。域模型充血度越高,就越难以映射到数据库。

1.2 Ejb3 java持久化API

         Ejb3java持久化API是元数据驱动的pojo技术。也就是说,为了把java对象中的数据保持到数据库中,我们的对象不必实现接口、扩展类,或采用框架模式。

(简单的java对象实际就是普通的javabean是使用pojo名称是为了避免和ejb混淆起来)

声明:如果你熟悉sqljdbc并且喜欢通过自己动手的便利方式得到控制权和灵活性,那么O/R的成熟、技巧和自动化形式可能不适合你。如果情况是这样,那么你应该多了解Spinrg JdbcTemplate(这个我不喜欢用)和iBATIS(这个框架应该对你对对象的理解要求低很多)。可是我要警告您,java本身就是对象化的语言,我们要完美化,就要一切为对象。

2.使用JPA实现域对象    

本章意在描述域对象的实现过程,下一张将详细介绍如何使用对象-关系映射把我们创建的实体和关系映射到数据库中。

(当然现在JPA不仅仅是EJB3值得骄傲的地方,其它好多公司也相继实现了JPA规范,做出了很多优秀的orm框架。如:hibernateopenjpatoplink等。并且规范的好处就在于,你只要完全按照规范来写代码,这些框架你可以随意更换,并是不更改代码的前提下。)

书签:下面我们主要说的是如何定义一个实体bean,也就是如何把你的POJO映射为数据库对象。

2.1 @Entity

@Entity注解,它把POJO转换为实体。(以后我们常叫这样的POJO为实体Bean

jpa主要是支持注解的形式,简单是说也就是使用注解对你对象化的POJO进行声明表示,生成对应的数据库和对数据库进行对象化的封装。

那么,我们学习JPA也就无非是学习几个注解,并且通过我们对对象的理解,标识对象的关系等。我们常用的注解无法就二三十个注解,所以JPA会让你感觉原来那么简单)

package cn.partner4java.bean.part2_1;

import javax.persistence.Entity;

import javax.persistence.Id;

@Entity

public class User {

    @Id

    String userId;

    String username;

    String email;

}  

2.2持久化实体数据

?我们注解标识的位置:

持久化分为两种:基于字段与基于属性的持久化。

使用实体的字段或实体变量定义的O/R映射被称为基于字段的访问,也就是注解标注在字段上面。当然基于字段如果你省略了getset,也可以生产成功。

如:

package cn.partner4java.bean.part2_1;

import javax.persistence.Entity;

import javax.persistence.Id;

@Entity

public class User {

    @Id

    String userId;

    String username;

    String email;

}  

基于属性,必须标注在get方法上面,而非set

如:

package cn.partner4java.bean.part2_1;

import javax.persistence.Entity;

import javax.persistence.Id;

@Entity

public class User {

    String userId;

    String username;

    String email;

    @Id

    public String getUserId() {

       return userId;

    }

    public void setUserId(String userId) {

       this.userId = userId;

    }

    public String getUsername() {

       return username;

    }

    public void setUsername(String username) {

       this.username = username;

    }

    public String getEmail() {

       return email;

    }

    public void setEmail(String email) {

       this.email = email;

    }

   

}  

注意:同一个类中,不可同时使用两种方式。因为两种方式的内部实现方式有所区别。(当然你标注在哪里看你个人爱好了,我比较喜欢标注在字段上面,因为我查找和修改的时候方便一些,我也见很多人标注在属性上面,具体哪种性能上更优秀一些,寡人没具体研究过,的需要查看源码了,并且每种实现产品又不一样,所以一直懒得去看)

建议:当您定义字段时,最好声明为私有的。

因为持久化提供器可能需要覆盖设置器和获取器,所以不能持久化的设置器和获取器声明为final。也就是getset

?如果你也随着我说的,自己打并执行了上面的代码,你会发现usernameemail我们并没有进行任何的标识,也生产了相应的数据库字段,但是如果我们不想生成该怎么办?定义顺时字段:加上@Transsient。也就是有些字段你不想映射进数据库时。

这里我们就简单的说了一下,后面我们会通过其他的解决,顺便解决了这里的详细使用。

2.3指定实体身份

?为什么要有实体身份并且规定是必须进行指定:上面我们介绍了第一个注解@Entity,把POJO声明为实体bean。这是不够的,因为实体在某个时间必须被持久化为数据库表中唯一可表示的行(或多个表中行的集合),如果没有进行标识,你就不知道在执行保存操作之后数据被保持到哪一行了。(我们还需要重写equals方法,是比较两个明显不同数据库记录的主键在对象中的等效方式)

身份表示注解:

a@Id

b@IdClass

c@EmbeddedId

?问题:怎么会有3种注解,我平时用到的仅仅是@Id,我感觉应该学着带着问题和思考去学习一个知识。

?什么样的类型可标识为实体身份:EJB3支持原始类型、原始包装器和Serializable类型(比如java.lang.Stringjava.util.Datejava.sql.Date)作为身份,此外因为floatFloatdouble等类型不确定的特点,当选址数据类型时应该避免使用这些类型。

第一种:@Id,相信对jpa有一点点了解的人就会知道这是做什么的,怎么用。

?后两种注解出项的原因:你有时使用一个以上的属性或字段(复合键)唯一的标识实体。

第二种:@IdClass

如:(一般通过例子就完全可以理解的,我就不会多说了)

package cn.partner4java.bean.part2_3;

import java.io.Serializable;

import java.util.Date;

public class CategoryPK implements Serializable {

    private String name;

    private Date CreateDate;

    …hashCode()…equals(Object obj)

 

package cn.partner4java.bean.part2_3;

import java.util.Date;

import javax.persistence.Entity;

import javax.persistence.Id;

import javax.persistence.IdClass;

@Entity

@IdClass(CategoryPK.class)

public class Category {

    @Id

    private String name;

    @Id

    private Date CreateDate;

    private String realname;

}

第三种:@EmbeddedId

package cn.partner4java.bean.part2_3;

import java.io.Serializable;

import java.util.Date;

import javax.persistence.Embeddable;

@Embeddable

public class CategoryPK implements Serializable {

    private String name;

    private Date CreateDate;

。。。

package cn.partner4java.bean.part2_3;

import javax.persistence.EmbeddedId;

import javax.persistence.Entity;

@Entity

public class Category {

    @EmbeddedId

    private CategoryPK categoryPK;

    private String realname;

}

有些地方说:这里的CategoryPK可以不实现序列化Serializable,但事实是必须也实现。因为所有的字段都必须是序列化的。

这后两种生产复合主键的形式,都可以,看您个人爱好了

2.4 @Embeddable 注解

上面我们第三种方式用到了这个注解进行复合主键对象的声明。它主要用于嵌入对象,我们平时常用的是域对象。如实体关系,一对一。

使用场景:纯粹的面向对象的域建模,所有的域对象总都是可以独立标识的么?如果对象仅仅在其他的对象内部用作方便的数据占位器/组织方式会怎么样?一个常见的例子,是User对象内部使用Address对象,它作为优雅的面向对象的替换方式,替代列出街道地址、城市、邮编等直接作为User对象的字段。因为不太可能在User之外使用Address对象,所以Adress对象没有必要具有身份,这正好是@Embeddable的适用场景。

如:

package cn.partner4java.bean.part1_2_4;

import javax.persistence.Embeddable;

@Embeddable

public class Address {

    private String city;

    private String state;

    private String country;

}

package cn.partner4java.bean.part1_2_4;

import javax.persistence.Embedded;

import javax.persistence.Entity;

import javax.persistence.Id;

@Entity

public class User {

    @Id

    private Long id;

    private String username;

    @Embedded

    private Address address;

}

生成的表仅一个。但是我们如果想生成的是两个表,怎么办呢?是不是有什么属性表示一下?但是我们上面就说过,如果是单独表映射就需要身份表示,否则我们就不知道是对哪个字段进行操作。但是嵌入对象不需要唯一身份。那么就的选择使用实体关系的方式。

3.实体关系

域关系类型和相应注解

关系类型

注解

一对一

@OneToOne

一对多

@OneToMany

多对一

@ManyToOne

多对多

@ManyToMany

3.1 @OneToOne

单向一对一:

User对象具有对BillingInfo的引用,但是没有反向引用,换句话说,次关系是单向的。

package cn.partner4java.bean.part1_3_1;

import javax.persistence.Entity;

import javax.persistence.Id;

@Entity

public class BillingInfo {

    @Id

    private Long billingId;

    private String bankName;

}

 

package cn.partner4java.bean.part1_3_1;

import javax.persistence.Entity;

import javax.persistence.Id;

import javax.persistence.OneToOne;

 

@Entity

public class User {

    @Id

    private String userId;

    private String email;

    @OneToOne

    private BillingInfo billingInfo;

}

User表里面生成了相应的关系引用字段。

@OneToOne(optional=false)

private BillingInfo billingInfo;

Optional元素:通知持久化提供器相关对象是否必须存在。默认情况下为true,不必存在。

双向一对一:

你需要从关系的任何一端访问相关实体:

package cn.partner4java.bean.part1_3_1;

import javax.persistence.Entity;

import javax.persistence.Id;

import javax.persistence.OneToOne;

@Entity

public class BillingInfo {

    @Id

    private Long billingId;

    private String bankName;

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

    private User user;

}

 

package cn.partner4java.bean.part1_3_1;

import javax.persistence.Entity;

import javax.persistence.Id;

import javax.persistence.OneToOne;

@Entity

public class User {

    @Id

    private String userId;

    private String email;

    @OneToOne

    private BillingInfo billingInfo;

}

mappedBy=”billingInfo”指定,它通知容器关系的“拥有”端在User类的billingInfo实体变量中,也就是在表User里生产外键引用字段。

Optional参数被设置为false,标识BillingInfo对象不能在没有相关User对象时存在。想想,你如果在User的:

@OneToOne(optional=false)

private BillingInfo billingInfo;

也设置为不能为空,会产生什么后果,保存执行sql语句会产生什么后果?(这个问题留在后面EntityManager使用时解决)

3.2 @OneToMany @ManyToOne

package cn.partner4java.bean.part1_3_2;

import java.util.Set;

import javax.persistence.Entity;

import javax.persistence.Id;

import javax.persistence.OneToMany;

@Entity

public class Item {

    @Id

    private Long id;

    private String title;

    @OneToMany(mappedBy="item")

    private Set bids;

}

 

package cn.partner4java.bean.part1_3_2;

import javax.persistence.Entity;

import javax.persistence.Id;

import javax.persistence.ManyToOne;

@Entity

public class Bid {

    @Id

    private Long bidId;

    private Double amount;

    @ManyToOne

    private Item item;

}

在关系中的非维护端的实体的列上使用mappingBy,从而标记关系的维护端,指定为Biditem字段为维护端。并且规定必须多的一端为维护端。因为,让世界人名记住小泉的名字,总比让小泉记住世界人民的名字容易的多。

3.3 @ManyToMany

虽然多对多关系可以是单向的,但是由于这种很想特殊、相互独立的性质,所以他们经常是双向的。

package cn.partner4java.bean.part1_3_3;

import java.util.Set;

import javax.persistence.Entity;

import javax.persistence.Id;

import javax.persistence.ManyToMany;

@Entity

public class CateGory {

    @Id

    private Long categoryId;

    private String name;

    @ManyToMany

    private Set items;

}

 

package cn.partner4java.bean.part1_3_3;

import java.util.Set;

import javax.persistence.Entity;

import javax.persistence.Id;

import javax.persistence.ManyToMany;

@Entity

public class Item {

    @Id

    private Long itemId;

    private String title;

    @ManyToMany(mappedBy="items")

    private Set categories;

}

双向的多对多会单独生成一个表进行关系的维护。

 

总结:我们上面介绍了各种关系,但是没有详细告诉大家一些注解参数的配置,如改变多对多关系表的名称等等,相信这些还是比较简单的东西,大家可以从文档里面查找。并且下面的第二部分会有详细的介绍。

 

 

 

第二部分:关系对象映射

 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

 

。。。。。。

详细请下载 http://download.csdn.net/source/1995131

你可能感兴趣的:(jpa,string,import,数据库建模,class,数据库)