(4)Hibernate中的many-to-one和one-to-many关系

今天小节了一下:

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值