-
(十一)Spring从入门到入土——Spring整合JPA
1、jpa入门
-
Java持久层api,替代jdbc,Java持久化规范。JPA是Hibernate的一个抽象,是一种ORM规范,是Hibernate功能的一个子集,Hibernate是JPA的一个实现
-
jpa和jdbc优缺点:
-
- jdbc:
本质:处理Java对象和关系型数据库表之间的转化
优点:性能最高,操作数据库最底层
缺点:
1.使用复杂(重复代码很多),移植数据库很麻烦
2.性能优化需要自己处理,没有提供数据缓存,需要自己实现。
3.面向的是sql语句操作,不是面向对象的。
-
- jpa:
本质:只是对于jdbc再次做了一层封装
优点:
1.程序员操作很简单,代码简单。
2.直接面向持久对象操作
3.提供世界级数据缓存(一级缓存,二级缓存,查询缓存)
4.数据库移植性很强,很少的修改(通过配置方言):把各种数据库抽取了一个方言接口,不同的数据库实现类一个方言接口,需要换数据库,只需要修改方言实现,驱动jar文件,连接数据库信息(4个:驱动,url地址,用户名,密码)
缺点:
1.不能干预sql语句的生成。find方法默认查询表的所有字段
2.一个项目中如果对sql语句的优化比较高,不适用jpa(不过jpa中有对原生sql的支持)
3.如果一个表中有上亿的数据,也不适合用jpa和jdbc(可以使用数据库读写分析,分库分表方案解决)
- 适用的项目规模:中小型,jpa在性能优化上比较吃力,超大型还是推荐使用MyBatis.
- ORM框架:就是把数据保存到可掉电式存储设备中,持久层就是dao层,
- ORM是对象关系映射框架,就是通过Java对象映射到数据库表,通过操作Java对象,就可以完成对数据库表的操作,
面向对象概念 | 面向关系概念 |
---|---|
类 | 表 |
对象实体 | 表的行(记录) |
属性,对象粒度 | 表的列(字段) |
2、JPA基本注解
-
@Entity:用于实体类声明语句之前,指出该Java类为实体类,将映射到指定的数据库表。
-
@Table:当实体类与其映射的数据库表名不同名时使用,该标注于@Entity并列使用,置于实体类声明语句之前,可写于单独语句行,也可与声明语句同行。
-
- name用于指明数据库的表名
- catalog和schema用于设置表所属的数据库目录或模式,通常为数据库名
- uniqueConstraints用于设置约束条件,通常不设置
-
@Id声明一个实体类的属性映射为数据库的主键列。通常位置声明语句之前或者同行,也可以置于属性的getter方法之前。、
-
@GeneratedValue用于标注主键的生成策略,通过strategy属性指定。默认情况下,jpa自动选择一个适合底层数据库的主键生成策略:SqlServer对应identity,MySQL对应auto increment。
-
- IDENTITY:采用数据库ID自增长方式来自增主键字段,但是Oracle不支持这种方式
- AUTO:JPA自动选择合适的策略,是默认选项:
- SEQUENCE:通过序列产生主键,通过@SequenceGenerator注解指定序列名,但是MySql不支持这种方式
- TABLE:通过表产生主键,便于数据库的移植
-
@Basic表示一个简单的属性到数据库表的字段的映射对于没有任何标注的get()方法。默认即为@Basic
-
- fetch:表示该属性的读取策略,有EAGER和LAZY两种,表示主支抓取和延迟加载,默认为true
- optional:表示该属性是否允许为null默认为true
-
Column:当实体属性与其映射的数据库表的类不同名时需要使用
-
Transient:表示该属性并非到数据库表的字段的映射,ORM框架将忽略该属性。必须标注
-
Temporal:调整精度
3、JPA的API
-
Persistence:用于获取EntiryManagerFactory的实例
-
- 常用方法:Persistence.createEntityManagerFactory(persistenceUnitName) 方法
-
EntiryManagerFactory
-
- 获取EntiryManager
- close()方法,关闭自身
-
EntityManager的常用API
-
- find()方法,在执行find方法时就发送SQL语句(类似于Hibernate中的Session的get()方法)
- getReference()方法,若不适用查询的对象则返回一个代理对象,到真正使用的时候才发送SQL语句chax(类似于Hibernate的Session的load()方法)
- persistence()方法,类似于 Hibernate 的 save() 方法,与 Hibernate 的 save() 方法不同的是其不能插入一个有 id 属性的对象
- remove() 方法,类似于 Hibernate 中 Session 的 delete 方法,但是其不能删除 游离化对象(仅有 id)
- merge() 方法,类似于 Hibernate 中 Session 的 saveOrUpdate() 方法
-
EntityTransaction:JPA中的事务操作
-
- 常用API:begin();commit();rollback()
4、JPA中映射关联关系
-
映射单向多对一的关联关系,many的一方作为关系的维护段,one的一方作为被维护端,one方指定@OneToMany注释并设置mappedBy属性,以指定他是被维护端,many方指定@ManyToOne注解,并使用@JoinColumn指点外键名称
-
- 创建Order实体类:标注注解生成数据表,使用@ManyToOne映射多对一的关联关系,使用@JoinColumn来标注外键。
- 单向多对一的保存:保存多对一是,建议先保存1的一段,这样不会多出额外的update语句
- 获取操作(find):默认情况下使用左外连接的方式来获取n的一端的对象和其关联的1的一端的对象。可以使用@ManyToOne的fetch属性来修改默认的关联属性的加载策略
- 删除操作(remove):不能直接删除1的一端,因为有外键约束
- 修改操作:可以根据n的一端对1的一端镜像修改操作。
-
映射单项一对多的关联关系Customer:Order 1:n,Customer中有Order的Set稽核属性,Order中没有Customer的属性
-
- 在Customer中添加Order的Set集合属性,并映射1-n关联关系,重新生成数据表
- 保存操作(persist):总会多出UPDATE语句,n的一端在插入式不会同时插入外键列
- 查询操作(find)默认使用懒加载
- 删除操作(remove):默认情况下删除1的一端,会先把关联的n的一端的外键置空,然后再删除,可以通过@OneToMany的cascade属性
-
映射双向多对一的关联关系(注:双向多对一通双向一对多)
-
- 实体:Customer中有Order的Set集合属性,Order中有Customer的属性,两个实体映射的外键列必须一致,都为CUSTOMER_ID
- 保存操作(persist):
-
映射双向一对一的关联关系
-
映射双向多对多的关联关系
5、JPA的二级缓存
-
若JPA实现支持二级缓存,该节点可以配置在当前的持久化单位中是否启用二级换窜,可配置如下值:
-
- ALL:所有实体类都被缓存
- NONE:所有实体类都不能被缓存
- ENABLE_SELECTIVE:表示@Cacheable(true)注解的实体类将被缓存
- DISABLE_SELECTIVE:换窜除表示@Cacheable(false)依赖的所有实体类
- UNSPECIFIED:默认值,JPA产品默认值将被使用
6、JPQL
-
JPQL语言的语句是select语句,update语句或delete语句,他们都通过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模式。参数可以取两个枚举值: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)
-
-
- 为查询语句的指定名称参数设置CalendarnameIllegalArgumentException异常。
-
-
Select语句:
-
- from是必选子句,如果不想返回重复实体,可以使用关键字distinct来进行修饰
- 查询所有实体:select o from Order o
- 调用 EntityManager的createQuery()方法可创建查询对象,接着调用Query接口的getResultList()方法就可获得查询结果集
- where子句用于指定查询条件,也支持包含参数的查询,但是参数名前必须冠以冒号。同样也可以使用参数序号
- order by子句,可以对查询结果镜像排序,默认为升序,asc(升序)desc(降序)
- group by子句与聚合查询,通常的聚合函数:AVG,COUNT,MAX,MIN
- having子句用于对group by分组设置约束条件,用法与where子句基本相同,having子句作用于分组,用于选择满足条件的组,其条件表单时中通常会使用聚合函数
- 关联查询。默认左关联,
- 子查询:常出现在any,all,exist s表达式中用于集合匹配查询
-
JPQL函数:字符串处理函数,算术函数和日期函数
-
UPDATE语句:用于执行数据更新操作,主要用于针对单个实体类的批量更新
-
DELETE语句:用于执行数据更新操作
7、整合Spring
三种整合方式
- LocalEntityManagerFactoryBean:适用于那些仅使用 JPA 进行数据访问的项目,该 FactoryBean 将根据JPA PersistenceProvider 自动检测配置文件进行工作,一般从“META-INF/persistence.xml”读取配置信息,这种方式最简单,但不能设置Spring 中定义的DataSource,且不支持 Spring管理的全局事务
- 从JNDI中获取:用于从 Java EE 服务器获取指定的EntityManagerFactory,这种方式在进行 Spring 事务管理时一般要使用 JTA 事务管理
- LocalContainerEntityManagerFactoryBean**:适用于所有环境的 FactoryBean,能全面控制 EntityManagerFactory 配置,如指定 Spring 定义的 DataSource 等等。
最后
- 如果觉得看完有收获,希望能给我点个赞,这将会是我更新的最大动力,感谢各位的支持
- 欢迎各位关注我的公众号【java冢狐】,专注于java和计算机基础知识,保证让你看完有所收获,不信你打我
- 如果看完有不同的意见或者建议,欢迎多多评论一起交流。感谢各位的支持以及厚爱。