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 代码的“分离实体传递给持久错误”