public class Subject extends Post
3.7自定义ID生成器
在Showcase中演示一个16位的UID生成。
3.8 关联关系大全
在mini-web中演示@ManyToMany.
在shwocase中演示,单向,双向的@OneToMany, @ManyToOne .
4. in SpringSide II --性能相关
Hibernate 其实做了很多性能相关的优化,大家可以尽量使用后,再决定要不要直接跑JDBC。
4.1 二级缓存
在Entity类及其Collection属性中都可以声明Hibernate缓存策略。Entity缓存对象实体,而Collection则缓存对象间 的关系。 注意并不是所有对象都适合缓存,需要进行精心选择,详见 Hibernate笔记。
这里使用了ehcache cache方案, 支持基于JGroups分布式二级缓存,在sessionFactory处配置了ehcache_hibernate.xml的配置文件。关于 Ehcache详见Ehcache部分。
QueryCache本身就是吃力不讨好的事情,在集群环境下更加需要注意,因此我们一般不推荐使用使用查询缓存.
4.2 不使用OpenSessionInFilter
对于性能要求较高的Web网站与WebService应用,还是应该在Service层用Hibernate.init()主动初始化对象然后关闭 Session。详见mini-service的演示。注意Hibernate.init(user)初始化user对象,而如果要同时初始化user与 user的Lob字段与关联对象,调用的是Hibernate.init(user.getRoles()), Hibernate.init(user.getDescription()).
4.3 预Fecth关联对象集合
HQL与Criteria都可以一次关联查询查出主对象与关联对象集合,需要注意的查出来的记录和我们平时用jdbc查一样,有三个子对象就会有三条重复 的主对象记录,可以用CriteriaSpecification.DISTINCT_ROOT_ENTITY去除重复。 注意,如果关联对象集合和关联对象是被缓存的,就不一定要预Fetch对象了。 详见Showcase的UserDaoTest 。
4.3 Bulk Update HQL
嗯,HQL也有Update/Delete语句的, 详见Showcase的UserDaoTest 。
4.4 扩展HQL Dialect
如果有些数据库特定的功能而Hibernate又还没提供的话,可以简单的扩展HQL Dialect. Showcase中的H2ExtDialect,为H2Dialect添加了两个新函数, 测试函数见UserDaoTest。
4.5 直接JDBC访问
如果还是不行,就在需要的地方干脆的使用JdbcTemplate吧,不要折腾什么Hibernate Native SQL了。
5. SpringSide3 封装
5.1 DAO类
1.通用的HibernateDAO
SpringSide 3 封装的泛型SimpleHibernateDAO
因为HibernateDAO已满足一般的DAO需要,因此可以直接在Service层中直接使用,仍然定义DAO子类主要为了保存注入 sessionFactory对象(否则sessionFactory要注入到Service层) 以及 可能存在的特殊DAO操作。
这里指的特殊处理并不是指一条HQL查询或一个按属性的查询都封装出一个查询函数,而是指RoleDAO中级联删除中间表这种真正特殊的 hibernate API调用和操作。
2. 不继承于HibernateDaoSupport/HibernateTemplate
参考Spring最新的Petlinc例子,DAO不再继承于Spring复杂的HibernateDaoSupport(Spring 1.x+ Hibernate 2.xd的产物),而是直接使用H3推荐的sessionFactorygetCurrentSession()方法与Hibernate的原生 API。
5.2 分页查询
SpringSide3封装的Page类配合Hibernate query by Criteria,可以迎合展示层Grid(表格控件)的种种需求(分页,排序,按属性查找)。
Page类分两部分:
一部分是请求参数:pageSize、pageNo、orderBy(多个排序字段以,分隔)、asc(是否升序,多个排序字段以,分隔)、 autoCount(是否自动执行count查询统计总结果数) 。
一部分是查询结果:result(分页的结果List),totalCount(查询的总结果数),totalPages(总页数), 以及相应的上页页号,下页页号,是否还有上一页,是否还有下一页等函数。
请求参数与结果放在同一个类里,是因为很多时候参数需要带到结果里,在页面上流转下去。
在queryByHQL的情况下,对简单HQL能够自动查询,而复杂的时候就需要自己另行执行count HQL语句查询后设置totalPages。
5.3 属性过滤条件
SpringSide封装的PropertyFitler类,可在页面中简单定义filter_EQS_name, filter_LIKES_NAME_OR_LOGIN_NAME的请求参数,可通过HibernateWebUtils的 buildPropertyFilter(ServletRequest)函数快速构造出PropertiyFilter列表并传递到 HibernateDAO的search(List
比较值类型可选S(String.class), I(Integer.class), L(Long.class), N(Double.class), D(Date.class), B(Boolean.class); 如果要同时比较多个属性,属性名之间用_OR_分隔.
5.4 HibernateUtils
像用户与角色,订单与订单项这些关联关系,通常需要展现到页面上的checkbox list 中,经用户重新勾勾选后,再保存回数据库。HibernateWebUtils提供了合并原有关联对象集合与勾选结果的Utils函数。
另外一个重要的函数是将页面上传来的filter_XXX参数构造成属性过滤条件列表。
Overview
无论Hibernate多么好,有时候还是需要直接的Jdbc访问。Spring的Jdbc Template提供了几个简单但实用的功能: 数据源,连接与事务的管理
? 命名查询参数的快速绑定(Map/Bean形式)。 ? 查询结果的快速转换与组装。
?
在Showcase的UserJdbcDao中,对JdbcTemplate的功能逐一做了演示,包括:
? ? ? ? ? ? ?
查询单个对象/对象列表(用RowMapper转换业务对象) 查询单个结果Map /Map列表(类似ResultSet) 使用Map形式传入的命名参数 使用Bean形式传入的命名参数
特别演示了IN语句的命名参数使用, where id in (:ids), 输入一个List参数即可。 批处理更新。
使用SQL Builder,在XML文件里定义Freemarker SQL模板。
TransactionTemplate
有时会嫌方法级别的@Transactional太粗旷,还是想自己精确控制事务,就用TransactionTemplate了, 在Showcase的UserJdbcDao演示了有/无返回值的事务以及需要catch异常自行处理不想再抛出的情形。
另外一个典型的场景是应用更改数据库后发送JMS消息,为了使消息接收者能查询到最新的数据,最好用TrasactionTemplate来精确控制事务 提交。