jpa学习笔记

来源:互联网 发布:godaddy域名别名解析 编辑:程序博客网 时间:2024/05/17 00:15
------------------@Transient----------------------
//工具方法. 不需要映射为数据表的一列. 
@Transient
public String getInfo(){
return "lastName: " + lastName + ", email: " + email;
}




-------------------@Temporal------------------
//设置数据库列的类型精确度
@Temporal(TemporalType.TIMESTAMP)
public Date getCreatedTime() {
return createdTime;
}


@Temporal(TemporalType.DATE)
public Date getBirth() {
return birth;
}




-------------find/getReference----------------------
find相当于hibernate的get,getReference相当于hibernate的load
区别:getReference只有使用查询出来的对象才会发送SQL,而get执行查询就立即发送SQL查询


--------------persist----------
persist保存,相当于hibernate的save
和 hibernate 的 save 方法的不同之处: 若对象有 id, 则不能执行 insert 操作, 而会抛出异常. 


--------------remove--------------
删除,类似于 hibernate的delete 方法
但注意: 该方法只能移除 持久化 对象. 而 hibernate 的 delete 方法实际上还可以移除 游离对象.
//Customer customer = new Customer();删除这个对象会出错,只能使用下面哪种方式,先查询再删除
// customer.setId(2);

Customer customer = entityManager.find(Customer.class, 2);
entityManager.remove(customer);


----------------merge------------------
总的来说: 类似于 hibernate Session 的 saveOrUpdate 方法.
//1. 若传入的是一个临时对象
//会创建一个新的对象, 把临时对象的属性复制到新的对象中, 然后对新的对象执行持久化操作. 所以
//新的对象中有 id, 但以前的临时对象中没有 id. 


//2.若传入的是一个游离对象, 即传入的对象有 OID. 
//1. 若在 EntityManager 缓存中没有该对象
//2. 若在数据库中也没有对应的记录
//3. JPA 会创建一个新的对象, 然后把当前游离对象的属性复制到新创建的对象中
//4. 对新创建的对象执行 insert 操作. 


//3.若传入的是一个游离对象, 即传入的对象有 OID. 
//1. 若在 EntityManager 缓存中没有该对象
//2. 若在数据库中也有对应的记录
//3. JPA 会查询对应的记录, 然后返回该记录对一个的对象, 再然后会把游离对象的属性复制到查询到的对象中.
//4. 对查询到的对象执行 update 操作. 


//4.若传入的是一个游离对象, 即传入的对象有 OID. 
//1. 若在 EntityManager 缓存中有对应的对象
//2. JPA 会把游离对象的属性复制到查询到EntityManager 缓存中的对象中.
//3. EntityManager 缓存中的对象执行 UPDATE. 


------------------flush---------------
同 hibernate 中 Session 的 flush 方法. 
作用:发送SQL语句,但是没有提交事务之前,数据库还看不到数据
如:
Customer customer = entityManager.find(Customer.class, 1);
System.out.println(customer);

customer.setLastName("AA");//在这句话这里更改了lastname

entityManager.flush();//没有提交之前可以使用flush方法发送sql


--------------------refresh-----------------
重新获取一个对象信息,看是不是最新的,把新的数据重新获取




==================级联操作==============
-------------单向多对一---------
保存多对一时, 建议先保存 1 的一端, 后保存 n 的一端, 这样不会多出额外的 UPDATE 语句.


//映射单向 n-1 的关联关系
//使用 @ManyToOne 来映射多对一的关联关系
//使用 @JoinColumn 来映射外键. 
//可使用 @ManyToOne 的 fetch 属性来修改默认的关联属性的加载策略
@JoinColumn(name="CUSTOMER_ID")
@ManyToOne(fetch=FetchType.LAZY)




------------------单向、双向 一对多-----------------------
//映射单向 1-n 的关联关系
//使用 @OneToMany 来映射 1-n 的关联关系
//使用 @JoinColumn 来映射外键列的名称
//可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略
//可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略. 
//注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 属性, 则 @OneToMany 端就不能再使用 @JoinColumn 属性了. 
// @JoinColumn(name="CUSTOMER_ID")
@OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.REMOVE},mappedBy="customer")
public Set<Order> getOrders() {
return orders;
}


//若是双向 1-n 的关联关系, 执行保存时
//若先保存 n 的一端, 再保存 1 的一端, 默认情况下, 会多出 n 条 UPDATE 语句.
//若先保存 1 的一端, 则会多出 n 条 UPDATE 语句
//在进行双向 1-n 关联关系时, 建议使用 n 的一方来维护关联关系, 而 1 的一方不维护关联系, 这样会有效的减少 SQL 语句. 
//注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 属性, 则 @OneToMany 端就不能再使用 @JoinColumn 属性了. 

//单向 1-n 关联关系执行保存时, 一定会多出 UPDATE 语句.
//因为 n 的一端在插入时不会同时插入外键列. 


//默认情况下, 若删除 1 的一端, 则会先把关联的 n 的一端的外键置空, 然后进行删除. 
//可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略. 




--------------------双向一对一-------------------
//使用 @OneToOne 来映射 1-1 关联关系。
//若需要在当前数据表中添加主键则需要使用 @JoinColumn 来进行映射. 注意, 1-1 关联关系, 所以需要添加 unique=true
@JoinColumn(name="MGR_ID", unique=true)
@OneToOne(fetch=FetchType.LAZY)


//对于不维护关联关系, 没有外键的一方, 使用 @OneToOne 来进行映射, 建议设置 mappedBy=true
@OneToOne(mappedBy="mgr")
public Department getDept() {


//双向 1-1 的关联关系, 建议先保存不维护关联关系的一方, 即没有外键的一方, 这样不会多出 UPDATE 语句.
//1.默认情况下, 若获取维护关联关系的一方, 则会通过左外连接获取其关联的对象. 
//但可以通过 @OntToOne 的 fetch 属性来修改加载策略.
//1. 默认情况下, 若获取不维护关联关系的一方, 则也会通过左外连接获取其关联的对象. 
//可以通过 @OneToOne 的 fetch 属性来修改加载策略. 但依然会再发送 SQL 语句来初始化其关联的对象
//这说明在不维护关联关系的一方, 不建议修改 fetch 属性. 


-------------------多对多----------------
//使用 @ManyToMany 注解来映射多对多关联关系
//使用 @JoinTable 来映射中间表
//1. name 指向中间表的名字
//2. joinColumns 映射当前类所在的表在中间表中的外键
//2.1 name 指定外键列的列名
//2.2 referencedColumnName 指定外键列关联当前表的哪一列
//3. inverseJoinColumns 映射关联的类所在中间表的外键
@JoinTable(name="ITEM_CATEGORY",
joinColumns={@JoinColumn(name="ITEM_ID", referencedColumnName="ID")}, //referencedColumnName也可以不写
inverseJoinColumns={@JoinColumn(name="CATEGORY_ID", referencedColumnName="ID")})
@ManyToMany
public Set<Category> getCategories() {
return categories;
}


@ManyToMany(mappedBy="categories")
public Set<Item> getItems() {


===================缓存================
Customer customer1 = entityManager.find(Customer.class, 1);
Customer customer2 = entityManager.find(Customer.class, 1);
这样查询两个相同数据,会自动使用一级缓存,会看到只会发送一条SQL


如果需要使用二级缓存,需要在persistence.xml中加如下配置:
<!-- 
配置二级缓存的策略 
ALL:所有的实体类都被缓存
NONE:所有的实体类都不被缓存. 
ENABLE_SELECTIVE:标识 @Cacheable(true) 注解的实体类将被缓存
DISABLE_SELECTIVE:缓存除标识 @Cacheable(false) 以外的所有实体类
UNSPECIFIED:默认值,JPA 产品默认值将被使用
-->
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>


<!-- 二级缓存相关 -->
<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"/><!--查询缓存-->
并添加缓存jar包和ehcache.xml
在实体类上添加@Cacheable(true)


=====================查询====================
---------------jpql--------------
String jpql = "FROM Customer c WHERE c.age > ?";
Query query = entityManager.createQuery(jpql);

//占位符的索引是从 1 开始
query.setParameter(1, 1);
List<Customer> customers = query.getResultList();
System.out.println(customers.size());
-----------------
如果只想查询部分列,那么集合将会存放数组
如果查询部分列,不想集合存放数组,那么需要给实体提供一个对应的构造函数,并如下查询:
String jpql = "SELECT new Customer(c.lastName, c.age) FROM Customer c WHERE c.id > ?";
List result = entityManager.createQuery(jpql).setParameter(1, 1).getResultList();

System.out.println(result);
------------
也可以通过createNamedQuery查询实体类中已经写好的jpql
@NamedQuery(name="testNamedQuery", query="FROM Customer c WHERE c.id = ?")//这里eclipse可能会显示错误,但是不影响运行,也可以写成select c FROM Customer c WHERE c.id = ?
@Table(name="JPA_CUTOMERS")
@Entity
public class Customer {


Query query = entityManager.createNamedQuery("testNamedQuery").setParameter(1, 3);
Customer customer = (Customer) query.getSingleResult();

System.out.println(customer);
--------------------
也可以使用sql语句查询:
String sql = "SELECT age FROM jpa_cutomers WHERE id = ?";
Query query = entityManager.createNativeQuery(sql).setParameter(1, 3);

Object result = query.getSingleResult();
System.out.println(result);


-------------------使用 hibernate 的查询缓存--------------
在每次查询后面跟上.setHint(QueryHints.HINT_CACHEABLE, true);如:
第一次查询:Query query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);
第二次查询:query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);


-----------------------
查询时也可以使用OrderBy、GroupBy、关联查询、子查询,如:
OrderBy:
String jpql = "FROM Customer c WHERE c.age > ? ORDER BY c.age DESC";
GroupBy:
String jpql = "SELECT o.customer FROM Order o "
+ "GROUP BY o.customer "
+ "HAVING count(o.id) >= 2";
关联查询:
String jpql = "FROM Customer c LEFT OUTER JOIN FETCH c.orders WHERE c.id = ?";
子查询:
String jpql = "SELECT o FROM Order o "
+ "WHERE o.customer = (SELECT c FROM Customer c WHERE c.lastName = ?)";
使用 jpql 自带的函数
String jpql = "SELECT lower(c.email) FROM Customer c";


------------
可以使用 JPQL 完成 UPDATE 和 DELETE 操作
String jpql = "UPDATE Customer c SET c.lastName = ? WHERE c.id = ?";
0 0