jpa

Posted hykd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jpa相关的知识,希望对你有一定的参考价值。

学习尚硅谷jpa笔记:

 

所依赖的jar包:

首先在META-INF下创建配置文件,persistence.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <persistence version="2.0"
 3     xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
 5     <persistence-unit name="jpa-1" transaction-type="RESOURCE_LOCAL">
 6         <!-- 
 7         配置使用什么 ORM 产品来作为 JPA 的实现 
 8         1. 实际上配置的是  javax.persistence.spi.PersistenceProvider 接口的实现类
 9         2. 若 JPA 项目中只有一个 JPA 的实现产品, 则也可以不配置该节点. 
10         -->
11         <provider>org.hibernate.ejb.HibernatePersistence</provider>
12     
13         <!-- 添加持久化类 -->
14         <class>com.atguigu.jpa.helloworld.Customer</class>
15         <class>com.atguigu.jpa.helloworld.Order</class>
16     
17         <class>com.atguigu.jpa.helloworld.Department</class>
18         <class>com.atguigu.jpa.helloworld.Manager</class>
19     
20         <class>com.atguigu.jpa.helloworld.Item</class>
21         <class>com.atguigu.jpa.helloworld.Category</class>
22         
23         <!-- 
24         配置二级缓存的策略 
25         ALL:所有的实体类都被缓存
26         NONE:所有的实体类都不被缓存. 
27         ENABLE_SELECTIVE:标识 @Cacheable(true) 注解的实体类将被缓存
28         DISABLE_SELECTIVE:缓存除标识 @Cacheable(false) 以外的所有实体类
29         UNSPECIFIED:默认值,JPA 产品默认值将被使用
30         -->
31         <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
32     
33         <properties>
34             <!-- 连接数据库的基本信息 -->
35             <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
36             <property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa"/>
37             <property name="javax.persistence.jdbc.user" value="root"/>
38             <property name="javax.persistence.jdbc.password" value="1230"/>
39             
40             <!-- 配置 JPA 实现产品的基本属性. 配置 hibernate 的基本属性 -->
41             <property name="hibernate.format_sql" value="true"/>
42             <property name="hibernate.show_sql" value="true"/>
43             <property name="hibernate.hbm2ddl.auto" value="update"/>
44             
45             <!-- 二级缓存相关 -->
46             <property name="hibernate.cache.use_second_level_cache" value="true"/>
47             <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
48             <property name="hibernate.cache.use_query_cache" value="true"/>
49         </properties>
50     </persistence-unit>
51 </persistence>

下面是使用jpa的基本流程:

 1 //1. 创建 EntitymanagerFactory
 2         String persistenceUnitName = "jpa-1";
 3         
 4         Map<String, Object> properites = new HashMap<String, Object>();
 5         properites.put("hibernate.show_sql", true);
 6         
 7         EntityManagerFactory entityManagerFactory = 
 8                 //Persistence.createEntityManagerFactory(persistenceUnitName);
 9                 Persistence.createEntityManagerFactory(persistenceUnitName, properites);
10                 
11         //2. 创建 EntityManager. 类似于 Hibernate 的 SessionFactory
12         EntityManager entityManager = entityManagerFactory.createEntityManager();
13         
14         //3. 开启事务
15         EntityTransaction transaction = entityManager.getTransaction();
16         transaction.begin();
17         
18         //4. 进行持久化操作
19         Customer customer = new Customer();
20         customer.setAge(12);
21         customer.setEmail("tom@atguigu.com");
22         customer.setLastName("Tom");
23         customer.setBirth(new Date());
24         customer.setCreatedTime(new Date());
25         
26         entityManager.persist(customer);
27         
28         //5. 提交事务
29         transaction.commit();
30         
31         //6. 关闭 EntityManager
32         entityManager.close();
33         
34         //7. 关闭 EntityManagerFactory
35         entityManagerFactory.close();

各种情况下的测试:

  1 package com.atguigu.jpa.test;
  2 
  3 import java.util.Date;
  4 import java.util.List;
  5 
  6 import javax.persistence.EntityManager;
  7 import javax.persistence.EntityManagerFactory;
  8 import javax.persistence.EntityTransaction;
  9 import javax.persistence.Persistence;
 10 import javax.persistence.Query;
 11 
 12 import org.hibernate.ejb.QueryHints;
 13 import org.junit.After;
 14 import org.junit.Before;
 15 import org.junit.Test;
 16 
 17 import com.atguigu.jpa.helloworld.Category;
 18 import com.atguigu.jpa.helloworld.Customer;
 19 import com.atguigu.jpa.helloworld.Department;
 20 import com.atguigu.jpa.helloworld.Item;
 21 import com.atguigu.jpa.helloworld.Manager;
 22 import com.atguigu.jpa.helloworld.Order;
 23 
 24 public class JPATest {
 25 
 26     private EntityManagerFactory entityManagerFactory;
 27     private EntityManager entityManager;
 28     private EntityTransaction transaction;
 29     
 30     @Before
 31     public void init(){
 32         entityManagerFactory = Persistence.createEntityManagerFactory("jpa-1");
 33         entityManager = entityManagerFactory.createEntityManager();
 34         transaction = entityManager.getTransaction();
 35         transaction.begin();
 36     }
 37     
 38     @After
 39     public void destroy(){
 40         transaction.commit();
 41         entityManager.close();
 42         entityManagerFactory.close();
 43     }
 44     
 45     //可以使用 JPQL 完成 UPDATE 和 DELETE 操作. 
 46     @Test
 47     public void testExecuteUpdate(){
 48         String jpql = "UPDATE Customer c SET c.lastName = ? WHERE c.id = ?";
 49         Query query = entityManager.createQuery(jpql).setParameter(1, "YYY").setParameter(2, 12);
 50         
 51         query.executeUpdate();
 52     }
 53 
 54     //使用 jpql 内建的函数
 55     @Test
 56     public void testJpqlFunction(){
 57         String jpql = "SELECT lower(c.email) FROM Customer c";
 58         
 59         List<String> emails = entityManager.createQuery(jpql).getResultList();
 60         System.out.println(emails);
 61     }
 62     
 63     @Test
 64     public void testSubQuery(){
 65         //查询所有 Customer 的 lastName 为 YY 的 Order
 66         String jpql = "SELECT o FROM Order o "
 67                 + "WHERE o.customer = (SELECT c FROM Customer c WHERE c.lastName = ?)";
 68         
 69         Query query = entityManager.createQuery(jpql).setParameter(1, "YY");
 70         List<Order> orders = query.getResultList();
 71         System.out.println(orders.size());
 72     }
 73     
 74     /**
 75      * JPQL 的关联查询同 HQL 的关联查询. 
 76      */
 77     @Test
 78     public void testLeftOuterJoinFetch(){
 79         String jpql = "FROM Customer c LEFT OUTER JOIN FETCH c.orders WHERE c.id = ?";
 80         
 81         Customer customer = 
 82                 (Customer) entityManager.createQuery(jpql).setParameter(1, 12).getSingleResult();
 83         System.out.println(customer.getLastName());
 84         System.out.println(customer.getOrders().size());
 85         
 86 //        List<Object[]> result = entityManager.createQuery(jpql).setParameter(1, 12).getResultList();
 87 //        System.out.println(result);
 88     }
 89     
 90     //查询 order 数量大于 2 的那些 Customer
 91     @Test
 92     public void testGroupBy(){
 93         String jpql = "SELECT o.customer FROM Order o "
 94                 + "GROUP BY o.customer "
 95                 + "HAVING count(o.id) >= 2";
 96         List<Customer> customers = entityManager.createQuery(jpql).getResultList();
 97         
 98         System.out.println(customers);
 99     }
100     
101     @Test
102     public void testOrderBy(){
103         String jpql = "FROM Customer c WHERE c.age > ? ORDER BY c.age DESC";
104         Query query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);
105         
106         //占位符的索引是从 1 开始
107         query.setParameter(1, 1);
108         List<Customer> customers = query.getResultList();
109         System.out.println(customers.size());
110     }
111     
112     //使用 hibernate 的查询缓存. 
113     @Test
114     public void testQueryCache(){
115         String jpql = "FROM Customer c WHERE c.age > ?";
116         Query query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);
117         
118         //占位符的索引是从 1 开始
119         query.setParameter(1, 1);
120         List<Customer> customers = query.getResultList();
121         System.out.println(customers.size());
122         
123         query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);
124         
125         //占位符的索引是从 1 开始
126         query.setParameter(1, 1);
127         customers = query.getResultList();
128         System.out.println(customers.size());
129     }
130     
131     //createNativeQuery 适用于本地 SQL
132     @Test
133     public void testNativeQuery(){
134         String sql = "SELECT age FROM jpa_cutomers WHERE id = ?";
135         Query query = entityManager.createNativeQuery(sql).setParameter(1, 3);
136         
137         Object result = query.getSingleResult();
138         System.out.println(result);
139     }
140     
141     //createNamedQuery 适用于在实体类前使用 @NamedQuery 标记的查询语句
142     @Test
143     public void testNamedQuery(){
144         Query query = entityManager.createNamedQuery("testNamedQuery").setParameter(1, 3);
145         Customer customer = (Customer) query.getSingleResult();
146         
147         System.out.println(customer);
148     }
149     
150     //默认情况下, 若只查询部分属性, 则将返回 Object[] 类型的结果. 或者 Object[] 类型的 List.
151     //也可以在实体类中创建对应的构造器, 然后再 JPQL 语句中利用对应的构造器返回实体类的对象.
152     @Test
153     public void testPartlyProperties(){
154         String jpql = "SELECT new Customer(c.lastName, c.age) FROM Customer c WHERE c.id > ?";
155         List result = entityManager.createQuery(jpql).setParameter(1, 1).getResultList();
156         
157         System.out.println(result);
158     }
159     
160     @Test
161     public void testHelloJPQL(){
162         String jpql = "FROM Customer c WHERE c.age > ?";
163         Query query = entityManager.createQuery(jpql);
164         
165         //占位符的索引是从 1 开始
166         query.setParameter(1, 1);
167         List<Customer> customers = query.getResultList();
168         System.out.println(customers.size());
169     }
170     
171     @Test
172     public void testSecondLevelCache(){
173         Customer customer1 = entityManager.find(Customer.class, 1);
174         
175         transaction.commit();
176         entityManager.close();
177         
178         entityManager = entityManagerFactory.createEntityManager();
179         transaction = entityManager.getTransaction();
180         transaction.begin();
181         
182         Customer customer2 = entityManager.find(Customer.class, 1);
183     }
184     
185     //对于关联的集合对象, 默认使用懒加载的策略.
186     //使用维护关联关系的一方获取, 还是使用不维护关联关系的一方获取, SQL 语句相同. 
187     @Test
188     public void testManyToManyFind(){
189 //        Item item = entityManager.find(Item.class, 5);
190 //        System.out.println(item.getItemName());
191 //        
192 //        System.out.println(item.getCategories().size());
193         
194         Category category = entityManager.find(Category.class, 3);
195         System.out.println(category.getCategoryName());
196         System.out.println(category.getItems().size());
197     }
198     
199     //多对所的保存
200     @Test
201     public void testManyToManyPersist(){
202         Item i1 = new Item();
203         i1.setItemName("i-1");
204     
205         Item i2 = new Item();
206         i2.setItemName("i-2");
207         
208         Category c1 = new Category();
209         c1.setCategoryName("C-1");
210         
211         Category c2 = new Category();
212         c2.setCategoryName("C-2");
213         
214         //设置关联关系
215         i1.getCategories().add(c1);
216         i1.getCategories().add(c2);
217         
218         i2.getCategories().add(c1);
219         i2.getCategories().add(c2);
220         
221         c1.getItems().add(i1);
222         c1.getItems().add(i2);
223         
224         c2.getItems().add(i1);
225         c2.getItems().add(i2);
226         
227         //执行保存
228         entityManager.persist(i1);
229         entityManager.persist(i2);
230         entityManager.persist(c1);
231         entityManager.persist(c2);
232     }
233     
234     //1. 默认情况下, 若获取不维护关联关系的一方, 则也会通过左外连接获取其关联的对象. 
235     //可以通过 @OneToOne 的 fetch 属性来修改加载策略. 但依然会再发送 SQL 语句来初始化其关联的对象
236     //这说明在不维护关联关系的一方, 不建议修改 fetch 属性. 
237     @Test
238     public void testOneToOneFind2(){
239         Manager mgr = entityManager.find(Manager.class, 1);
240         System.out.println(mgr.getMgrName());
241         
242         System.out.println(mgr.getDept().getClass().getName());
243     }
244     
245     //1.默认情况下, 若获取维护关联关系的一方, 则会通过左外连接获取其关联的对象. 
246     //但可以通过 @OntToOne 的 fetch 属性来修改加载策略.
247     @Test
248     public void testOneToOneFind(){
249         Department dept = entityManager.find(Department.class, 1);
250         System.out.println(dept.getDeptName());
251         System.out.println(dept.getMgr().getClass().getName());
252     }
253     
254     //双向 1-1 的关联关系, 建议先保存不维护关联关系的一方, 即没有外键的一方, 这样不会多出 UPDATE 语句.
255     @Test
256     public void testOneToOnePersistence(){
257         Manager mgr = new Manager();
258         mgr.setMgrName("M-BB");
259         
260         Department dept = new Department();
261         dept.setDeptName("D-BB");
262         
263         //设置关联关系
264         mgr.setDept(dept);
265         dept.setMgr(mgr);
266         
267         //执行保存操作
268         entityManager.persist(mgr);
269         entityManager.persist(dept);
270     }
271     
272     @Test
273     public void testUpdate(){
274         Customer customer = entityManager.find(Customer.class, 10);
275         
276         customer.getOrders().iterator().next().setOrderName("O-XXX-10");
277     }
278     
279     //默认情况下, 若删除 1 的一端, 则会先把关联的 n 的一端的外键置空, 然后进行删除. 
280     //可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略. 
281     @Test
282     public void testOneToManyRemove(){
283         Customer customer = entityManager.find(Customer.class, 8);
284         entityManager.remove(customer);
285     }
286     
287     //默认对关联的多的一方使用懒加载的加载策略. 
288     //可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略
289     @Test
290     public void testOneToManyFind(){
291         Customer customer = entityManager.find(Customer.class, 9);
292         System.out.println(customer.getLastName());
293         
294         System.out.println(customer.getOrders().size());
295     }
296     
297     //若是双向 1-n 的关联关系, 执行保存时
298     //若先保存 n 的一端, 再保存 1 的一端, 默认情况下, 会多出 n 条 UPDATE 语句.
299     //若先保存 1 的一端, 则会多出 n 条 UPDATE 语句
300     //在进行双向 1-n 关联关系时, 建议使用 n 的一方来维护关联关系, 而 1 的一方不维护关联系, 这样会有效的减少 SQL 语句. 
301     //注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 属性, 则 @OneToMany 端就不能再使用 @JoinColumn 属性了. 
302     
303     //单向 1-n 关联关系执行保存时, 一定会多出 UPDATE 语句.
304     //因为 n 的一端在插入时不会同时插入外键列. 
305     @Test
306     public void testOneToManyPersist(){
307         Customer customer = new Customer();
308         customer.setAge(18);
309         customer.setBirth(new Date());
310         customer.setCreatedTime(new Date());
311         customer.setEmail("mm@163.com");
312         customer.setLastName("MM");
313         
314         Order order1 = new Order();
315         order1.setOrderName("O-MM-1");
316         
317         Order order2 = new Order();
318         order2.setOrderName("O-MM-2");
319         
320         //建立关联关系
321 带有 JPA/EJB 代码的“分离实体传递给持久错误”

Glassfish - 无法使用 JPA 删除实体

从数据库为 JPA 实体生成自定义代码

JPA 之 QueryDSL-JPA 使用指南

您将如何使 JPA 2.1 模块独立于 JPA 实现?

在每个模型的不同 DAL 类中实现 JPA 存储库方法时如何避免重复的代码行/代码块