JPA知识详解

234 阅读21分钟

@TOC

JPA简介

JPA定义:

  • Java Persistence API:用于对象持久化的 API
  • Java EE 5.0 平台标准的 ORM 规范,使得应用程序以统一的方式访问持久层 在这里插入图片描述
  • JPA 是 hibernate 的一个抽象(就像JDBC和JDBC驱动的关系)
  • JPA 是规范:JPA 本质上就是一种 ORM 规范,不是ORM 框架 —— 因为 JPA 并未提供 ORM实现,它只是制订了一些规范,提供了一些编程的 API 接口,但具体实现则由 ORM 厂商提供实现
  • Hibernate 是实现:Hibernate 除了作为 ORM 框架之外,它也是一种 JPA 实现从功能上来说,JPA 是Hibernate 功能的一个子集
  • JPA 的目标之一是制定一个可以由很多供应商实现的 API,目前Hibernate 3.2+、TopLink 10.1+ 以及OpenJPA 都提供了 JPA 的实现。 ①Hibernate:JPA 的始作俑者就是 Hibernate 的作者,Hibernate 从 3.2 开始兼容 JPA ②OpenJPA:OpenJPA 是 Apache 组织提供的开源项目 ③TopLink:TopLink 以前需要收费,如今开源了

JPA的优势:

  • 标准化: 提供相同的 API,这保证了基于JPA 开发的企业应用能够经过少量的修改就能够在不同的 JPA 框架下运行。
  • 简单易用,集成方便: JPA 的主要目标之一就是提供更加简单的编程模型,在 JPA 框架下创建实体和创建 Java 类一样简单,只需要使用 javax.persistence.Entity 进行注释;JPA 的框架和接口也都非常简单。
  • 可媲美JDBC的查询能力: JPA的查询语言是面向对象的,JPA定义了独特的JPQL,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
  • 支持面向对象的高级特性: JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,最大限度的使用面向对象的模型。

JPA 包括 3方面的技术:

  • ORM 映射元数据:JPA 支持 XML 和 JDK 5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中。
  • JPA 的 API:用来操作实体对象,执行CRUD操作,框架在后台完成所有的事情,开发者从繁琐的 JDBC和 SQL代码中解脱出来。
  • 查询语言(JPQL):这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序和具体的 SQL紧密耦合。

JPA使用

使用JPA持久化对象的步骤:

  • 创建 persistence.xml, 在这个文件中配置持久化单元 ①需要指定跟哪个数据库进行交互; ②需要指定 JPA 使用哪个持久化的框架以及配置该框架的基本属性
  • 创建实体类, 使用 annotation 来描述实体类跟数据库表之间的映射关系
  • 使用 JPA API 完成数据增加、删除、修改和查询操作 ①创建 EntityManagerFactory (对应 Hibernate 中的 SessionFactory); ②创建 EntityManager (对应 Hibernate 中的Session);
  • 引入的依赖:hibernate-jpa-2.1-api.jar其中javax.persistence这个包的作用是持久化的作用,具体的说就是在实体类中进行元数据标签的作用,ORM框架可以通过这个元数据标签,使得实体类与数据库中的表建立映射关系。

persistence.xml使用:

  • JPA 规范要求在类路径的 META-INF 目录下放置persistence.xml,文件的名称是固定的
  • hibernate.hbm2ddl.auto的几个常用属性值: ① 实际项目中 update 用的多一点,因为它只更新对象关系的变化,不会清空数据或者重建表。 <1>none:默认值,什么都不做,每次启动项目,不会对数据库进行任何验证和操作 <2>create:每次运行项目,没有表会新建表,如果表内有数据会被清空 <3>create-drop:每次程序结束的时候会清空表 <4>update:每次运行程序,没有表会新建表,但是表内有数据不会被清空,只会更新表结构。 <5>validate:运行程序会校验数据与数据库的字段类型是否相同,不同会报错 ②JPA默认情况下和MyBatis一样开启一级缓存。JPA是针对与entityManager,Mybatis是针对于sqlSession。JPA的二级缓存是跨entityManager的,JPA的二级缓存需要显式配置。
<persistence>
<!-- 
	一、name 属性用于定义持久化单元的名字, 必选。
	二、transaction-type:指定 JPA  的事务处理策略。RESOURCE_LOCAL:默认值,数据库级别的事务,只能针对一种数据库,不支持分布式事务。
	如果需要支持分布式事务,使用JTA:transaction-type="JTA“
-->
	<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.atguigu.jpa.helloworld.Customer</class>
		<class>com.atguigu.jpa.helloworld.Order</class>
	
		<class>com.atguigu.jpa.helloworld.Department</class>
		<class>com.atguigu.jpa.helloworld.Manager</class>
	
		<class>com.atguigu.jpa.helloworld.Item</class>
		<class>com.atguigu.jpa.helloworld.Category</class>
		
		<!-- 
			配置二级缓存的策略 
			ALL:所有的实体类都被缓存
			NONE:所有的实体类都不被缓存. 
			ENABLE_SELECTIVE:标识 @Cacheable(true) 注解的实体类将被缓存
			DISABLE_SELECTIVE:缓存除标识 @Cacheable(false) 以外的所有实体类
			UNSPECIFIED:默认值,JPA 产品默认值将被使用
		-->
		<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="1230"/>
			
			<!-- 配置 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>

JPA基本注解

JPA 基本注解:

  • @Entity@Entity 标注用于实体类声明语句之前,指出该Java 类为实体类,将映射到指定的数据库表。如声明一个实体类 Customer,它将映射到数据库中的 customer 表上。
  • @Table当实体类与其映射的数据库表名不同名时需要使用 @Table 标注说明,该标注与 @Entity 标注并列使用,置于实体类声明语句之前,可写于单独语句行,也可与声明语句同行。 ②@Table 标注的常用选项是 name,用于指明数据库的表名 ③@Table标注还有一个两个选项 catalog 和 schema 用于设置表所属的数据库目录或模式,通常为数据库名。uniqueConstraints 选项用于设置约束条件,通常不须设置。
  • @Id@Id 标注用于声明一个实体类的属性映射为数据库的主键列。该属性通常置于属性声明语句之前,可与声明语句同行,也可写在单独行上。 ②@Id标注也可置于属性的getter方法之前。
  • @GeneratedValue@GeneratedValue 用于标注主键的生成策略,通过 strategy 属性指定。默认情况下,JPA 自动选择一个最适合底层数据库的主键生成策略:SqlServer 对应 identity,MySQL 对应 auto increment。 ②在 javax.persistence.GenerationType 中定义了以下几种可供选择的策略: 1、IDENTITY:采用数据库 ID自增长的方式来自增主键字段,Oracle 不支持这种方式; 2、AUTO: JPA自动选择合适的策略,是默认选项; 3、SEQUENCE:通过序列产生主键,通过 @SequenceGenerator 注解指定序列名,MySql 不支持这种方式 4、TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。
  • @Basic ① @Basic 表示一个简单的属性到数据库表的字段的映射,对于没有任何标注的 getXxxx() 方法,默认即为@Basic ②fetch: 表示该属性的读取策略,有 EAGER 和 LAZY 两种,分别表示主支抓取和延迟加载,默认为 EAGER. ③optional:表示该属性是否允许为null, 默认为true
  • @Column当实体的属性与其映射的数据库表的列不同名时需要使用@Column 标注说明,该属性通常置于实体的属性声明语句之前,还可与 @Id 标注一起使用。 ②@Column 标注的常用属性是 name,用于设置映射数据库表的列名。此外,该标注还包含其它多个属性,如:unique 、nullable、length 等。 ③@Column 标注的 columnDefinition 属性: 表示该字段在数据库中的实际类型.通常 ORM 框架可以根据属性类型自动判断数据库中字段的类型,但是对于Date类型仍无法确定数据库中字段类型究竟是DATE,TIME还是TIMESTAMP.此外,String的默认映射类型为VARCHAR, 如果要将 String 类型映射到特定数据库的 BLOB 或TEXT 字段类型. @Column标注也可置于属性的getter方法之前
  • @Transient(短暂的)表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性. ②如果一个属性并非数据库表的字段映射,就务必将其标示为@Transient,否则,ORM框架默认其注解为@Basic
  • @Temporal(与时间有关的)在核心的 Java API 中并没有定义 Date 类型的精度(temporal precision). 而在数据库中,表示 Date 类型的数据有 DATE, TIME, 和 TIMESTAMP 三种精度(即单纯的日期,时间,或者两者 兼备). 在进行属性映射时可使用@Temporal注解来调整精度.
  • @MappedSuperclass ①在Jpa里, 当我们在定义多个实体类时, 可能会遇到这几个实体类都有几个共同的属性, 这时就会出现很多重复代码. ②这时我们可以选择编写一个父类,将这些共同属性放到这个父类中, 并且在父类上加上@MappedSuperclass注解. ③注意:标注为@MappedSuperclass的类将不是一个完整的实体类,他将不会映射到数据库表,但是他的属性都将映射到其子类的数据库字段中。 ④标注为@MappedSuperclass的类不能再标注@Entity或@Table注解,也无需实现序列化接口.

JPA API

JPA相关接口/类:Persistence:

  • Persistence 类是用于获取 EntityManagerFactory 实例。该类包含一个名为createEntityManagerFactory 的 静态方法
  • createEntityManagerFactory 方法有如下两个重载版本。 ①带有一个参数的方法以 JPA 配置文件 persistence.xml 中的持久化单元名为参数 ②带有两个参数的方法:前一个参数含义相同,后一个参数 Map类型,用于设置 JPA 的相关属性,这时将忽略其它地方设置的属性。Map 对象的属性名必须是 JPA 实现库提供商的名字空间约定的属性名。

EntityManagerFactory接口主要用来创建 EntityManager 实例。该接口约定了如下4个方法:

  • createEntityManager():用于创建实体管理器对象实例。
  • createEntityManager(Map map):用于创建实体管理器对象实例的重载方法,Map 参数用于提供 EntityManager 的属性。
  • isOpen():检查 EntityManagerFactory是否处于打开状态。实体管理器工厂创建后一直处于打开状态,除非调用close()方法将其关闭。
  • close():关闭 EntityManagerFactory 。 EntityManagerFactory关闭后将释放所有资源,isOpen()方法测试将返回false,其它方法将不能调用,否则将导致IllegalStateException异常。

EntityManager:

  • 在 JPA 规范中, EntityManager 是完成持久化操作的核心对象。实体作为普通 Java 对象,只有在调用EntityManager 将其持久化后才会变成持久化对象。EntityManager 对象在一组实体类与底层数据源之间进行 O/R映射的管理。它可以用来管理和更新 Entity Bean, 根椐主键查找 Entity Bean, 还可以通过JPQL语句查询实体。
  • 实体的状态: ①新建状态: 新创建的对象,尚未拥有持久性主键。 ②持久化状态:已经拥有持久性主键并和持久化建立了上下文环境(一级缓存) ③游离状态:拥有持久化主键,但是没有与持久化建立上下文环境(一级缓存) ④删除状态: 拥有持久化主键,已经和持久化建立上下文环境(一级缓存),但是从数据库中删除。 在这里插入图片描述

EntityManager方法:

  • find (Class<T> entityClass,Object primaryKey): 返回指定的 OID 对应的实体类对象,如果这个实体存在于当前的持久化环境,则返回一个被缓存的对象;否则会创建一个新的 Entity, 并加载数据库中相关信息;若 OID 不存在于数据库中,则返回一个 null。第一个参数为被查询的实体类类型,第二个参数为待查找实体的主键值。
  • getReference (Class<T> entityClass,Object primaryKey): 与find()方法类似,不同的是:如果缓存中不存在指定的 Entity, EntityManager 会创建一个 Entity 类的代理,但是不会立即加载数据库中的信息,只有第一次真正使用此 Entity 的属性才加载,所以如果此 OID 在数据库不存在,getReference() 不会返回 null 值, 而是抛出EntityNotFoundException
  • persist (Object entity): 用于将新创建的 Entity 纳入到 EntityManager 的管理。该方法执行后,传入 persist() 方法的 Entity 对象转换成持久化状态。 ①如果传入 persist() 方法的 Entity 对象已经处于持久化状态,则 persist() 方法什么都不做。 ②如果对删除状态的 Entity 进行 persist() 操作,会转换为持久化状态。 ③如果对游离状态的实体执行 persist() 操作,可能会在 persist() 方法抛出 EntityExistException(也有可能是在flush或事务提交后抛出)。
  • remove (Object entity): 删除实例。如果实例是被管理的,即与数据库实体记录关联,则同时会删除关联的数据库记录。
  • merge (T entity): merge() 用于处理 Entity 的同步。即数据库的插入和更新操作
  • flush (): 同步持久上下文环境,即将持久上下文环境的所有未保存实体的状态信息保存到数据库中。
  • setFlushMode (FlushModeType flushMode): 设置持久上下文环境的Flush模式。参数可以取2个枚举 ①FlushModeType.AUTO 为自动更新数据库实体。 ②FlushModeType.COMMIT 为直到提交事务时才更新数据库记录。
  • getFlushMode (): 获取持久上下文环境的Flush模式。返回FlushModeType类的枚举值。
  • refresh (Object entity): 用数据库实体记录的值更新实体对象的状态,即更新实例的属性值。
  • clear (): 清除持久上下文环境,断开所有关联的实体。如果这时还有未提交的更新则会被撤消。
  • contains (Object entity): 判断一个实例是否属于当前持久上下文环境管理的实体。
  • isOpen (): 判断当前的实体管理器是否是打开状态。
  • getTransaction (): 返回资源层的事务对象。EntityTransaction实例可以用于开始和提交多个事务。
  • close (): 关闭实体管理器。之后若调用实体管理器实例的方法或其派生的查询对象的方法都将抛出 IllegalstateException 异常,除了getTransaction 和 isOpen方法(返回 false)。不过,当与实体管理器关联的事务处于活动状态时,调用 close 方法后持久上下文将仍处于被管理状态,直到事务完成。
  • createQuery (String qlString): 创建一个查询对象。
  • createNamedQuery (String name): 根据命名的查询语句块创建查询对象。参数为命名的查询语句。
  • createNativeQuery (String sqlString): 使用标准 SQL语句创建查询对象。参数为标准SQL语句字符串。
  • createNativeQuery (String sqls, String resultSetMapping): 使用标准SQL语句创建查询对象,并指定返回结果集 Map的 名称。

EntityTransaction方法:

  • begin (): 用于启动一个事务,此后的多个数据库操作将作为整体被提交或撤消。若这时事务已启动则会抛出 IllegalStateException 异常。
  • commit (): 用于提交当前事务。即将事务启动以后的所有数据库更新操作持久化至数据库中。
  • rollback (): 撤消(回滚)当前事务。即撤消事务启动后的所有数据库更新操作,从而不对数据库产生影响。
  • setRollbackOnly (): 使当前事务只能被撤消。
  • getRollbackOnly (): 查看当前事务是否设置了只能撤消标志。
  • isActive (): 查看当前事务是否是活动的。如果返回true则不能调用begin方法,否则将抛出 IllegalStateException 异常;如果返回 false 则不能调用 commit、rollback、setRollbackOnly 及 getRollbackOnly 方法,否则将抛出 IllegalStateException 异常。

映射关联关系

映射关联关系简介:

  • ManyToOne(多对一): 单向:不产生中间表,但可以用@Joincolumn(name=" ")来指定生成外键的名字,外键在多的一方表中产生!
  • OneToMany(一对多): 单向:会产生中间表,此时可以用@onetoMany @Joincolumn(name=" ")避免产生中间表,并且指定了外键的名字(别看 @joincolumn在一中写着,但它存在在多的那个表中)
  • OneToMany ,ManyToOne 双向: (两个注解一起用的):如果不在 @OneToMany 中加mappedy属性就会产生中间表,此时通常在 @ManyToOne 的注 解下再添上注解 @Joincolumn(name=" ") 来指定外键的名字(说明:多的一方为关系维护端,关系维护端负责外键记录的更新,关系被维护端没有权利更新 外键记录)! ( @OneToMany(mappedBy="一对多中,多中一的属性") 出现mapby为被维护端|||默认为延迟加载)
  • 双向多对多关联关系: 在双向多对多关系中,我们必须指定一个关系维护端(owner side),可以通过 @ManyToMany 注释中指定 mappedBy 属性来标识其为关系维护端。
  • 双向一对一映射: 基于外键的 1-1 关联关系:在双向的一对一关联中,需要在关系被维护端(inverse side)中的 @OneToOne 注释中指定 mappedBy,以指定是这一关联中的被维护端。同时需要在关系维护端(owner side)建立外键列指向关系被维护端的主键列。

使用二级缓存

二级缓存:

  • <shared-cache-mode> 节点:若 JPA实现支持二级缓存,该节点可以配置在当前的持久化单元中是否启用二级缓存,可配置如下值: ①ALL:所有的实体类都被缓存 ②NONE:所有的实体类都不被缓存. ③ENABLE_SELECTIVE:标识 @Cacheable(true) 注解的实体类将被缓存 ④DISABLE_SELECTIVE:缓存除标识 @Cacheable(false) 以外的所有实体类 ⑤UNSPECIFIED:默认值,JPA 产品默认值将被使用

JPQL

JPQL定义:

  • JPQL语言,即 Java Persistence Query Language 的简称。JPQL 是一种和 SQL非常类似的中间性和对象化查询语言,它最终会被编译成针对不同底层数据库的 SQL 查询,从而屏蔽不同数据库的差异。
  • JPQL语言的语句可以是 select 语句、update 语句或delete语句,它们都通过 Query 接口封装执行

javax.persistence.Query:

  • Query接口封装了执行数据库查询的相关方法。调用 EntityManager 的 createQuery、createNamedQuery 及 createNativeQuery 方法可以获得查询对象,进而可调用 Query 接口的相关方法来执行查询操作。
  • Query接口的主要方法: ①int executeUpdate() :用于执行update或delete语句。 ②List getResultList() :用于执行select语句并返回结果集实体列表。 ③Object getSingleResult() :用于执行只返回单个结果实体的select语句。 ④Query setFirstResult(int startPosition) :用于设置从哪个实体记录开始返回查询结果。 ⑤Query setMaxResults(int maxResult) :用于设置返回结果实体的最大数。与setFirstResult结合使用可实现分页查询。 ⑥Query setFlushMode(FlushModeType flushMode) :设置查询对象的Flush模式。参数可以取2个枚举值:FlushModeType.AUTO 为自动更新数据库记录,FlushMode Type.COMMIT 为直到提交事务时才更新数据库记录。 ⑦setHint(String hintName, Object value) :设置与查询对象相关的特定供应商参数或提示信息。参数名及其取值需要参考特定 JPA 实现库提供商的文档。如果第二个参数无效将抛出IllegalArgumentException异常。 ⑧setParameter(int position, Object value) :为查询语句的指定位置参数赋值。Position 指定参数序号,value 为赋给参数的值。 ⑨setParameter(int position, Date d, TemporalType type) :为查询语句的指定位置参数赋 Date 值。Position 指定参数序号,value 为赋给参数的值,temporalType 取 TemporalType 的枚举常量,包括 DATE、TIME 及 TIMESTAMP 三个,,用于将 Java 的 Date 型值临时转换为数据库支持的日期时间类型(java.sql.Date、java.sql.Time及java.sql.Timestamp)。 ⑩setParameter(int position, Calendar c, TemporalType type) :为查询语句的指定位置参数赋 Calenda r值。position 指定参数序号,value 为赋给参数的值,temporalType 的含义及取舍同前。 ⑪setParameter(String name, Object value) :为查询语句的指定名称参数赋值。 ⑫setParameter(String name, Date d, TemporalType type) :为查询语句的指定名称参数赋 Date 值。用法同前。 ⑬setParameter(String name, Calendar c, TemporalType type) :为查询语句的指定名称参数设置Calendar值。name为参数名,其它同前。该方法调用时如果参数位置或参数名不正确,或者所赋的参数值类型不匹配,将抛出 IllegalArgumentException 异常。

select语句:

  • select语句用于执行查询。其语法可表示为:
select_clause 
form_clause 
[where_clause] 
[groupby_clause] 
[having_clause]
[orderby_clause]

select-from 子句:

  • from 子句是查询语句的必选子句。 ①Select 用来指定查询返回的结果实体或实体的某些属性 ②From 子句声明查询源实体类,并指定标识符变量(相当于SQL表的别名)。
  • 如果不希望返回重复实体,可使用关键字 distinct 修饰。select、from 都是 JPQL的关键字,通常全大写或全小写,建议不要大小写混用。

查询所有实体:

  • 查询所有实体的 JPQL 查询字串很简单,例如:
select o from Order o 或  select o from Order as o
  • 关键字 as 可以省去。
  • 标识符变量的命名规范与 Java 标识符相同,且区分大小写。
  • 调用 EntityManager 的 createQuery() 方法可创建查询对象,接着调用 Query 接口的 getResultList() 方法就可获得查询结果集。例如:
Query query = entityManager.createQuery( "select o from Order o"); 
List orders = query.getResultList();
Iterator iterator = orders.iterator();
while( iterator.hasNext() ) {
	// 处理Order
}

where子句:

  • where子句用于指定查询条件,where跟条件表达式。例:
select o from Orders o where o.id = 1
select o from Orders o where o.id > 3 and o.confirm = 'true'	
select o from Orders o where o.address.streetNumber >= 123
  • JPQL也支持包含参数的查询,例如:
select o from Orders o where o.id = :myId
select o from Orders o where o.id = :myId and o.customer = :customerName

 

  • 注意:参数名前必须冠以冒号:,执行查询前须使用Query.setParameter(name, value)方法给参数赋值。
  • 也可以不使用参数名而使用参数的序号,例如:
select o from Order o where o.id = ?1 and o.customer = ?2
  • 其中 ?1 代表第一个参数,?2 代表第一个参数。在执行查询之前需要使用重载方法
Query.setParameter(pos, value) 提供参数值。
Query query = entityManager.createQuery( "select o from  	Orders o where o.id = ?1 and o.customer = ?2" );
query.setParameter( 1, 2 );
query.setParameter( 2, "John" );
List orders = query.getResultList();
… …
  • where条件表达式中可用的运算符基本上与SQL一致,包括: ①算术运算符:+ - * / +(正) -(负) ②关系运算符:== <> > >= < <= between…and like in is null 等 ③逻辑运算符: and or  not
  • where子句示例:
// 以下语句查询 Id 介于 100 至 200 之间的订单。
select o from Orders o where o.id between 100 and 200
// 以下语句查询国籍为的 'US'、'CN'或'JP' 的客户。
select c from Customers c where c.county in ('US','CN','JP')
// 以下语句查询手机号以139开头的客户。%表示任意多个字符序列,包括0个。
select c from Customers c where c.phone like '139%'
// 以下语句查询名字包含4个字符,且234位为ose的客户。_表示任意单个字符。
select c from Customers c where c.lname like '_ose' 
// 以下语句查询电话号码未知的客户。Nul l用于测试单值是否为空。
select c from Customers c where c.phone is null
// 以下语句查询尚未输入订单项的订单。empty用于测试集合是否为空。
select o from Orders o where o.orderItems is empty

查询部分属性:

  • 如果只须查询实体的部分属性而不需要返回整个实体。例如:
select o.id, o.customerName, o.address.streetNumber from Order o order by o.id
  • 执行该查询返回的不再是Orders实体集合,而是一个对象数组的集合(Object[]),集合的每个成员为一个对象数组,可通过数组元素访问各个属性。

使用 Hibernate 的查询缓存:

String jpql = "SELECT c FROM Customer c" ;
Query query = entityManager.createQuery(jpql);
query.setHint(QueryHints.CACHEABLE, false);

order by子句:

  • order by子句用于对查询结果集进行排序。和SQL的用法类似,可以用 “asc“ 和 "desc“ 指定升降序。如果不显式注明,默认为升序。
select o from Orders o order by o.id
select o from Orders o order by o.address.streetNumber desc
select o from Orders o order by o.customer asc, o.id desc

group by子句与聚合查询:

  • group by 子句用于对查询结果分组统计,通常需要使用聚合函数。常用的聚合函数主要有 AVG、SUM、COUNT、MAX、MIN等,它们的含义与SQL相同。例如:
select max(o.id) from Orders o
  • 没有 group by子句的查询是基于整个实体类的,使用聚合函数将返回单个结果值,可以使用Query.getSingleResult()得到查询结果。例如:
Query query = entityManager.createQuery(
					"select max(o.id) from Orders o");
Object result = query.getSingleResult();
Long max = (Long)result;

having子句:

  • Having 子句用于对 group by 分组设置约束条件,用法与where 子句基本相同,不同是 where 子句作用于基表或视图,以便从中选择满足条件的记录;having 子句则作用于分组,用于选择满足条件的组,其条件表达式中通常会使用聚合函数。
  • 例如,以下语句用于查询订购总数大于100的商家所售商品及数量:
select o.seller, o.goodId, sum(o.amount) from V_Orders o group by 
o.seller, o.goodId having sum(o.amount) > 100
  • having子句与where子句一样都可以使用参数。

关联查询:

  • 在JPQL中,很多时候都是通过在实体类中配置实体关联的类属性来实现隐含的关联(join)查询。例如:
select o from Orders o where o.address.streetNumber=2000 
  • 上述JPQL语句编译成以下SQL时就会自动包含关联,默认为左关联。
  • 在某些情况下可能仍然需要对关联做精确的控制。为此,JPQL 也支持和 SQL 中类似的关联语法。如:
left out join / left join 
inner join 
left join / inner join fetch 
  • 其中,left join和left out join等义,都是允许符合条件的右边表达式中的实体为空。
  • 例如,以下外关联查询可以找出所有客户实体记录,即使它未曾订货:
select c from Customers c left join c.orders o
  • 以下内关联查询只找出所有曾订过商品的客户实体记录:
select c from Customers c inner join c.orders o
  • 如果001号客户下过5次订单的话,以下fetch关联查询将得到 5个客户实体的引用,并且执行了 5 个订单的查询:
select c from Customers c left join fetch c.orders o where c.id=001

子查询:

  • JPQL也支持子查询,在 where 或 having 子句中可以包含另一个查询。当子查询返回多于 1 个结果集时,它常出现在any、all、exist s表达式中用于集合匹配查询。它们的用法与SQL语句基本相同。
string jpql = "SELECT c FROM Customer c WHERE c.customerName = " +
"(SELECT c2.customerName FROM customer c2 WHERE c2.customerId = ?1)";
Query query = entityManager.createQuery(jpq1);
query.setHint(QueryHints.CACHEABLE, false).setParameter(11);

JPQL函数:

  • 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,它们不需要参数,返回服务器上的当前日期、时间和时戳。

update语句:

  • update语句用于执行数据更新操作。主要用于针对单个实体类的批量更新
  • 以下语句将帐户余额不足万元的客户状态设置为未偿付:
update Customers c set c.status = '未偿付' where c.balance < 10000

delete语句:

  • delete语句用于执行数据更新操作。
  • 以下语句删除不活跃的、没有订单的客户:
delete from Customers c where c.status = 'inactive' and c.orders is empty

Spring 整合 JPA

三种整合方式:

  • LocalEntityManagerFactoryBean:适用于那些仅使用 JPA 进行数据访问的项目,该 FactoryBean将根据JPA PersistenceProvider自动检测配置文件进行工作,一般从“META-INF/persistence.xml”读取配置信息,这种方式最简单,但不能设置 Spring中定义的DataSource,且不支持 Spring 管理的全局事务。
  • 从JNDI中获取:用于从 Java EE 服务器获取指定的EntityManagerFactory,这种方式在进行 Spring事务管理时一般要使用 JTA 事务管理
  • LocalContainerEntityManagerFactoryBean:适用于所有环境的 FactoryBean,能全面控制EntityManagerFactory 配置,如指定 Spring 定义的 DataSource 等等。
	<!-- 配置自动扫描的包 -->
	<context:component-scan base-package="com.atguigu.jpa"></context:component-scan>

	<!-- 配置 C3P0 数据源 -->
	<context:property-placeholder location="classpath:db.properties"/>
	
	<bean id="dataSource"
		class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="user" value="${jdbc.user}"></property>
		<property name="password" value="${jdbc.password}"></property>
		<property name="driverClass" value="${jdbc.driverClass}"></property>
		<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>	
		<!-- 配置其他属性 -->
	</bean>
	
	<!-- 配置 EntityManagerFactory -->
	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<!-- 配置 JPA 数据源 -->
		<property name="dataSource" ref="dataSource"></property>
		<!-- 配置 JPA 提供商的适配器. 可以通过内部 bean 的方式来配置 -->
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>	
		</property>	
		<!--
		<property name="jpaVendorAdapter">
        	<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            	//配置是否自动创建数据库表
            	<property name="generateDdl" value="true"/>
            	//指定数据库类型,注意全部是大写
            	<property name="database" value="MYSQL"/>
            	//数据库方言:支持的特有语法(每个数据库都有细微的差别)
            	<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
            	<property name="showSql" value="true"/>
        	</bean>
     	</property>
     	-->
		<!-- 配置实体类所在的包 -->
		<property name="packagesToScan" value="com.atguigu.jpa.spring.entities"></property>
		<!-- 配置 JPA 的基本属性. 例如 JPA 实现产品的属性 -->
		<property name="jpaProperties">
			<props>
				<!-- 二级缓存相关 -->
				<prop key="hibernate.cache.region.factory_class">
					org.hibernate.cache.ehcache.EhCacheRegionFactory
				</prop>
				<prop key="net.sf.ehcache.configurationResourceName">
					ehcache-hibernate.xml
				</prop>
				<!-- 生成的数据表的列的映射策略 -->
				<prop key="hibernate.ejb.naming_strategy">
					org.hibernate.cfg.ImprovedNamingStrategy
				</prop>
				<!-- hibernate 基本属性 -->
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.format_sql">true</prop>
				<prop key="hibernate.hbm2ddl.auto">update</prop>
			</props>
		</property>
	</bean>
	
	<!-- 配置 JPA 使用的事务管理器 -->
	<bean id="transactionManager"
		class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory"></property>	
	</bean>
	
	<!-- 配置支持基于注解式事务配置 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>

</beans>

JDBC和JPA区别

  • 使用的sql语言不同: ①JDBC使用的是基于关系型数据库的标准SQL语言; ②JPA通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。
  • 操作的对象不同: ①JDBC操作的是数据,将数据通过SQL语句直接传送到数据库中执行: ②JPA操作的是持久化对象,由底层持久化对象的数据更新到数据库中。
  • 数据状态不同: ①JDBC操作的数据是“瞬时”的,变量的值无法与数据库中的值保持一致; ②JPA操作的数据时可持久的,即持久化对象的数据属性的值是可以跟数据库中的值保持一致的。