JPA基础(HelloWord)

JPA

Java Persistence API:用于对象持久化的 API

Java EE 5.0 平台标准的 ORM 规范,使得应用程序以统一的方式访问持久层。

JPA与Hibernate

JPA 是 hibernate 的一个抽象(就像JDBC和JDBC驱动的关系),不是ORM 框架。因为JPA 并未提供 ORM 实现,它只是制订了一些规范,提供了一些编程的 API 接口,但具体实现则由 ORM 厂商提供实现

Hibernate 是实现:Hibernate 除了作为 ORM 框架之外,它也是一种 JPA 实现

JPA的优势

标准化:  提供相同的 API,这保证了基于JPA 开发的企业应用能够经过少量的修改就能够在不同的 JPA 框架下运行。

简单易用,集成方便:  JPA 的主要目标之一就是提供更加简单的编程模型,在 JPA 框架下创建实体和创建 Java  类一样简单,只需要使用 javax.persistence.Entity 进行注释;JPA 的框架和接口也都非常简单,

可媲美JDBC的查询能力:  JPA的查询语言是面向对象的,JPA定义了独特的JPQL,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。

支持面向对象的高级特性: JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,最大限度的使用面向对象的模型

JPA 技术

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

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

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

JPA 注解

@Entity

@Entity 标注在实体类上,将映射到指定的数据库表。

@Table

@Table 标注与 @Entity 标注并列使用,@Table的name指定数据库表名。

@Table标注的catalog 和 schema 用于设置表所属的数据库目录或模式,通常为数据库名。

uniqueConstraints 选项用于设置约束条件。

@Table(name="JPA_CATEGORIES")

@Entity

public class Category {

}

@Id

@Id 标注用于声明一个实体类的属性映射为数据库的主键列。

@Id标注也可置于属性的getter方法之前。

@GeneratedValue(strategy=GenerationType.AUTO)

@Id

public Integer getId() {

return id;

}

@GeneratedValue

@GeneratedValue  用于标注主键的生成策略,通过 strategy 属性指定。

默认情况下,JPA 自动选择一个最适合底层数据库的主键生成策略:SqlServer 对应 identity,MySQL 对应 auto increment。

GenerationType

IDENTITY:采用数据库 ID自增长的方式来自增主键字段,Oracle 不支持这种方式;

AUTO: JPA自动选择合适的策略,是默认选项;

SEQUENCE:通过序列产生主键,通过 @SequenceGenerator 注解指定序列名,MySql 不支持这种方式

TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。

@Basic

@Basic 表示一个简单的属性到数据库表的字段的映射。没有任何标注的 getXxxx() 方法,默认即为@Basic。

fetch: 表示该属性的读取策略,有 EAGER 和 LAZY 两种,分别表示主支抓取和延迟加载,默认为 EAGER.

optional:表示该属性是否允许为null, 默认为true。

@Column

映射的数据库表的列。不指定时与实体类对应。可与 @Id 与@Basic标注一起使用。

属性:

name:数据库对应列名

columnDefinition:  表示该字段在数据库中的实际类型.

@Transient

表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性.

@Temporal

对应Date 类型的数据有 DATE, TIME, 和 TIMESTAMP 三种精度,在进行属性映射时可使用@Temporal注解来调整精度.

@TableGenerator

@TableGenerator(name="ID_GENERATOR",

table="jpa_id_generators",

pkColumnName="PK_NAME",

pkColumnValue="CUSTOMER_ID",

valueColumnName="PK_VALUE",

allocationSize=100)

@TableGenerator 表示只想一张单独保存主键id的表

 

name 属性表示该主键生成策略的名称,它被引用在@GeneratedValue中设置的generator 值中

table 属性表示表生成策略所持久化的表名

pkColumnName 属性的值表示在持久化表中,该主键生成策略所对应键值的名称valueColumnName 属性的值表示在持久化表中,该主键当前所生成的值,它的值将会随着每次创建累加

pkColumnValue 属性的值表示在持久化表中,该生成策略所对应的主键

allocationSize 表示每次主键值增加的大小, 默认值为 50

JPA API

Persistence

Persistence  类是用于获取 EntityManagerFactory 实例。

entityManagerFactory = Persistence.createEntityManagerFactory(arg1,arg2);

1 带有一个参数的方法以 JPA 配置文件 persistence.xml 中的持久化单元名为参数

2 带有两个参数的方法:前一个参数含义相同,后一个参数 Map类型,用于设置 JPA 的相关属性,这时将忽略其它地方设置的属性。Map 对象的属性名必须是 JPA 实现库提供商的名字空间约定的属性名。

EntityManagerFactory

createEntityManager():用于创建实体管理器对象实例。

createEntityManager(Map map):用于创建实体管理器对象实例的重载方法,Map 参数用于提供 EntityManager 的属性。

isOpen():检查 EntityManagerFactory 是否处于打开状态。实体管理器工厂创建后一直处于打开状态,除非调用close()方法将其关闭。

close():关闭 EntityManagerFactory 。 EntityManagerFactory 关闭后将释放所有资源,isOpen()方法测试将返回 false,其它方法将不能调用,否则将导致IllegalStateException异常。

EntityManager

EntityManager 是完成持久化操作的核心对象。实体作为普通 Java 对象,只有在调用 EntityManager 将其持久化后才会变成持久化对象。EntityManager 对象在一组实体类与底层数据源之间进行 O/R 映射的管理。它可以用来管理和更新 Entity Bean, 根椐主键查找 Entity Bean, 还可以通过JPQL语句查询实体。

实体的状态:

新建状态:   新创建的对象,尚未拥有持久性主键。

持久化状态:已经拥有持久性主键并和持久化建立了上下文环境

游离状态:拥有持久化主键,但是没有与持久化建立上下文环境

删除状态:  拥有持久化主键,已经和持久化建立上下文环境,但是从数据库中删除。

方法:

find:返回指定的 OID 对应的实体类对象,若不存在返回null

getReference:与find类似,不同之处在不会立即加载数据库中的信息,只有第一次真正使用此 Entity 的属性才加载,所以如果此 OID 在数据库不存在,getReference() 不会返回 null 值, 而是抛出EntityNotFoundException

persist :持久化对象,将新创建的 Entity 纳入到 EntityManager 的管理。

remove :删除实例.

merge :用于处理 Entity 的同步。即数据库的插入和更新操作

flush ():同步持久上下文环境,即将持久上下文环境的所有未保存实体的状态信息保存到数据库中。

setFlushMode (FlushModeType flushMode):设置持久上下文环境的Flush模式。

FlushModeType.AUTO 为自动更新数据库实体,

FlushModeType.COMMIT 为直到提交事务时才更新数据库记录。

getFlushMode ():获取持久上下文环境的Flush模式。

EntityTransaction

用来管理资源层实体管理器的事务操作。

关系映射

双向一对多及多对一映射

可以在 one 方指定 @OneToMany 注释并设置 mappedBy 属性,以指定它是这一关联中的被维护端,many 为维护端。

在 many 方指定 @ManyToOne 注释,并使用 @JoinColumn 指定外键名称

 

1-n

可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略

可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略.

注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 属性, 则 @OneToMany 端就不能再使用 @JoinColumn 属性了.

@OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.REMOVE},mappedBy="customer")

public Set<Order> getOrders() {

return orders;

}

n-1

映射单向 n-1 的关联关系

使用 @ManyToOne 来映射多对一的关联关系

使用 @JoinColumn 来映射外键.

可使用 @ManyToOne 的 fetch 属性来修改默认的关联属性的加载策略

@JoinColumn(name="CUSTOMER_ID")

@ManyToOne(fetch=FetchType.LAZY)

public Customer getCustomer() {

return customer;

}

双向一对一映射

在双向的一对一关联中,需要在关系被维护端(inverse side)中的 @OneToOne 注释中指定 mappedBy,以指定是这一关联中的被维护端。同时需要在关系维护端(owner side)建立外键列指向关系被维护端的主键列。

 

对于不维护关联关系, 没有外键的一方, 使用 @OneToOne 来进行映射, 建议设置 mappedBy

@OneToOne(mappedBy="mgr")

public Department getDept() {

return dept;

}

使用 @OneToOne 来映射 1-1 关联关系。

若需要在当前数据表中添加主键则需要使用 @JoinColumn 来进行映射. 注意, 1-1 关联关系, 所以需要添加 unique=true

@JoinColumn(name="MGR_ID", unique=true)

@OneToOne(fetch=FetchType.LAZY)

public Manager getMgr() {

return mgr;

}

双向多对多关联关系

在双向多对多关系中,必须指定一个关系维护端(owner side),可以通过 @ManyToMany 注释中指定 mappedBy 属性来标识其为关系维护端。

被维护端:

@ManyToMany(mappedBy="categories")

public Set<Item> getItems() {

return items;

}

维护端:

使用 @ManyToMany 注解来映射多对多关联关系

使用 @JoinTable 来映射中间表

1. name 指向中间表的名字

2. joinColumns 映射当前类所在的表在中间表中的外键

      name 指定外键列的列名

      referencedColumnName 指定外键列关联当前表的哪一列

3. inverseJoinColumns 映射关联的类所在中间表的外键

@JoinTable(name="ITEM_CATEGORY",

joinColumns={@JoinColumn(name="ITEM_ID", referencedColumnName="ID")},

inverseJoinColumns={@JoinColumn(name="CATEGORY_ID", referencedColumnName="ID")})

@ManyToMany

public Set<Category> getCategories() {

return categories;

}

缓存

一级缓存

 

JPA在同一个EntityManager下查询同一条记录只执行一次查询。

Customer customer = entityManager.find(Customer.class, 1);

Customer customer2 = entityManager.find(Customer.class, 1);

第二次从第一次查询过后缓存中拿取。

二级缓存

<shared-cache-mode> 节点配置

ALL:所有的实体类都被缓存

NONE:所有的实体类都不被缓存.

ENABLE_SELECTIVE:标识 @Cacheable(true) 注解的实体类将被缓存

DISABLE_SELECTIVE:缓存除标识 @Cacheable(false) 以外的所有实体类

UNSPECIFIED:默认值,JPA 产品默认值将被使用

例:

<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>

然后再实体类上标注@Cacheable(true)

JPQL

Java Persistence Query Language 的简称。

Query接口封装了执行数据库查询的相关方法。

String jpql = "FROM Customer c WHERE c.age > ?";

Query query = entityManager.createQuery(jpql);

query.setParameter(1, 1);

List<Customer> customers = query.getResultList();

使用缓存查询

query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);

 

获取单个结果

Query query = entityManager.createQuery(

"select max(o.id) from Orders o");

Object result = query.getSingleResult();

Long max = (Long)result;

JPQL函数

concat(String s1, String s2):字符串合并/连接函数。

substring(String s, int start, int length):取字串函数。

trim([leading|trailing|both,] [char c,] String s):从字符串中去掉首/尾指定的字符或空格。

lower(String s):将字符串转换成小写形式。

upper(String s):将字符串转换成大写形式。

length(String s):求字符串的长度。

locate(String s1, String s2[, int start]):从第一个字符串中查找第二个字符串(子串)出现的位置。若未找到则返回0。

算术函数主要有 abs、mod、sqrt、size 等。Size 用于求集合的元素个数。

日期函数主要为三个,即 current_date、current_time、current_timestamp.

 

 

使用JPA持久化对象的步骤

1 添加依赖jar包

hibernate-release-xxx.Final\lib\required\*.jar

hibernate-release-xxx.Final\lib\jpa\*.jar

Mysql-connector-xxx.jar

2 在SRC/META-INF下创建 persistence.xml, 在这个文件中配置持久化单元

需要指定跟哪个数据库进行交互;

需要指定 JPA 使用哪个持久化的框架以及配置该框架的基本属性

Persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="2.0"

xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

<persistence-unit name="jpa-1" transaction-type="RESOURCE_LOCAL">

<!--

配置使用什么 ORM 产品来作为 JPA 的实现

1. 实际上配置的是  javax.persistence.spi.PersistenceProvider 接口的实现类

2. 若 JPA 项目中只有一个 JPA 的实现产品, 则也可以不配置该节点.

-->

<provider>org.hibernate.ejb.HibernatePersistence</provider>



<!-- 添加持久化类 -->

<class>com.jpa.helloworld.Customer</class>

<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>



<properties>

<!-- 连接数据库的基本信息 -->

<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>

<property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa"/>

<property name="javax.persistence.jdbc.user" value="root"/>

<property name="javax.persistence.jdbc.password" value="123456"/>



<!-- 配置 JPA 实现产品的基本属性. 配置 hibernate 的基本属性 -->

<property name="hibernate.format_sql" value="true"/>

<property name="hibernate.show_sql" value="true"/>

<property name="hibernate.hbm2ddl.auto" value="update"/>



<!-- 二级缓存相关 -->

<property name="hibernate.cache.use_second_level_cache" value="true"/>

<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>

<property name="hibernate.cache.use_query_cache" value="true"/>

</properties>

</persistence-unit>

</persistence>

3 创建实体类

Customer:

@Cacheable(true)

@Table(name="JPA_CUTOMERS")

@Entity

public class Customer {



private Integer id;

private String lastName;



private String email;

private int age;



private Date createdTime;

private Date birth;



public Customer() {}



public Customer(String lastName, int age) {

this.lastName = lastName;

this.age = age;

}







@GeneratedValue(strategy=GenerationType.AUTO)

@Id

public Integer getId() {

return id;

}



public void setId(Integer id) {

this.id = id;

}



@Column(name="LAST_NAME",length=50,nullable=false)

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;

}



public int getAge() {

return age;

}



public void setAge(int age) {

this.age = age;

}



@Temporal(TemporalType.TIMESTAMP)

public Date getCreatedTime() {

return createdTime;

}



public void setCreatedTime(Date createdTime) {

this.createdTime = createdTime;

}



@Temporal(TemporalType.DATE)

public Date getBirth() {

return birth;

}



public void setBirth(Date birth) {

this.birth = birth;

}

@Transient

public String getInfo(){

return "lastName: " + lastName + ", email: " + email;

}

}

4 使用 JPA API 完成数据增加、删除、修改和查询操作

@Test

public void testFind() {

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("jpa-1");

EntityManager entityManager = entityManagerFactory.createEntityManager();

Customer customer = entityManager.find(Customer.class, 1);

}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值