今天小节了一下:
1 Hibernate 中查询.
2 inverse 和 cascade的对比.
3 二级缓存和查询缓存的使用。
hibernate.cfg.xml 如下:
<!-- 指定使用 Echache做缓存提供者 --> <property name="hibernate.cache.provider_class"> org.hibernate.cache.EhCacheProvider </property> <!-- 使用查询缓存(查询缓存在二级缓存的基础上使用) --> <property name="hibernate.cache.use_query_cache">true</property>
ehcache.xml(用于二级缓存)如下:
<ehcache> <!-- 内存中存不下时存放在硬盘的位置 --> <diskStore path="F:\\temp" /> <defaultCache maxElementsInMemory="2000" eternal="false" timeToIdleSeconds="1000" timeToLiveSeconds="1000" overflowToDisk="true"> </defaultCache> <cache name="com.isw2.bo.TelBO" maxElementsInMemory="500" eternal="false" timeToIdleSeconds="1000" timeToLiveSeconds="1000" overflowToDisk="true" /> <cache name="com.isw2.bo.UserBO" maxElementsInMemory="500" eternal="false" timeToIdleSeconds="1000" timeToLiveSeconds="1000" overflowToDisk="true" /> <cache name="com.isw2.bo.UserBO.telBOs" maxElementsInMemory="500" eternal="false" timeToIdleSeconds="1000" timeToLiveSeconds="1000" overflowToDisk="true" /> <cache name="org.hibernate.cache.StandardQueryCache" maxElementsInMemory="100" eternal="true" overflowToDisk="true"> </cache> <cache name="org.hibernate.cache.UpdateTimestampsCache" maxElementsInMemory="100" eternal="true" overflowToDisk="true"> </cache> </ehcache>
TelBO.hbm.xml 如下:
<class name="com.isw2.bo.TelBO" table="t_tel" catalog="many_to_one" lazy="true"> <!-- 读写策略 --> <cache usage="read-write" /> <id name="telId" column="telId"> <generator class="native"></generator> </id> <property name="telNumber" column="telNumber" length="32" type="string"> </property> <many-to-one name="userBO" fetch="select" column="userId" lazy="proxy"> </many-to-one> </class>
UserBO.hbm.xml如下:
<class name="com.isw2.bo.UserBO" table="t_user" catalog="many_to_one" lazy="true"> <!-- 使用二级缓存 --> <cache usage="read-write" /> <id name="userId" column="userId"> <generator class="native"></generator> </id> <property name="userName" column="userName" length="32" type="string"> </property> <set name="telBOs" fetch="select" cascade="all" lazy="true" inverse="true"> <!-- 使用二级缓存 --> <cache usage="read-write" /> <key column="userId"></key> <one-to-many class="com.isw2.bo.TelBO" /> </set> </class>
/** * 关于 inverse="true" */ public void update() { Session session = HibernateSessionFactory.getSession(); Transaction tr = session.beginTransaction(); Query query = session.createQuery("from UserBO ub where ub.userId = 7"); UserBO userBO = (UserBO) query.uniqueResult(); TelBO telBO = new TelBO("9058492", userBO); userBO.getTelBOs().add(telBO); session.update(userBO); tr.commit(); session.close(); /** * 在one-to-many 中 设置 inverse="true" 表示由many方维护数据间的关系. 注意: 区别于 cascade * 表示需要哪些维护数据间的关系(all:所有情况下均进行关联操作; * none:所有情况下均不进行关联操作,这是默认值;save-update:在执行save/update/saveOrUpdate时进行关联操作; * delete:在执行delete时进行关联操作。 ) * * 对下面的操作分析可知,当由one方维护时数据先存入数据库,然后根据 one 执行更新操作; * 由many 方维护时,数据先查询,然后根据查询结果存入数据库 */ /** * inverse="true" 时操作如下: * Hibernate: select userbo0_.userId as userId1_, * userbo0_.userName as userName1_ from many_to_one.t_user userbo0_ * where userbo0_.userId=7 * * Hibernate: select telbos0_.userId as * userId1_, telbos0_.telId as telId1_, telbos0_.telId as telId0_0_, * telbos0_.telNumber as telNumber0_0_, telbos0_.userId as userId0_0_ * from many_to_one.t_tel telbos0_ where telbos0_.userId=? * * Hibernate: * insert into many_to_one.t_tel (telNumber, userId) values (?, ?) * * * * inverse="false" 时操作如下: * * Hibernate: select userbo0_.userId as userId1_, * userbo0_.userName as userName1_ from many_to_one.t_user userbo0_ * where userbo0_.userId=7 * * Hibernate: select telbos0_.userId as * userId1_, telbos0_.telId as telId1_, telbos0_.telId as telId0_0_, * telbos0_.telNumber as telNumber0_0_, telbos0_.userId as userId0_0_ * from many_to_one.t_tel telbos0_ where telbos0_.userId=? * * Hibernate:insert into many_to_one.t_tel (telNumber, userId) values (?, ?) * Hibernate: update many_to_one.t_tel set userId=? where telId=? */ } /** * 根据Bean 查询对象 */ public void findByEntity() { Session session = HibernateSessionFactory.getSession(); UserBO userBO = (UserBO) session.load(UserBO.class, new Long(7)); /** * Query query = session.createQuery("from TelBO tb where tb.userBO = * ?"); query.setParameter(0, userBO); TelBO telBO = new TelBO(); * telBO.setTelNumber("591201270"); */ // 这里把UserBO 当作Bean 来使用,userBO.getUserId 在这里可以提供参数注意:userId Query query = session.createQuery("from TelBO tb " + "where tb.telId =:userId"); query.setProperties(userBO); System.out.println(query.setMaxResults(1).uniqueResult()); session.close(); } /** * 根据 Alias 联合查询(distinct 无法解决) */ public void findByJoinAlias() { Session session = HibernateSessionFactory.getSession(); Criteria cr = session.createCriteria(UserBO.class); cr.createAlias("telBOs", "tb");// 别名的使用 cr.add(Restrictions.like("tb.telNumber", "%")); // //这样查询结果仅有userName 一个字段 // cr.setProjection(Projections.distinct(Projections.property("userName"))); // //这只是在结果集中做了处理分页时无法使用 // cr.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY); List list = cr.list(); for (Object object : list) { System.out.println(object); } session.close(); } /** * 通过HQL 联合查询 */ public void findByJoinHQL() { Session session = HibernateSessionFactory.getSession(); // fetch 查询和 非fetch 查询, SQL语句相同,不同的是前者以 对象形式 返回,后者以数组形式返回 // Query query = session.createQuery("from UserBO ub inner join // ub.telBOs"); // Query query = session // .createQuery("from UserBO ub inner join fetch ub.telBOs"); Query query = session .createQuery("select distinct ub from UserBO ub inner join fetch ub.telBOs"); List list = query.list(); for (Object object : list) { System.out.println(object); } session.close(); } /** * 使用二级缓存(批量更新数据时为提高效率通过session.setCacheMode设置缓存模式) */ public void testCache() { System.out.println("开始查询....."); Session session = HibernateSessionFactory.getSession(); Query query = session.createQuery("from UserBO"); List list = query.list(); for (Object object : list) { System.out.println(object); } session.close(); System.out.println("使用二级缓存......"); /** * 查询SQL: Hibernate: select userbo0_.userId as col_0_0_ from * many_to_one.t_user userbo0_ * * 这里先查询Id 然后在缓存中根据id查找. 这里要注意,使用的是query.iterate. * 因为它会先查询Id,再根据Id查询对象,如二级缓存中有则直接取,否则就去数据库查询. * 之前一次查询后数据已放入二级缓存,第二次就没有查询数据库. * * 集合的缓存中存放的是Id,然后根据Id 查询二级缓存 * * 如果用query.list 则要使用查询缓存. */ session = HibernateSessionFactory.getSession(); query = session.createQuery("from UserBO"); Iterator<Object> iterator = query.iterate(); for (; iterator.hasNext();) { Object object = iterator.next(); System.out.println(object); } session.close(); } /** * 使用查询缓存 */ public void testSearchCache() { System.out.println("开始查询....."); Session session = HibernateSessionFactory.getSession(); Query query = session.createQuery("from UserBO"); // 设置使用查询缓存(查询缓存默认不使用,这里要显示启动) query.setCacheable(true); // 设置缓存区域 query.setCacheRegion("com.isw2.bo.UserBO"); // ------------------------------------ List list = query.list(); for (Object object : list) { System.out.println(object); } session.close(); System.out.println("使用查询缓存......"); session = HibernateSessionFactory.getSession(); query = session.createQuery("from UserBO"); // 设置使用查询缓存(两次使用同样的缓存区域) query.setCacheable(true); query.setCacheRegion("com.isw2.bo.UserBO"); // ------------------------------------ list = query.list(); for (Object object : list) { System.out.println(object); } /** * 在这里查询缓存类似于集合缓存。通过查询语句和 Id 集的方式存放查询结果,然后在二级缓存中查询结果 */ }
这里以又向关联为主。二级缓存因为命中率不高使用的不多,自己也不是很熟。
参考:
http://www.iteye.com/topic/18904
http://rujingzhang.iteye.com/blog/219487
http://www.blogjava.net/i369/articles/219408.html