hibernate的一些杂记:
1.sessionFactory的用法:
SessionFactory是线程安全的,构造 SessionFactory 很消耗资源
sessionFactory = new Configuration().configure().addClass(**).addClass(**).buildSessionFactory();
Session session = sessionFactory.openSession();
在这里addClass的好处是不需要在hibernate.cfg.xml中声明domain中各个实体对应的配置文件
2.二级缓存
二级缓存中的类缓存,只适用于ID查询的方式(get()或load()),对于HQL的方式不可以,这个时候可以配置查询缓存,使用查询缓存需要先在hibernate.cfg.xml中开启查询缓存,然后在查询到时候setCacheable(true).
时间戳缓存:指定hibernate的二级缓存会自动检测,如果使用了update或delete语句,则会把数据清出缓存,重新查询。注::但是这是一级缓存session中的内容不会被刷新,所以要手动refresh().
list()方法默认不会使用缓存,除非调用了SetCacheable(true),但是如果HQL一变或者参数一遍,缓存就失效了,但是用iterate()查询,就可以。
3.iterate()查询的原理:
先执行一个查询,查询所有的符合条件的ID,再使用每一个对象时,会根据ID去缓存中查,如果查得到直接使用,如果查不到,那么就查出缓存中没有的相应数据。
4.关于级联
在设置了关联关系以后,如果主从对象存在级联关系,可以用cascade属性来设置,在使用时应仔细分析对象的级联关系,是否需要级联删除等操作。
5.在使用的时候
从对象的角度来说:让双方都设置关联关系比较好。所以用inverse属性配置是否由对方维护关联关系。一般都是让一的一方去放弃维护关联关系。为了使查询的集合元素有顺序,可以配置order-by属性
从数据库的角度来说,只要让一方设置关联就可以。所以在用时候可以让一的一方维护多的一方,也可以让多的一方维护一的一方。这样都会比双方同时维护性能要好。但是这样做的效果缺点是:代码不清晰。
注::在一对多中,维护关联关系就是指更新外键的值
在save的时候应该先保存无外键的一方,再保存有外键的一方(基于外键的一对一也同样),这样会节省一个update语句
6.主键生成策略:native---数据库的自动增长(oracle不支持)(identity,sequence[oracle],hilo)increment存在多线程问题。联合主键
7.DML语句不经过缓存,要手动session.refresh();
8. Query和Criteria接口
都是查询接口,Query实例包装了HQL查询语句,hql是面向对象的,他引用类名及类的属性名,而不是表名和字段名。Criteria接口完全封装了基于字符串形式的查询语句,比Query接口更面向对象,他擅长执行动态查询
9. Hibernate访问持久化类属性的策略
propertye(默认值):
表明hibernate通过getXXX和setXXX来访问类属性。推荐使用。提高域模型透明性。
field
hibernate通过java反射机制直接访问类属性。对于没有get与set方法的属性可设置该访问策略。
noop
它映射Java持久化类中不存在的属性,即主要用于HQL(用query接口测试,使用hql语句)中,当数据库中有某列,而实体中不存在的情况。
<!-- 该属性在Customer类中有get与set方法 -->
<property name="name" column="name"type="string"/>
<!-- 该属性在Customer类中不存在get和set方法 -->
<property name="name" column="name"type="string" access="field" />
<!-- 该属性在Customer类中不存在,但在数据库存在该字段。
使用noop处理,查询的时候忽略该字段-->
<property name="name"column="name" type="string" access="noop"/>
10.利用<property>元素的formula属性,用来设置一个sql表达式,hibernate将根据它来计算出派生属性的值。
如果指定了formula 属性,则就会insert=”false” update=”false”
11.java与Hibernate如何区分对象
Java语言按内存地址(==)或equals()方法区分不同的对象
Hibernate中用对象表示符(OID)来区分对象
OID是关系数据库中的主键在java对象模型中的等价物。在运行时,hibernate根据OID来维持java对象和数据库记录的对应关系。
Hibernate使用OID来区分对象,不是equals()方法!所以不重写持久化类的hashCode()与equals()方法Hibernate也可以正确运行(但要放到HashSet等集合中时要注意需要重写这两个方法)。
12. List是有序集合,因此持久化到数据库时必须增加一列来表示集合元素的次序。
集合属性只能以接口声明(当持久化某个实例时, Hibernate 会自动把程序中的集合实现类替换成 Hibernate 自己的集合实现类)
list元素要求用list-index的子元素来映射有序集合的次序列。
集合的属性的值会存放有另外的表中,须以外键关联,用 Key 元素来映射外键列
13.在映射一对多的双向关联关系时,应该在one方把inverse属性设为true, 这可以提高性能。
在建立两个对象的关联时,应该同时修改关联两端的相应属性,这样才会使程序更加健壮,提高业务逻辑层的独立性,使业务逻辑层的程序代码
不受Hibernate实现类的影响。同理,当删除双向关联的关系时,也应该修改关联两端的对象的相应属性.
14.update 、saveOrUpdate、 meger区别与用法
通常下面的场景会使用 update()
或 saveOrUpdate()
:
- 如果对象已经在本 session 中持久化了,不做任何事
- 如果另一个与本 session 关联的对象拥有相同的持久化标识(identifier),抛出一个异常
- 如果对象没有持久化标识(identifier)属性,对其调用
save()
- 如果对象的持久标识(identifier)表明其是一个新实例化的对象,对其调用
save()
。 - 如果对象是附带版本信息的(通过
<version>
或<timestamp>
)并且版本属性的值表明其是一个新实例化的对象,save()
它。 - 否则
update()
这个对象
- 如果 session 中存在相同持久化标识(identifier)的实例,用用户给出的对象的状态覆盖旧有的持久实例
- 如果 session 没有相应的持久实例,则尝试从数据库中加载(此处会有一次查询),或创建新的持久化实例
- 最后返回该持久实例
- 用户给出的这个对象没有被关联到 session 上,它依旧是脱管的