hibernate查询&二级缓存


想要高薪就业?必须自己多写多练,多思考,多总结,有事微 我:LesterLan,我是强哥 Hibernate查询&二级缓存(day4) Hibernate 课程安排 一. 配置查询对象的模型;(掌握) 二. hql;(掌握) 三. 标准化对象查询(Criteria Query);(了解) 四. 原生SQL查询;(了解) 五. 分页查询;(掌握) 六. Fetch join;(了解) 七. 二级缓存;(精华,掌握) 八. 作业;(掌握) 一. 配置查询对象的模型(掌握) Java对象 1. CREATE TABLE `department` ( 2. `id` bigint(20) NOT NULL AUTO_INCREMENT, 3. `name` varchar(255) DEFAULT NULL, 4. `provice` varchar(255) DEFAULT NULL, 5. `city` varchar(255) DEFAULT NULL, 6. `street` varchar(255) DEFAULT NULL, 7. `manager_id` bigint(20) DEFAULT NULL, 8. `sn` varchar(4) DEFAULT NULL, 9. PRIMARY KEY (`id`), 10. KEY `FKA9601F7262086B81` (`manager_id`), 11. CONSTRAINT `FKA9601F7262086B81` FOREIGN KEY (`manager_id`) REFERENCES `employee` (`id`) 12. ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 13. 14. public class Department { 15. private Long id; 16. private String name; 17. private String provice; 18. private String city; 19. private String street; 20. private String sn; 21. // 外键`manager_id` bigint(20) DEFAULT NULL, 22. // 多对一,多个部门由一个部门经理管理 23. private Employee manager; 24. // 双向一对多:当前部门有那些员工 25. private Set employees = new HashSet(); 26. } 27. 28. CREATE TABLE `employee` ( 29. `id` bigint(20) NOT NULL AUTO_INCREMENT, 30. `name` varchar(255) DEFAULT NULL, 31. `department_id` bigint(20) DEFAULT NULL, 32. `salary` decimal(8,2) DEFAULT NULL, 33. `hireDate` date DEFAULT NULL, 34. PRIMARY KEY (`id`), 35. KEY `FK4AFD4ACE3DA4510D` (`department_id`), 36. CONSTRAINT `FK4AFD4ACE3DA4510D` FOREIGN KEY (`department_id`) REFERENCES `department` (`id`) 37. ) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8; 38. 39. public class Employee { 40. private Long id; 41. private String name; 42. private BigDecimal salary; 43. private Date hireDate; 44. // 外键`department_id` bigint(20) DEFAULT NULL, 45. // 多对一:多个员工属于同一个部门 46. private Department department; 47. } 48. 49. CREATE TABLE `phone` ( 50. `id` bigint(20) NOT NULL AUTO_INCREMENT, 51. `types` varchar(255) DEFAULT NULL, 52. `number` varchar(255) DEFAULT NULL, 53. `employee_id` bigint(20) DEFAULT NULL, 54. PRIMARY KEY (`id`), 55. KEY `FK4984D4E3CBA8E0` (`employee_id`), 56. CONSTRAINT `FK4984D4E3CBA8E0` FOREIGN KEY (`employee_id`) REFERENCES `employee` (`id`) 57. ) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8; 58. 59. public class Phone { 60. private Long id; 61. private String types; 62. private String number; 63. // 外键`employee_id` bigint(20) DEFAULT NULL, 64. // 多对一:多个电话属于同一个员工 65. private Employee employee; 66. } 67. 68. CREATE TABLE `project` ( 69. `id` bigint(20) NOT NULL AUTO_INCREMENT, 70. `name` varchar(255) DEFAULT NULL, 71. `manager_id` bigint(20) DEFAULT NULL, 72. PRIMARY KEY (`id`), 73. KEY `FK50C8E2F962086B81` (`manager_id`), 74. CONSTRAINT `FK50C8E2F962086B81` FOREIGN KEY (`manager_id`) REFERENCES `employee` (`id`) 75. ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8; 76. 77. public class Project { 78. private Long id; 79. private String name; 80. // 外键`manager_id` bigint(20) DEFAULT NULL, 81. // 多对一,多个项目由同一个项目经理管理 82. private Employee manager; 83. // 多对多 84. private Set employees = new HashSet(); 85. } 配置文件hibernate.cfg.xml 1. 映射文件domain.hbm.xml 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 二. hql (掌握) 最基本的HQL的格式:java的类名和属性名 SELECT o[o.property,o.property*] FROM Entity o [WHERE conditions] ORDER BY o.property[ASC|DESC] HQL本质是Hibernate通过antlr-2.7.6.jar翻译成sql并且封装执行. 基本查询 1. 1.里面写的都是java的类名或者属性名或者别名.对象属性.属性 2. 3. 2.SELECT o[o.property,o.property*] FROM Entity o [WHERE conditions] ORD ER BY o.property[ASC|DESC] 4. 5. 3.HQL本质是Hibernate通过antlr-2.7.6.jar翻译成sql并且封装执行. 6. 7. 4.不用出现多余的空格,也不用少 8. 9. 5.select o.name,o.department.name from Employee o:会由Hibernate处理2个表 之间外键关联:department_id 10. select o.name,d.name from Employee o,Department d where d=o.department :条件写的是对象的等于,最终会变成外键的关联等于 11. 12. 6.返回值 13. List=select o.name,o.department.name from Employee o 14. List=select o.name from Employee o 15. List=select new Employee(o.name,o.salary) from Employee o必须 要有对应的构造方法 16. 17. public Employee() { 18. } 19. 20. public Employee(String name, String deptName) { 21. this.name = name; 22. this.department = new Department(); 23. this.department.setName(deptName); 24. } 25. 26. 7.占位符? 27. select o from Employee o where o.department.city=? or o.department.cit y=? 28. query.setString(0, "成都").setString(1, "广州"); 29. select o from Employee o where o.department.street in (?,?) 30. query.setString(0, "八宝街").setString(1, "恩宁路"); 31. 32. 8.命名参数:最终还是会变成占位符? 33. select o from Employee o where o.department.street in:streets 34. query.setParameterList("streets", new String[] { "八宝街", "恩宁路" }); 其他查询 1. distinct去重 2. 3. size在sql是不存在的,size最后由Hibernate翻译成count(id) 4. select o from Department o where o.employees.size>? 5. select o from Project o where o.employees.size=? 6. 7. sql:select a.*,b.* from A a join B b on a.b_id=b.id 8. hql:select a,b from A a join a.b b 9. 10. 1.不用写on字句 11. 2.join后面的对象必须通过前面对象别名.出来 12. 13. 查询出各个项目参与人数报表:sql是不同 14. hql = "select p.name,p.employees.size from Project p"; 15. hql = "select p.name,p.employees.size from Project p group by p.name"; 16. hql = "select p.name,count(e) from Project p join p.employees e group by p.name"; 17. 18. 查询出各个项目参与人数(>3)报表 19. select p.name,count(e) from Project p join p.employees e group by p.na me having count(e)>3 20. 21. 查询出没有留移动电话的员工【使用in,EXISTS】 22. sql in:select * from employee where id not in(select employee_id from phone where types='CELL'); 23. sql exists:select e.* from Employee e where not exists(select p.id from Phone p where e.id=p.employee_id and p.types='CELL'); 24. 如果子查询的p.id有返回值,exists返回就是true,如果=true,主查询就返回结果 25. hql EXISTS: 26. 1.where后面没有条件 27. 2.子查询里面的对象是通过外面对象.出来e.phones p或者使用关联查询:p.employee.id=o .id 28. 3.子查询里面的返回值不能使用多行函数count,最好使用主键p.id 三. 标准化对象查询(Criteria Query)(了解) 以对象的方式进行查询,将查询语句封装为对象操作。 优点:可读性好,符合Java 程序员的编码习惯。 缺点:不够成熟,不支持投影(projection)或统计函数(aggregation) Criteria criteria = session.createCriteria(Employee.class); // 按照名称模糊查询 criteria.add(Restrictions.like("name", "en",MatchMode.ANYWHERE)); // 按照薪资降序 criteria.addOrder(Order.desc("salary")); 四. 原生SQL查询(了解) String sql = "select * from employee where name like ?"; SQLQuery sqlQuery = session.createSQLQuery(sql); //把*->Employee sqlQuery.addEntity(Employee.class).setString(0, "%a%"); List list = sqlQuery.list(); //或者自己写个模型类型,专门用来装返回的结果(一般少用,麻烦) String sql = "select name,salary from employee where name like ?"; SQLQuery sqlQuery = session.createSQLQuery(sql); sqlQuery.setString(0, "%a%"); List list = sqlQuery.list(); 五. 分页查询 (掌握) 1. 2. org.hibernate.dialect.MySQLDialect 3. 4. //从哪里开始取数据,索引从0开始 5. int firstResult = (cureentPage - 1) * pageSize; 6. //取多少条 7. int maxResults = pageSize; 8. query.setFirstResult(firstResult).setMaxResults(maxResults); 9. 10. //从Hibernate3.2开始都是Long 11. select count(o) from Employee o 12. Long countLong = (Long) query.uniqueResult(); org.hibernate.dialect.MySQLDialect核心代码 1. @Override 2. public String getLimitString(String sql, boolean hasOffset) { 3. return sql + (hasOffset ? " limit ?, ?" : " limit ?"); 4. } org.hibernate.dialect.Oracle10gDialect核心代码 1. @Override 2. public String getLimitString(String sql, boolean hasOffset) { 3. sql = sql.trim(); 4. String forUpdateClause = null; 5. boolean isForUpdate = false; 6. final int forUpdateIndex = sql.toLowerCase().lastIndexOf( "for upda te") ; 7. if ( forUpdateIndex > -1 ) { 8. // save 'for update ...' and then remove it 9. forUpdateClause = sql.substring( forUpdateIndex ); 10. sql = sql.substring( 0, forUpdateIndex-1 ); 11. isForUpdate = true; 12. } 13. 14. final StringBuilder pagingSelect = new StringBuilder( sql.length() + 100 ); 15. if (hasOffset) { 16. pagingSelect.append( "select * from ( select row_.*, rownum rownum_ from ( " ); 17. } 18. else { 19. pagingSelect.append( "select * from ( " ); 20. } 21. pagingSelect.append( sql ); 22. if (hasOffset) { 23. pagingSelect.append( " ) row_ where rownum <= ?) where rownum_ > ?" ); 24. } 25. else { 26. pagingSelect.append( " ) where rownum <= ?" ); 27. } 28. 29. if ( isForUpdate ) { 30. pagingSelect.append( " " ); 31. pagingSelect.append( forUpdateClause ); 32. } 33. 34. return pagingSelect.toString(); 35. } 六. Fetch join (了解) 1. // 查询出员工,部门的数据,有延迟加载:1(员工)+4(部门,一级缓存命中)条sql 2. @Test 3. public void test9() throws Exception { 4. Session session = HibernateUtils.getSession(); 5. String hql = "select o from Employee o"; 6. Query query = session.createQuery(hql); 7. List list = query.list(); 8. for (Employee employee : list) { 9. System.out.println(employee + "," + employee.getDepartment()); 10. } 11. System.out.println("size:" + list.size()); 12. session.close(); 13. } 14. 15. // 查询出员工,部门的数据(只能用一条sql),没有延迟加载 16. @Test 17. public void test10() throws Exception { 18. Session session = HibernateUtils.getSession(); 19. String hql = "select o,o.department from Employee o"; 20. Query query = session.createQuery(hql); 21. List list = query.list(); 22. for (Object[] objects : list) { 23. System.out.println(Arrays.toString(objects)); 24. } 25. System.out.println("size:" + list.size()); 26. session.close(); 27. } 28. 29. // Fetch join 30. // 查询出员工,部门的数据(用一条sql,不管是否需要部门都会自动查询出来,自动封装成do main对象),没有延迟加载 31. @Test 32. public void test11() throws Exception { 33. Session session = HibernateUtils.getSession(); 34. String hql = "select o from Employee o join fetch o.department"; 35. Query query = session.createQuery(hql); 36. List list = query.list(); 37. for (Employee employee : list) { 38. System.out.println(employee + "," + employee.getDepartment()); 39. } 40. System.out.println("size:" + list.size()); 41. session.close(); 42. } 七. 二级缓存 (精华,掌握) 添加二级缓存jar文件 hibernate-release-4.3.8.Final\lib\optional\ehcache\3个jar文件 Hibernate.cfg.xml hibernate-release-4.3.8.Final\project\etc\hibernate.properties Second-level Cache 1. #开启二级缓存 2. hibernate.cache.use_second_level_cache=true 3. #添加一个二级缓存的供应商(实现类) 4. hibernate4的配置 5. #org.hibernate.cache.internal.EhCacheRegionFactory文档里面是错误的 6. hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCach eRegionFactory 7. hibernate3的配置 8. hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider 9. #开启查询缓存 10. hibernate.cache.use_query_cache=true 类的二级缓存 在hibernate.cfg.xml配置那个domain需要二级缓存 1. 2. 3. 4. 5. // 一级缓存命中条件:同一个session,OID相同 6. // 一条sql 7. @Test 8. public void test1() throws Exception { 9. Session session = HibernateUtils.getSession(); 10. // 放入一级缓存 11. session.get(Employee.class, 1L);// 没有命中 12. session.get(Employee.class, 1L);// 一级缓存命中 13. session.close(); 14. } 15. 16. // 二级缓存类配置:命中条件:同一个SessionFactory,不同的session,OID相同 17. // 一条sql 18. // 20. @Test 21. public void test2() throws Exception { 22. Session session = HibernateUtils.getSession(); 23. // 放入一级缓存,二级缓存 24. session.get(Department.class, 1L);// 没有命中 25. session.get(Department.class, 1L);// 一级缓存命中 26. session.close(); 27. 28. Session session2 = HibernateUtils.getSession(); 29. session2.get(Department.class, 1L);// 二级缓存命中 30. session2.get(Department.class, 1L);// 一级缓存命中 31. session2.close(); 32. } 类里面集合的二级缓存 1. 2. 3. 4. // 二级缓存类的集合配置(必须配置集合类的二级缓存):命中条件:同一个 SessionFactory,OID相同 5. // 2条sql 6. // 8. // 10. @Test 11. public void test3() throws Exception { 12. Long deptId = 1L; 13. 14. Session session = HibernateUtils.getSession(); 15. // 放入一级缓存,二级缓存 16. Department department = (Department) session.get(Department.class, deptId);// 没有命中 17. // 放入类的集合二级缓存(本质还是OID),但是后面查询如果要命中必须通过OID 18. System.out.println(department.getEmployees().size());// 集合查询 19. session.close(); 20. 21. Session session2 = HibernateUtils.getSession(); 22. Department department2 = (Department) session2.get(Department.class, deptId);// 二级缓存命中 23. System.out.println(department2.getEmployees().size());// 集合查询 24. session2.close(); 25. } 查询缓存 1. #开启查询缓存 2. hibernate.cache.use_query_cache=true 3. 4. // 查询缓存:依赖于二级缓存 5. // 一条sql 6. // 命中条件:同一个SessionFactory,发出的sql语句必须相同并且查询的条件也要相同 7. // 如果有查询条件,就不能使用查询缓存,命中率非常低 8. // 查询缓存里面查询指的是hql,sql,面向对象查询 9. @Test 10. public void test4() throws Exception { 11. Session session = HibernateUtils.getSession(); 12. // 发出查询,放入一级缓存,二级缓存 13. String hql = "select o from Employee o where id>?"; 14. Query query = session.createQuery(hql).setLong(0, 0L); 15. // 放入查询缓存 16. query.setCacheable(true); 17. System.out.println("size:" + query.list().size()); 18. session.get(Employee.class, 1L);// 一级缓存命中 19. session.close(); 20. 21. Session session2 = HibernateUtils.getSession(); 22. // 发出查询,放入一级缓存,二级缓存 23. String hql2 = "select o from Employee o where id>?"; 24. Query query2 = session2.createQuery(hql2).setLong(0, 0L); 25. // 使用查询缓存 26. query2.setCacheable(true); 27. System.out.println("size:" + query2.list().size()); 28. session2.get(Employee.class, 1L);// 一级缓存命中 29. session2.close(); 30. } 面试题:什么场景使用二级缓存 读取大于修改; 对数据要有独享控制,数据不会被第三方修改; 可以容忍出现无效数据,非关键数据(不是财务数据等); 数据量不能超过内存容量,数据量特别巨大,此时不适合于二级缓存 ehcache.xml 默认这个缓存配置文件,使用默认配置文件 hibernate-release-4.3.8.Final\project\etc\ehcache.xml 关键配置:如果内存里面的缓存对象超过10000个,钝化到硬盘 默认所有类的二级缓存,类的集合的二级缓存,查询缓存都是使用默认配置 如果希望单独使用缓存配置 ehcache.xml文件里面属性含义 timeToIdleSeconds="300"秒 timeToLiveSeconds="600" 秒overflowToDisk="true" /> name:Cache的唯一标识 maxElementsInMemory:内存中最大缓存对象数 eternal:Element是否永久有效,一但设置了,timeout将不起作用。 timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久 有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大 timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和 失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间 无穷大。 maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大。 overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory 时,Ehcache将会Element写到磁盘中。 二级缓存缓存策略 操作二级缓存(了解) 二级缓存分析 Session的save方法、update、saveOrUpdate、list、iterator、get、load等方法以及 Query、Criteria都会填充二级缓存。 默认情况下,只有几个查询方法会从二级缓存中读取数据;iterator(n+1问题)、get、 load。 Query、Criteria(查询缓存)由于命中率低,默认是关闭的;要打开查询缓存,需要配置 参数 true 在Query中使用setCacheable来指定缓存指定查询条件; 面试题:iterator(n+1问题) 17+1条sql 1=select id from employee N=员工的条数 全部按照oid查询 如果没有oid的缓存.性能非常低,一般都是不用 缓存命中条件 一级缓存同一个session,OID相同 二级缓存类配置:同一个SessionFactory,OID相同 二级缓存类的集合配置(必须配置集合类的二级缓存):命中条件:同一个 SessionFactory,OID相同 查询缓存:同一个SessionFactory,发出的sql语句必须相同并且查询的条件也要相同 如果有查询条件,就不能使用查询缓存,命中率非常低 八. 作业(掌握) 创建一个hibernate-permission(权限)工程 创建3个domain模型(User,Role,Permission), 生成5张表,其中2个是中间表 映射配置3个class,都是单向多对多  1.测试生成5张表  2.插入模拟数据,5个session.save(xxx),这里不使用级联保存;  3.写一句hql:关联查询,出现2个join 条件是user的id=1,查询对应的拥有2个Permission 条件是user的id=2,查询对应的拥有1个Permission
还剩16页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 0 人已下载

下载pdf

pdf贡献者

tanlin

贡献于2016-11-16

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf