一. JPA简介

JPA是Java Persistence API的简称,中文名Java持久层Api,是JDK1.5注解或者Xml描述对象-关系表的映射关系,并将运行期的实体类对象持久化Dao数据库中!注意的是,如果两种映射发生冲突的时候XML优先于注解的方式!

1. 什么是JPA?

JPA由EJB 3.0软件专家组开发,作为JSR-220实现的一部分。但它又不限于EJB 3.0,你可以在Web应用、甚至桌面应用中使用。JPA的宗旨是为POJO提供持久化标准规范,由此可见,经过这几年的实践探索,能够脱离容器独立运行,方便开发和测试的理念已经深入人心了。Hibernate3.2+、TopLink 10.1.3以及OpenJPA都提供了JPA的实现。

JPA的总体思想和现有Hibernate、TopLink、JDO等ORM框架大体一致。总的来说,JPA包括以下3方面的技术:

ORM映射元数据

JPA支持XML和JDK5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中;

API

用来操作实体对象,执行CRUD操作,框架在后台替代我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。

查询语言

这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。

2. JPA和Hibernate的关系!

JPA 的目标之一是制定一个可以由很多供应商实现的API,并且开发人员可以编码来实现该API,而不是使用私有供应商特有的API。因此开发人员只需使用供应商特有的API来获得JPA规范没有解决但应用程序中需要的功能。尽可能地使用JPA API,但是当需要供应商公开但是规范中没有提供的功能时,则使用供应商特有的API。

JPA是需要Provider来实现其功能的,Hibernate就是JPA Provider中很强的一个,应该说无人能出其右。从功能上来说,JPA就是Hibernate功能的一个子集。Hibernate 从3.2开始,就开始兼容JPA。Hibernate3.2获得了Sun TCK的JPA(Java Persistence API) 兼容认证。

只要熟悉Hibernate或者其他ORM框架,在使用JPA时会发现其实非常容易上手。例如实体对象的状态,在Hibernate有自由、持久、游离三种,JPA里有new,managed,detached,removed,明眼人一看就知道,这些状态都是一一对应的。再如flush方法,都是对应的,而其他的再如说Query query = manager.createQuery(sql),它在Hibernate里写法上是session,而在JPA中变成了manager,所以从Hibernate到JPA的代价应该是非常小的

同样,JDO,也开始兼容JPA。在ORM的领域中,看来JPA已经是王道,规范就是规范。在各大厂商的支持下,JPA的使用开始变得广泛。

二. JPA注解开发步骤

1. 为实体类添加注解

使用Hibernate的方法操作数据,我们利用xml配置文件将持久化类映射到数据库表,通过面向对象的思想,操作对象间接的操作数据库,但是xml配置写起来比较繁琐,那么我们可以使用Hibernate配置JPA注解的方式进行开发,这样简化开发步骤!

 @Entity
@Table(name="t_customer3")
public class Customer{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private Long id; @Column(name="name")
private String name; @Column(name="gender")
private Character gender; @Column(name="age")
private Integer age; @Column(name="level")
private String level;
}
注解名称 注解含义
@Entity 表明是一个JPA实体,可以使用JPA注解
@Table table表明实体类对应一个表,name属性对应表名
@Id 指定改变量为主键
@GeneratedValue 主键生成策略
@Column Column将变量对应数据库列!name指定对应列名

补充: @Column指定实体类变量对应数据库列, name属性指定对应列名,除此之外,在介绍下@Column的其他属性

属性名称 属性介绍
nullable boolean类型!此字段是否可以为null
length 指定列长度
precision 指定数字类型位数
scale 指定小数点位数

补充其他属性:

临时字段

@Transient 注解,用于给实体类添加临时属性(临时属性不需要反映到数据库中)

 @Transient // 临时字段,不反映到数据库中
private Boolean married;
public Boolean getMarried() {
return married;
}
public void setMarried(Boolean married) {
this.married = married;
}

默认值字段

默认值字段!创建列时添加defult修饰

  @ColumnDefault("默认值!默认值都是字符串类型");
private Integer age;

2. 修改Hibernate的核心配置文件

添加JPA注解的实体类,需要将类全路径配置到核心配置文件上

 <mapping class="类的全路径"></mapping>

3. 测试

 public class AnnotationTest {
/**
* 使用注解
*/
@Test
public void testAnnotation(){
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction(); Customer cust = new Customer();
cust.setName("王五2222");
session.save(cust); tx.commit();
}
}

二. JPA的主键策略

1. JPA的主键策略

JPA 主键策略,没有 Hibernate 主键策略丰富,例如:

     @Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private Long id;

其他的策略:

  • IDENTITY: 利用数据库的自增长的能力。适合 mysql

  • SEQUENCE:利用数据库的序列机制,适合 Oracle

  • TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。不同的JPA实现商生成的表名是不同的,如 OpenJPA生成openjpa_sequence_table表,Hibernate生成一个hibernate_sequences表,而TopLink则生成sequence表。这些表都具有一个序列名和对应值两个字段,如SEQ_NAME和SEQ_COUNT

  • AUTO:自动选择一个最适合底层数据库的主键生成策略。这个是默认选项,即如果只写@GeneratedValue,等价于@GeneratedValue(strategy=GenerationType.AUTO)。

2. hibernate的主键策略

如果使用Hibernate对JPA的实现,可以使用Hibernate对主键生成策略的扩展,通过Hibernate的@GenericGenerator实现。

注意:id的数据类型改成String

 @Id
//声明一个策略通用生成器,name为"system-uuid",策略strategy为"uuid"。
@GenericGenerator(name="system-uuid", strategy="uuid")
@Column(name="id")
private String id;

测试:

 /**
* UUID主键策略
*/
@Test
public void testUUID(){
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction(); Customer cust = new Customer();
cust.setName("王五2222");
cust.setId(UUID.randomUUID().toString());
session.save(cust); tx.commit();
}

也可以按照如下配置,在注解中指定要使用的策略生成器,这样测试用例中就不用人工生成uuid了。

 @Id
//声明一个策略通用生成器,name为"system-uuid",策略strategy为"uuid"。
@GenericGenerator(name="system-uuid", strategy="uuid")
//用generator属性指定要使用的策略生成器。
@GeneratedValue(generator="system-uuid")
@Column(name="id")
private String id;

三. 关联关系

1. 一对多

1.1 创建订单实体

 /**
* 订单(多方)
*/
@Entity
@Table(name="t_order4")
public class Order { @Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private Long id; @Column(name="orderno")
private String orderno; //关联客户
@ManyToOne
@JoinColumn(name="cust_id")
private Customer customer;
}

注意: @JoinColumn一般放在对应表中有外键的那个类中

mappedBy不能同时与@JoinColumn或@JoinTable出现在同一方配置

1.2 修改客户实体

添加关联订单,这里使用了级联配置

  //关联订单
@OneToMany(mappedBy="customer", cascade={CascadeType.ALL})
private Set<Order> orders = new HashSet<Order>();

CascadeType.PRESIST 级联持久化(保存)操作(持久保存拥有方实体时,也会持久保存该实体的所有相关数据。)

CascadeType.REMOVE 级联删除操作(删除一个实体时,也会删除该实体的所有相关数据。)

CascadeType.MERGE 级联更新(合并)操作(将分离的实体重新合并到活动的持久性上下文时,也会合并该实体的所有相关数据。)

CascadeType.REFRESH 级联刷新操作 (只会查询获取操作)

CascadeType.ALL 包含以上全部级联操作

注意:以上配置需要执行相应的级联操作的特定方法,扩展阅读:http://sefcertyu.iteye.com/blog/475237

1.3 修改Hibernate核心配置文件

hibernate.hbm.xml中添加Order的映射

<mapping class="com.qfedu.hibernate.pojo.Order" />

1.4 测试

     /**
* 测试一对多注解
*/
@Test
public void testOneToMany(){
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction(); Customer cust = new Customer();
cust.setName("王五3");
session.save(cust); Order o1 = new Order();
o1.setOrderno("201709003"); cust.getOrders().add(o1); session.save(cust);
//session.save(o1); tx.commit();
}

2. 多对多

用户和角色是多对多关系!

2.1 创建User实体

 /**
* 用户(多方)
*/
@Entity
@Table(name="t_user1")
public class User{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private Integer id; @Column(name="user_name")
private String name; //关联角色
@ManyToMany(cascade={CascadeType.ALL})
//@JoinTable: 用于映射中间表
//joinColumns: 当前方在中间表的外键字段名称
//inverseJoinColumns:对方在中间表的外键字段名称
@JoinTable(
name="t_user_role1",
joinColumns=@JoinColumn(name="user_id"),
inverseJoinColumns=@JoinColumn(name="role_id"))
private Set<Role> roles = new HashSet<Role>();
}

2.2 创建Role实体

 /**
* 角色(多方)
*/
@Entity
@Table(name="t_role1")
public class Role{ @Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private Integer id;
@Column(name="role_name")
private String name; //关联用户
@ManyToMany(mappedBy="roles")
private Set<User> users = new HashSet<User>();
}

2.3 配置映射

   <mapping class="pojo.User" />
<mapping class="pojo.Role" />

2.4 测试

 /**
* 测试多对多注解
*/
@Test
public void testManyToMany(){
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction(); User u1 = new User();
u1.setName("Helen"); Role r1 = new Role();
r1.setName("VIP"); u1.getRoles().add(r1); session.save(u1);
//session.save(r1); tx.commit();
}

3. 一对一

3.1 创建Person实体

 @Entity
@Table(name="t_person1")
public class Person{ @Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private Integer id; @Column(name="name")
private String name; //关联身份证
@OneToOne(mappedBy="person", cascade={CascadeType.ALL})
private Card card;
}

3.2 创建Card实体

 @Entity
@Table(name="t_card1")
public class Card{ @Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private Integer id; @Column(name="card_no")
private String cardno; //关联公民
@OneToOne
@JoinColumn(name="person_id")
private Person person;
}

3.3 Hibernate核心配置文件

    <mapping class="pojo.Person" />
<mapping class="pojo.Card" />

3.4 测试

  @Test
public void testOneToOne(){ Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction(); Person p = new Person();
p.setName("老王"); Card c = new Card();
c.setCardno("44333222"); p.setCard(c); session.save(p);
//session.save(c);
tx.commit();
}

总结

一对一为例:针对 mappedBy 、 @JoinColumn 、 cascade 的总结

外键由谁来维护

1、当关联关系的双方都不配置mappedBy 属性时,那么双方会互相生成外键,并且执行三条sql

两条插入sql,一条额外的维护外键的sql

2、如果有一方配置了mappedBy 属性,那么对方会生成外键

3、mappedBy 和 @JoinColumn 不能配置在同一方中

4、如果配置在同一方中,以mappedBy为准,@JoinColumn失效

5、只能有一方配置 mappedBy

级联操作

1、在A设置了级联操作,A就应该被session操作

2、在A方设置了级联操作,B就应该被设置为A的属性

3、如果A中有外键,那么B应该被设置为A的属性,外键才能被填充

Hibernate结合JPA05的更多相关文章

  1. hibernate多对多关联映射

    关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...

  2. 解决 Springboot Unable to build Hibernate SessionFactory @Column命名不起作用

    问题: Springboot启动报错: Caused by: org.springframework.beans.factory.BeanCreationException: Error creati ...

  3. hibernate多对一双向关联

    关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...

  4. Hibernate中事务的隔离级别设置

    Hibernate中事务的隔离级别,如下方法分别为1/2/4/8. 在Hibernate配置文件中设置,设置代码如下

  5. Hibernate中事务声明

    Hibernate中JDBC事务声明,在Hibernate配置文件中加入如下代码,不做声明Hibernate默认就是JDBC事务. 一个JDBC 不能跨越多个数据库. Hibernate中JTA事务声 ...

  6. spring applicationContext.xml和hibernate.cfg.xml设置

    applicationContext.xml配置 <?xml version="1.0" encoding="UTF-8"?> <beans ...

  7. [原创]关于Hibernate中的级联操作以及懒加载

    Hibernate: 级联操作 一.简单的介绍 cascade和inverse (Employee – Department) Casade用来说明当对主对象进行某种操作时是否对其关联的从对象也作类似 ...

  8. hibernate的基本xml文件配置

    需要导入基本的包hibernate下的bin下的required和同bin下optional里的c3p0包下的所有jar文件,当然要导入mysql的驱动包了.下面需要注意的是hibernate的版本就 ...

  9. Maven搭建SpringMVC+Hibernate项目详解 【转】

    前言 今天复习一下SpringMVC+Hibernate的搭建,本来想着将Spring-Security权限控制框架也映入其中的,但是发现内容太多了,Spring-Security的就留在下一篇吧,这 ...

随机推荐

  1. 用commander.js构建自己的脚手架工具

    随着前端技术的发展,工程化逐渐成为了一种趋势.但在实际开发时,搭建项目是一件很繁琐的事情,尤其是在对一个框架的用法还不熟悉的时候.于是很多框架都自带一套脚手架工具,在初始化前端项目的时候就可以不用自己 ...

  2. IP判断

    题目描述 在基于Internet的程序中,我们常常需要判断一个IP字符串的合法性. 合法的IP是这样的形式: A.B.C.D 其中A.B.C.D均为位于[0, 255]中的整数.为了简单起见,我们规定 ...

  3. Python学习第十四篇——类初步使用及面向对象思想

    class Restaurant(): def __init__(self,restaurant_name,cuisine_type): self.name = restaurant_name sel ...

  4. git出现: not a git repository

    使用用git add . 出现这样错误: fatal: not a git repository (or any of the parent directories): .git 意思是说:.git没 ...

  5. Vue父子传值

    昨天创建完项目以后,今日首先使用项目来做一个简单的导航栏体会一下Vue的使用 1.项目的结构: 2.首先在Vheader.Vue中编辑代码: <template> <header c ...

  6. PHP中多个文件包含的问题 (一)

    使用require或者include来包含文件时,包含的文件的内容相对性,这个很容易搞混,所以记录一下. 这个相对性包括 __DIR__,__FILE__,$_SERVER['PHP_SELF'],$ ...

  7. 【kindle笔记】之 《解忧杂货店》-2018-3-13

    [kindle笔记]读书记录-总 <解忧杂货店>-2018-3-13 东野的大ID加上此书的大ID,今天终于在回来天津的火车上一口气读完了. 此前在微信读书上看过这本书,只看了前一部分,感 ...

  8. java不同的包下相同的类名的问题与解决办法

    Java中的类以包进行分类组织,当程序中需要用到某个包下的类时,可以以该类的全限定名进行引用.这样,不同的包中的类就可以同名,不会产生混淆. 但是这样就可能导致引用的时候会产生一些问题. 第一个问题, ...

  9. day 7-18 mysql case when语句

    概述: sql语句中的case语句与高级语言中的switch语句,是标准sql的语法,适用于一个条件判断有多种值的情况下分别执行不同的操作. 首先,让我们看一下CASE的语法.在一般的SELECT中, ...

  10. j收集ava面试题

    史上最全Java面试题(带全部答案) https://blog.csdn.net/linzhiqiang0316/article/details/80473906