HibernateX 实践总结
Hibernate不是盏省油的灯也不是想像的射来射去很简单的事有很多细节处理不好会让你很不舒服的这方面最突出的表现在两方面一是事务管理是JTA事务还是JDBC事务?幸亏有了Spring和JEE容器二是胡乱映射模型关系建立不合理或者错误导致或者是映射策略和技术不过关导致这样的最终结果是抛出一堆HibernateException摸不着头脑下面是我实践中的一些总结作为备忘录写出来
参考的是最新的Hibernate GA API文档还吸收了Hibernate牛人(夏新)写的书和翻译中文开发手册的精华
Configuration/SessionFactory/Session
Configuration实例代表了一个应用程序中Java类型 到SQL数据库映射的完整集合 Configuration被用来构建一个(不可变的 (immutable))SessionFactory
SessionFactory是线程安全的创建代价很高
Session是非线程安全的轻量级的一个Session对应一个JDBC连接
Session的connection()会获取Session与之对应的数据库连接Connection对象
Session的功能就是操作对象的这些对象和数据库表有映射关系
Session操作的对象是有状态的分三类
自由状态(transient): 未持久化未与任何Session相关联数据库表中没有对应的记录
持久化状态(persistent): 与一个Session相关联对应数据库表中一条记录
游离状态(detached): 已经进行过持久化但当前未与任何Session相关联数据库表中曾经有一条记录现在还有没有就不知道了
游离状态的实例可以通过调用save()persist()或者saveOrUpdate()方法进行持久化持久化实例可以通过调用 delete()变成游离状态通过get()或load()方法得到的实例都是持久化状态的游离状态的实例可以通过调用 update()saveOrUpdate()lock()或者replicate()进行持久化游离或者自由状态下的实例可以通过调用merge()方法成为一个新的持久化实例
Session的save()/persist()/update()/saveOrUpdate()/merge()/delete()方法
save()方法将指定对象保存插入表中一条数据
persist()方法将指定对象保存插入表中一条数据我还没发现它和save方法有什么特别之处
replicate()方法完全使用给定对象各个属性的值(包括标识id)来持久化给定的游离状态(Transient)的实体很暴力啊其中还需要指定存储模式(有四种保存策略供选择)
update()方法将指定对象更新更新表中一条数据
saveOrUpdate()方法接收一个实体对象根据实体对象的id判断是否已经存在进行保存或更新操作这样保存和更新方法就统一了
merge()方法将给定的对象的状态复制到具有相同标识的持久化对象上
delete()方法将指定对象删除删除表中一条数据
特别注意为了使用saveOrUpdate()方法在由定义映射文件时通过设定<id>标签的unsavedvalue=null来判断执行什么操作 当id属性等于unsavedvalue的值(在此为null)时则认为还没有保存应该执行保存操作否则执行更新操作这样设定之后可以使用saveOrUpdate()方法来统一保存和更新的方法
<id name=id column=id type=javalangInteger unsavedvalue=null>
<generator class=native/>
</id>
unsavedvalue可以设定的值有四个
any总是储存
none总是更新
nullid为null时储存(预设)
validid为null或是指定值时储存
Session的get()/load()方法
get()方法会总是查询实体对象不存在时候返回null
load()方法也是获取一个实体对象不存在时候抛空指针异常
Session的clear()/evict()方法
clear()方法清除Session级别缓存中的所有实体(包括各种状态)对象目的是释放内存
evict()方法清除Session级别缓存中的指定的实体(包括各种状态)对象
当然Session关闭后这些缓存也就不存在了会等待JVM回收
Session的flush()方法
flush()强制持久化Session缓存中的实体对象一般还会调用clear()或evict()目的是赶紧保存释放宝贵内存资源
Session的commit()/rollback()方法
commit()方法用于提交Session上的事务否则工作单元不会对数据库产生影响如果执行出现异常(也就是commit()失败了)则之前的操作取消执行rollback()可撤消之前的操作
Session的close()/isOpen()/isConnected()/reconnect()方法
close()方法关闭Session所对应数据库连接与其相关联的对象生命周期结束
isOpen()方法检查Session是否仍然打开如果Session已经断开则可以使用reconnect(Connection connection)来重新让Session关联一个JDBC连接
isConnected()方法检查当前Session是否处于连接状态
CriteriaDetchedCriteria和Query接口
Criteria和Query的实例都是和Session绑定的其生命周期跟随着Session结束而结束
DetchedCriteria实例相当于一个SQL模板目的是为了复用其中的getExecutableCriteria(session)方法接收一个Session对象并与之绑定返回一个Criteria对象
Hibernate类的initialize()方法
initialize()方法强制Hibernate立即加载指定实体所关联的对象和集合Hibernate类中还有其他几个很有用但不适很常用的方法
映射文件中的lazy属性
在Hibernate中class元素的lazy属性默认是true如果不需要则需要显示指定为lazy=false否则操作load返回的对象会抛异常另外Hibernate中还可以为实体属性指定lazy属性
JDBC事务和JTA事务
Hibernate本身没有事务管理功能它依赖于JDBC或JTA的事务管理功能在Hibernate配置文件中如果不显式指定Transaction的工厂类别属性hibernatetransactionfactory_class的配置则默认为JDBC事务
<property name=hibernatetransactionfactory_class>orghibernatetransactionJDBCTransactionFactory</property>
在通过SessionFactory获取到Session后与Session相关联的JDBC Connection实例就被设定为false
特别注意如果数据库不支持事务比如MySQL的MyISAM引擎的表就不支持事务声明事务也不会起作用要使MySQL的表支持事务则可以指定表的引擎类型为InnoDB如果是学习或者研究目前最好还是使用PostgreSQL 或DBOracle
JDBC事务总是和一个数据库连接(或一个Session)相关联的
JTA事务则可以跨越多个数据连接(或多个Session)这些连接还可以是不同数据库的连接JTA事务一般由容器进行管理编程只要在多个操作单元的开始和结束定义JTA事务的边界即可
特别注意如果使用了JTA事务则不能再用在JDBC式的事务来管理每个Session的操作否则会出错为了程序的的通用性一般来说都是使用JTA事务来构建应用这使用任何环境当然也可以使用事务代理为每个JDBC的操作方法加入事务控制这样也为程序以后移植到JTA容器事务上带来很大方便其实现在可以使用Spring的事务管理与Hibernate结合的非常完美