JPA学习之JSP对象持久化API总结
JPA 学习笔记
##jpa是什么
1 | Java Persistence API:用于对象持久化的 API |
JPA和Hibernate的关系
1 |
|
jpa的hello world程序
首先弄个jpa的helloworld程序
persistence.xml 文件。这个要放到resources目录下面的META-INF目录下面.
JPA规范要求在类路径的META-INF目录下面放persistence.xml,文件名称是固定的。
1 |
|
pom.xml 文件,采用maven来管理jar包的依赖,这里加的jar包比较多.
几个比较关键的jar包, hibernate-entitymanager ,hibernate-jpa-2.1-api ,hibernate-commons-annotations
1 |
|
持久化类:
1 | package com.mamh.jpa; |
测试类
1 | package com.mamh.jpa; |
jpa中常用的注解
@Entity 放到实体类上面
1 | @Entity 标注用于实体类声明语句之前,指出该Java 类为实体类,将映射到指定的数据库表。 |
@Table(name = “jpa_customer”)设置表名
1 | 当实体类与其映射的数据库表名不同名时需要使用 @Table 标注说明,该标注与 @Entity 标注并列使用, |
@Id映射主键的,放到getter方法上
1 | @Id 标注用于声明一个实体类的属性映射为数据库的主键列。该属性通常置于属性声明语句之前,可与声明语句同行,也可写在单独行上。 |
@GeneratedValue(strategy = GenerationType.AUTO)设置生成主键的策略
1 | @GeneratedValue 用于标注主键的生成策略,通过 strategy 属性指定。默认情况下, |
@Basic 默认的注解
1 | @Basic 表示一个简单的属性到数据库表的字段的映射,对于没有任何标注的 getXxxx() 方法,默认即为@Basic |
@Column(name = “last_name”) 设置列,name映射到数据库表中的列名
1 | 当实体的属性与其映射的数据库表的列不同名时需要使用@Column 标注说明, |
@Transient 不需要影响为数据库表的列的方法上加上这个注解
1 | 表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性. |
@Temporal(TemporalType.TIMESTAMP) 设置时间日期对应到数据库表列的类型的
1 | 在核心的 Java API 中并没有定义 Date 类型的精度(temporal precision). |
jpa中常用的类
Persistence类
1 | Persistence 类是用于获取 EntityManagerFactory 实例。该类包含一个名为 createEntityManagerFactory 的 静态方法 。 |
EntityManagerFactory
1 | EntityManagerFactory 接口主要用来创建 EntityManager 实例。该接口约定了如下4个方法: |
EntityManager
1 | 在 JPA 规范中, EntityManager 是完成持久化操作的核心对象。实体作为普通 Java 对象, |
EntityManager.find()方法
1 | find (Class<T> entityClass,Object primaryKey):返回指定的 OID 对应的实体类对象, |
1 |
|
EntityManager.getReference()方法,只有在使用对象的时候才去数据库中查询。会出现懒加载异常。
1 | getReference (Class<T> entityClass,Object primaryKey):与find()方法类似,不同的是:如果缓存中不存在指定的 Entity, EntityManager 会创建一个 Entity 类的代理,但是不会立即加载数据库中的信息,只有第一次真正使用此 Entity 的属性才加载,所以如果此 OID 在数据库不存在,getReference() 不会返回 null 值, 而是抛出EntityNotFoundException |
1 |
|
EntityManager.persist()方法,使对象由临时状态变为持久化状态。
1 | persist (Object entity):用于将新创建的 Entity 纳入到 EntityManager 的管理。该方法执行后,传入 persist() 方法的 Entity 对象转换成持久化状态。 |
1 |
|
如果这时设置了customer的ID,则会报错的。
EntityManager.remove()方法,删除数据库记录,只能删除持久化对象,游离对象不行。
1 | remove (Object entity):删除实例。如果实例是被管理的,即与数据库实体记录关联,则同时会删除关联的数据库记录。 |
这样才能删除
1 |
|
EntityManager.merge()方法 merge (T entity):merge() 用于处理 Entity 的同步。即数据库的插入和更新操作
会创建一个新的对象,把临时对象的属性复制到新的对象中,然后对新的对象执行持久化操作,新的对象中会有id,之前的对象没有id了。
1 |
|
若传入的是一个游离对象,也就是说传入的对象有ID值。
1 |
|
1 | flush ():同步持久上下文环境,即将持久上下文环境的所有未保存实体的状态信息保存到数据库中。 |
EntityTransaction
1 | EntityTransaction 接口用来管理资源层实体管理器的事务操作。通过调用实体管理器的getTransaction方法 获得其实例。 |
多对一关联关系
多对一在插入数据的情况:
1 |
|
1 | Hibernate: |
保存的时候建议先保存一的那一端对象,也就是先保存customer。
然后再保存多的那一端,也就是order。这样不会多出sql语句。
1 |
|
1 | Hibernate: |
多对一在获取的时候:
1 |
|
1 | Hibernate: |
这里会使用一个左外链接。
在Order类里面可以设置customer @ManyToOne (fetch = FetchType.LAZY) 为懒加载。
多对一在删除数据的情况
1 |
|
这种情况下是不让删除的,因为有个外键。
##一对多关联关系
一对多关联关系插入数据的情况
1 |
|
单向一对多,执行保存时,会多出update语句。因为多的一端在插入的时候不会同时插入外键列。
一对多关联关系查询数据的情况
1 |
|
默认是懒加载的情况。
通用可以使用 @OneToMany(fetch = FetchType.EAGER) 来修改。然后那个查询会变为左外链接。
双向一对多关联关系
1 | /** |
先插入customer,然后在插入order,只有2个update语句,如果反过来插入,会有4条update语句的。
1 | Hibernate: |
在进行双向一对多的关联关系时。建议使用多的一方来维护管理关系。
可以在customer上设置 @OneToMany(fetch = FetchType.EAGER,cascade = {CascadeType.REMOVE},mappedBy = “customer”)
这样customer就不会维护关联关系了。
此时这个不能同时使用 @JoinColumn(name = “customer_id”) 了。
双向一对一的关联关系
1 | package com.mamh.jpa; |
1 | package com.mamh.jpa; |
1 |
|
在添加数据的时候, 先保存不维护关联关系的那一方,这里就是先保存manager。
1 | Hibernate: |
获取的情况
1 |
|
1 | Hibernate: |
1 |
|
1 | Hibernate: |
双向一对一的关联关系
基于主键来做这个一对一关联关系,可以使用“@PrimaryKeyJoinColumn(name = “id”)”
双向多对多关联关系
1 | package com.mamh.jpa; |
1 | package com.mamh.jpa; |
使用@ManyToMany注解来映射多对多关联关系。使用@JoinTable来映射中间表
1 | @ManyToMany |
1 | @ManyToMany(mappedBy = "categories") |
多对多的保存
1 | @Test |
输出结果
1 | Hibernate: |
多对多的查询
1.先获取维护关联关系的,也就是先获取Item。
1 |
|
1 | Hibernate: |
- 获取 不维护关联关系的,也就是先获取Category。
1 |
|
1 | Hibernate: |
通过以上两种方式获取的,效果是一样的,因为是有一张中间表,获取那边都是一样的。
jpql
1 | @Test |
命名查询
需要在实体类上面加上注解@NamedQuery(name = “testNamedQuery”, query = “select c from Customer c where c.id = ?”)
1 |
|
1 |
|
一级缓存
jpa默认是有一级缓存的。
1 |
|
上面的代码查询2次,只会发送一条sql语句的。特别注意 查询出来的数据要存在,如果不存在也是发送2条sql语句了。
二级缓存
1 |
|
配置文件
1 |
|
最后实体类上面要加上@Cacheable(true)注解
这样最后的输出就只会发送一个sql语句了
1 | Hibernate: |
查询缓存
需要在配置文件中配置启用查询缓存
1 |
|
还有就是jar的版本要对。 hibernate-ehcache的版本要对。
1 |
|
1 |
|
本来是发送2个sql语句的,现在使用了查询缓存只发送1个sql语句。
1 | Hibernate: |
order by 和 group by 子句
1 |
|
1 |
|
1 |
|
1 | Hibernate: |
关联查询
1 |
|
如上代码没有使用left outer join fetch,这样先获取customer会发送一条sql语句。然后在获取oder又会发送一条sql语句的。
1 | Hibernate: |
以下代码加上left outer join fetch,效果就不一样了。
1 |
|
1 |
|
如果不加fetch,返回的结果会是多个
1 |
|
1 | Hibernate: |
子查询
1 |
|
1 | Hibernate: |
jpql的udpate操作
1 |
|
jpql的delete操作
1 |
spring整合JPA
有这么三种整合方式
1 | LocalEntityManagerFactoryBean:适用于那些仅使用 JPA 进行数据访问的项目, |
1 | package com.mamh.jpa; |
1 |
|
1 | package com.mamh.jpa.dao; |
1 |
|
1 |
|