hibernate 一级缓存:(缓存的是实体对象)
一级缓存很短和session的生命周期一致,一级缓存也叫session级的缓存或事务缓存
哪些方法支持一级缓存:
*get()
*load()
*iterate() (查询实体对象)
如何管理一级缓存:
* session.clear() session.evict()
如何避免一次性大量的实体数据入库导致内存溢出
*先flush,再clear
如果数据量特别大,考虑采用jdbc实现,如果jdbc也不能满足要求,可以考虑采用数据库本身的特定导入工具
一.Load测试: 在同一个session中发出两次load查询
Student sutdent = (Student)session.load(Student.class,1);
System.out.println(student.getName());
sutdent = (Student)session.load(Student.class,1);
System.out.println(student.getName());
在同一个session中发出两次load查询,第一次load的时候不会去查询数据库,因为他是LAZY的,当使用的时候才去查询数据库, 第二次load的时候也不会,当使用的时候也不会查询数据库,因为他在缓存里找到,不会发出sql
Load测试: 开启两个session中发出两次load查询
Student sutdent = (Student)session.load(Student.class,1);
System.out.println(student.getName());
sessioin.close();
………..
sutdent = (Student)session.load(Student.class,1);
System.out.println(student.getName());
开启两个session中发出两次load查询,第一次load的时候不会去查询数据库,因为他是LAZY的,当使用的时候才去查询数据库, 第二次load的时候也不会,当使用的时候查询数据库,因为session间不能共享一级缓存的数据,因为他会随session的生命周期存在和消亡
二.Get测试: 在同一个session中发出两次get查询
Student sutdent = (Student)session.get(Student.class,1);
System.out.println(student.getName());
sutdent = (Student)session.get(Student.class,1);
System.out.println(student.getName());
在同一个session中发出两次get查询, 第一次get的时候去查询数据库,第二次get的时候不会查询数据库,因为他在缓存里找到,不会发出sql
三.iterate测试: 在同一个session中发出两次iterator查询
Student student = (Student)session.createQuery(“from Student s where s.id=1”).iterate().next();
System.out.println(student.getName());
student = (Student)session.createQuery(“from Student s where s.id=1”).iterate().next();
System.out.println(student.getName());
在同一个session中发出两次iterator查询,第一次iterate().next()的时候会发出查询id的sql,使用的时候会发出相应的查询实体对象,第二次iterate().next()的时候会发出查询id的sql,不会发出查询实体对象的sql,因为iterate使用缓存,不会发出sql
四.Iterate查询属性测试: 同一个session中发出两次查询属性
String name = (String)session.createQuery(“select s.name from Student s where s.id=1”).iterate().next();
System.out.println(name);
String name = (String)session.createQuery(“select s.name from Student s where s.id=1”).iterate().next();
System.out.println(name);
在同一个session中发出两次查询属性, 第一次iterate().next()的时候会发出查询属性的sql,第二次iterate().next()的时候会发出查询属性的sql,iterate查询普通属性,一级缓存不会缓存,所以会发出sql
五.同一个session中先save,再发出load查询save过的数据
Student stu = new Student();
stu.setName(“王五”);
Serializable id = session.save(stu);
Student sutdent = (Student)session.load(Student.class,id);
System.out.println(student.getName());
save的时候,他会在缓存里放一份,不会发出sql,因为save是使用缓存的
六.同一个session中先调用load查询,然后执行sessio.clear()或session.evict(),再调用load查询
Student sutdent = (Student)session.load(Student.class,1);
System.out.println(student.getName());
session.clear();
Student sutdent = (Student)session.load(Student.class,1);
System.out.println(student.getName());
sessio.clear()或session.evict()可以管理一级缓存,一级缓存无法取消,但可以管理.
上面的语句都会发出sql 因为一级缓存中的实体被清除了
七.向数据库中批量加入1000条数据
for(int i=0;i<1000;i++){
Student student = new Student();
student.setName(“s” + i);
session.save(student);
//每20条数据就强制session将数据持久化,同时清除缓存,避免大量数据造成内存溢出
if( i %20 == 0 ){
session.flush();
session.clear();
}
}
hibernate查询缓存(hibernate默认是关闭的)
查询缓存是针对普通属性结果集的缓存
对实体对象的结果集只缓存id
查询缓存的生命周期,当前关联的表发生修改,那么查询缓存生命周期结束
查询缓存的配置和使用:
1. 启用查询缓存:在hibernate.cfg.xml中加入:
<property name=”hibernate.cache.use_query_cache”>true</property>
2. 在程序中必须手动启用查询缓存,如:query.setCacheable(true);
测试查询缓存:
一. 开启查询缓存,关闭二级缓存,开启一个session,分别调用query.list (查询属性)
Query query = session.createQuery(“select s.name from Student s”);
//启用查询缓存
query.setCacheable(true);
List names = query.list();
for(Iterator iter = names.terator();iter.hasNext();){
String name = (String)iter.next();
System.out.println(name);
}
System.out.println(“------------------------------------------”);
query = session.createQuery(“select s.name from Student s”);
//启用查询缓存
query.setCacheable(true);
names = query.list();
for(Iterator iter = names.terator();iter.hasNext();){
String name = (String)iter.next();
System.out.println(name);
}
第二次没有去查询数据库,因为启用了查询缓存
二. 开启查询缓存,关闭二级缓存,开启两个session,分别调用query.list (查询属性)
Query query = session.createQuery(“select s.name from Student s”);
//启用查询缓存
query.setCacheable(true);
List names = query.list();
for(Iterator iter = names.terator();iter.hasNext();){
String name = (String)iter.next();
System.out.println(name);
}
session.close();
System.out.println(“------------------------------------------”);
………
Query query = session.createQuery(“select s.name from Student s”);
//启用查询缓存
query.setCacheable(true);
List names = query.list();
for(Iterator iter = names.terator();iter.hasNext();){
String name = (String)iter.next();
System.out.println(name);
}
第二次没有去查询数据库,因为查询缓存生命周期与session生命周期无关
三. 开启查询缓存,关闭二级缓存,开启两个session,分别调用query.iterate (查询属性)
Query query = session.createQuery(“select s.name from Student s”);
//启用查询缓存
query.setCacheable(true);
for(Iterator iter =query.iterate();iter.hasNext();){
String name = (String)iter.next();
System.out.println(name);
}
session.close();
System.out.println(“------------------------------------------”);
………
Query query = session.createQuery(“select s.name from Student s”);
//启用查询缓存
query.setCacheable(true);
for(Iterator iter = query.iterate();iter.hasNext();){
String name = (String)iter.next();
System.out.println(name);
}
第二去查询数据库,因为查询缓存只对query.list()起作用,对query.iterate()不起作用,也就是说query.iterate()不使用查询缓存
四. 关闭查询缓存,关闭二级缓存,开启两个session,分别调用query.list (查询实体对象)
Query query = session.createQuery(“ from Student s”);
//query.setCacheable(true);
List students = query.list();
for(Iterator iter = students.iterate();iter.hasNext();){
Student stu = (Student)iter.next();
System.out.println(stu.getName());
}
session.close();
System.out.println(“------------------------------------------”);
………
Query query = session.createQuery(“ from Student s”);
//query.setCacheable(true);
List students = query.list();
for(Iterator iter = students.iterate();iter.hasNext();){
Student stu = (Student)iter.next();
System.out.println(stu.getName());
}
第二去查询数据库,因为list默认每次都会发出查询sql
五. 开启查询缓存,关闭二级缓存,开启两个session,分别调用query.list (查询实体对象)
Query query = session.createQuery(“ from Student s”);
query.setCacheable(true);
List students = query.list();
for(Iterator iter = students.iterate();iter.hasNext();){
Student stu = (Student)iter.next();
System.out.println(stu.getName());
}
session.close();
System.out.println(“------------------------------------------”);
………
Query query = session.createQuery(“ from Student s”);
query.setCacheable(true);
List students = query.list();
for(Iterator iter = students.iterate();iter.hasNext();){
Student stu = (Student)iter.next();
System.out.println(stu.getName());
}
第二去查询数据库时,会发出N条sql语句,因为开启了查询缓存,关闭了二级缓存,那么查询缓存会缓存实体对象的id,所以hibernate会根据实体对象的id去查询相应的实体,如果缓存中不存在相应的实体,那么将发出根据实体id查询的sql语句,否则不会发出sql,使用缓存中的数据
六. 开启查询缓存,开启二级缓存,开启两个session,分别调用query.list (查询实体对象)
Query query = session.createQuery(“ from Student s”);
query.setCacheable(true);
List students = query.list();
for(Iterator iter = students.iterate();iter.hasNext();){
Student stu = (Student)iter.next();
System.out.println(stu.getName());
}
session.close();
System.out.println(“------------------------------------------”);
………
Query query = session.createQuery(“ from Student s”);
query.setCacheable(true);
List students = query.list();
for(Iterator iter = students.iterate();iter.hasNext();){
Student stu = (Student)iter.next();
System.out.println(stu.getName());
}
第二不会发出sql,因为开启了二级缓存和查询缓存,查询缓存缓存了实体对象的id列表,hibernate会根据实体对象的id列表到二级缓存中取得相应的数据
悲观锁
悲观锁的实现,通常依赖于数据库机制,在整个过程中将数据锁定,其它任何用户都不能读取或修改。
举个例子:
//查询id=1的那条记录,使用悲观锁
User user = (User)session.load(User.class, 1 , LockMode.UPGRADE);
使用了数据库中的 for update 锁定
乐观锁
大多数基于数据版本记录机制(version)实现,一半是在数据库表加入一个version字段,读取数据时将版本号一同读出,之后更新数据时版本号加一,如果提交数据时版本号小于或等于数据库表中的版本号,则认为数据是过期的,否则给予更新。
其实并非是锁,是一种冲突检测 (没有hibernate也可以使用的,自己要在数据库中建字段来控制,使用hibernate方便些,封装好了)
在*.hm.xml中 添加红色部分:
<class
name="com.tao3c.orm.TbBusinessInfo" table="tb_business_info" optimistic-lock=”version”>
其中version是com.tao3c.orm.TbBusinessInfo类的属性,hiernbate会去维护的,不用自己去该
悲观锁
悲观锁的实现,通常依赖于数据库机制,在整个过程中将数据锁定,其它任何用户都不能读取或修改。
举个例子:
//查询id=1的那条记录,使用悲观锁
User user = (User)session.load(User.class, 1 , LockMode.UPGRADE);
使用了数据库中的 for update 锁定
乐观锁
大多数基于数据版本记录机制(version)实现,一半是在数据库表加入一个version字段,读取数据时将版本号一同读出,之后更新数据时版本号加一,如果提交数据时版本号小于或等于数据库表中的版本号,则认为数据是过期的,否则给予更新。
其实并非是锁,是一种冲突检测 (没有hibernate也可以使用的,自己要在数据库中建字段来控制,使用hibernate方便些,封装好了)
在*.hm.xml中 添加红色部分:
<class
name="com.tao3c.orm.TbBusinessInfo" table="tb_business_info" optimistic-lock=”version”>
其中version是com.tao3c.orm.TbBusinessInfo类的属性,hiernbate会去维护的,不用自己去该
在hibernate中设置:
查询数据库每次最多返回50条结果:
<property name=”hibernate.jdbc.fetch_size”>50</property>
30条更新数据库一次:
<property name= ”hibernatejdbc.batch_size”>30</property>
但不是所有的数据库都支持的,sqlServer 和orcale 都支持的。
一.hibernate 抓取策略(Fetch) 单端代理批量抓取
1.fetch=”select” 关联实体
//fetch 默认是select
<many-to-one name="businessId" column="business_id" insert="true" update="true" fetch="select">
Student student = (Student)session.load(Student.class,1);
System.out.println(student.getName());
System.out.println(student.getClasses().getName()); //多对一中的属性班级,获取班级名称
Fetch=”select” ,上面程序会发2条sql语句,第二条发送一条select语句抓取当前对象关联实体或集合 (这里指是班级名称)
2.fetch=” join” 关联实体
//fetch 设置成 join
<many-to-one name="businessId" column="business_id" insert="true" update="true"
fetch=" join ">
Student student = (Student)session.load(Student.class,1);
System.out.println(student.getName());
System.out.println(student.getClasses().getName()); //多对一中的属性班级,获取班级名称
fetch=” join” , 上面程序会发1条sql语句, hibernate会通过select使用外链接来加载其关联实体或集合,此时lazy会失效
二.hibernate 抓取策略(Fetch) 集合代理批量抓取
1. fetch=”select”
//fetch 默认是select
<set name="students" inverse="true" cascade="all" fetch="select">
<key column="classid" />
<one-to-many class="com.Student" />
</set>
Classes cla = (Classes)session.load(Classes.class,1);
System.out.println(cla.getName());
for(Iterator iter = cla.getStudents().iterator();iter.hasNext();){
Student student = (Student)iter.next();
System.out.println(student.getName());
}
fetch=”select” ,上面程序用到了就发sql语句,第二从循环中发了N条,如果:fetch=”subselect”,则只是发送一条语句,见下面
2 fetch=”join”
//fetch 设置成join
<set name="students" inverse="true" cascade="all" fetch="join">
<key column="classid" />
<one-to-many class="com.Student" />
</set>
Classes cla = (Classes)session.load(Classes.class,1);
System.out.println(cla.getName());
for(Iterator iter = cla.getStudents().iterator();iter.hasNext();){
Student student = (Student)iter.next();
System.out.println(student.getName());
}
Fetch=”select” ,上面程序只发了一条sql语句
三.hibernate 抓取策略(Fetch) 集合代理批量抓取
2. fetch=”subselect”
//fetch设置成subselect
<set name="students" inverse="true" cascade="all" fetch="subselect">
<key column="classid" />
<one-to-many class="com.Student" />
</set>
List classesList = session.createQuery(“select c from Classes c where c.id in(1,2,3)”);
for(Iterator iter=classesList.iterator();iter.hasNext();){
Classess classess = (Classess)iter.next();
System.out.println(“classes.name=”+ classes.getName());
for(Iterator iter1 = classess.getStudents().iterator();iter1.hasNext();){
Student student = (Student)iter1.next();
System.out.println(student.getName());
}
}
Fetch=”subselct” ,另外发送一条select语句抓取在前面查询到的所有实体对象的关联集合
四.hibernate 批量策略batch-size属性,可以批量加载实体类,
参见Classes.hbm.xml,同时集合也可以是使用,如:
<set name="students" inverse="true" cascade="save-update" batch-size=”5”>
在配置文件hbm.xml 设置中:
<class name="com.Classes " table="tb_classes" batch-size=”3”>
List students = session.createQuery(“select s from Student s where s.id in(:ids)”).setParameterList(“:ids”,new Object[]{1,11,21,31,41,51,61,71,81,91}).list();
for(Iterator iter=students.iterator();iter.hasNext();){
Student student = (Sutdent)iter.next();
System.out.println(student.getName());
System.out.println(student.getClassess().getName());
}
当第二个for循环时,每次加载 之前设置的 数量 实体对象, 如:现在设置3,那么当Iterator iter=students.iterator();iter.hasNext();时候,他会查询出3个student对象
一.hibernate多对多映射(单项),自动产生第三张表
User--à Role
user(id,name) role(id,name)
User类:
private int id; private String name; private Set roles;
Role类:
private int id; private String name;
User.hbm.xml中:
<set name=”roles” table=”t_user_role”>
<key column=”userid” />
<many-to-many class=”com.Role” column=”roleid” />
</set>
这样,hibernate会自动产生中间表t_user_role(userid,roleid) 并且是复合主键,userid为t_user的外键,roleid为t_role的外键
二.hibernate多对多的存储
Role r1 = new Role();
r1.setName(“数据录入人员”);
Role r2 = new Role();
r2.setName(“商务主管”);
Role r3 = new Role();
r3.setName(“大区经理”);
User u1 = new User();
u1.setName(“10”);
Set u1Roles = new HashSet();
u1Roles.add(r1);
u1Roles.add(r2);
u1.setRoles(u1Roles);
User u2 = new User();
u1.setName(“祖儿”);
Set u2Roles = new HashSet();
u2Roles.add(r2);
u2Roles.add(r3);
u2.setRoles(u2Roles);
User u3 = new User();
u3.setName(“杰伦”);
Set u3Roles = new HashSet();
u3Roles.add(r1);
u3Roles.add(r2);
u3Roles.add(r3);
u3.setRoles(u3Roles);
session.save(r1);
session.save(r2);
session.save(r3);
session.save(u1);
session.save(u2);
session.save(u3);
结束之后,在第三张表中也有数据
三.hibernate多对多的加载
User user = (User)session.load(User.class,1);
System.out.println(user.getName());
for(Iterator iter = user.getRoles().iterator();iter.hasNext();){
Role role = (Role)iter.next();
System.out.println(role.getName());
}
每次加载都会发出sql语句
三.hibernate多对多的 双向映射
User ß--.-àRole
user(id,name) role(id,name)
User类:
private int id; private String name; private Set roles;
Role类:
private int id; private String name; private Set users;
User.hbm.xml中:
<set name=”roles” table=”t_user_role”>
<key column=”userid” />
<many-to-many class=”com.Role” column=”roleid” />
</set>
Role.hbm.xml中:
<set name=”roles” table=”t_user_role”> //这里可以设置order-by=”userid”,根据userid排序
<key column=”roleid” />
<many-to-many class=”com.User” column=”userid” />
</set>
注意,上面中间表名字是一样的
这样,hibernate也会自动产生中间表t_user_role(userid,roleid) 并且是复合主键,userid为t_user的外键,roleid为t_role的外键
一.hibernate多对多映射(单项),自动产生第三张表
User--à Role
user(id,name) role(id,name)
User类:
private int id; private String name; private Set roles;
Role类:
private int id; private String name;
User.hbm.xml中:
<set name=”roles” table=”t_user_role”>
<key column=”userid” />
<many-to-many class=”com.Role” column=”roleid” />
</set>
这样,hibernate会自动产生中间表t_user_role(userid,roleid) 并且是复合主键,userid为t_user的外键,roleid为t_role的外键
二.hibernate多对多的存储
Role r1 = new Role();
r1.setName(“数据录入人员”);
Role r2 = new Role();
r2.setName(“商务主管”);
Role r3 = new Role();
r3.setName(“大区经理”);
User u1 = new User();
u1.setName(“10”);
Set u1Roles = new HashSet();
u1Roles.add(r1);
u1Roles.add(r2);
u1.setRoles(u1Roles);
User u2 = new User();
u1.setName(“祖儿”);
Set u2Roles = new HashSet();
u2Roles.add(r2);
u2Roles.add(r3);
u2.setRoles(u2Roles);
User u3 = new User();
u3.setName(“杰伦”);
Set u3Roles = new HashSet();
u3Roles.add(r1);
u3Roles.add(r2);
u3Roles.add(r3);
u3.setRoles(u3Roles);
session.save(r1);
session.save(r2);
session.save(r3);
session.save(u1);
session.save(u2);
session.save(u3);
结束之后,在第三张表中也有数据
三.hibernate多对多的加载
User user = (User)session.load(User.class,1);
System.out.println(user.getName());
for(Iterator iter = user.getRoles().iterator();iter.hasNext();){
Role role = (Role)iter.next();
System.out.println(role.getName());
}
每次加载都会发出sql语句
三.hibernate多对多的 双向映射
User ß--.-àRole
user(id,name) role(id,name)
User类:
private int id; private String name; private Set roles;
Role类:
private int id; private String name; private Set users;
User.hbm.xml中:
<set name=”roles” table=”t_user_role”>
<key column=”userid” />
<many-to-many class=”com.Role” column=”roleid” />
</set>
Role.hbm.xml中:
<set name=”roles” table=”t_user_role”> //这里可以设置order-by=”userid”,根据userid排序
<key column=”roleid” />
<many-to-many class=”com.User” column=”userid” />
</set>
注意,上面中间表名字是一样的
这样,hibernate也会自动产生中间表t_user_role(userid,roleid) 并且是复合主键,userid为t_user的外键,roleid为t_role的外键
单态定义:
Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。
在很多操作中,比如建立目录 数据库连接都需要这样的单线程操作。
还有, singleton能够被状态化; 这样,多个单态类在一起就可以作为一个状态仓库一样向外提供服务,比如,你要论坛中的帖子计数器,每次浏览一次需要计数,单态类能否保持住这个计数,并且能synchronize的安全自动加1,如果你要把这个数字永久保存到数据库,你可以在不修改单态接口的情况下方便的做到。
另外方面,Singleton也能够被无状态化。提供工具性质的功能,
Singleton模式就为我们提供了这样实现的可能。使用Singleton的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收(garbage collection)。
我们常常看到工厂模式中类装入器(class loader)中也用Singleton模式实现的,因为被装入的类实际也属于资源。
如何使用?
一般Singleton模式通常有几种形式:
public class Singleton {
private Singleton(){}
//在自己内部定义自己一个实例,是不是很奇怪?
//注意这是private 只供内部调用
private static Singleton instance = new Singleton();
//这里提供了一个供外部访问本class的静态方法,可以直接访问
public static Singleton getInstance() {
return instance;
}
}
第二种形式:
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
//这个方法比上面有所改进,不用每次都进行生成对象,只是第一次
//使用时生成实例,提高了效率!
if (instance==null)
instance=new Singleton();
return instance; }
}
使用Singleton.getInstance()可以访问单态类。
上面第二中形式是lazy initialization,也就是说第一次调用时初始Singleton,以后就不用再生成了。
注意到lazy initialization形式中的synchronized,这个synchronized很重要,如果没有synchronized,那么使用getInstance()是有可能得到多个Singleton实例。关于lazy initialization的Singleton有很多涉及double-checked locking (DCL)的讨论,有兴趣者进一步研究。
一般认为第一种形式要更加安全些。
使用Singleton注意事项:
有时在某些情况下,使用Singleton并不能达到Singleton的目的,如有多个Singleton对象同时被不同的类装入器装载;在EJB这样的分布式系统中使用也要注意这种情况,因为EJB是跨服务器,跨JVM的。
我们以SUN公司的宠物店源码(Pet Store 1.3.1)的ServiceLocator为例稍微分析一下:
在Pet Store中ServiceLocator有两种,一个是EJB目录下;一个是WEB目录下,我们检查这两个ServiceLocator会发现内容差不多,都是提供EJB的查询定位服务,可是为什么要分开呢?仔细研究对这两种ServiceLocator才发现区别:在WEB中的ServiceLocator的采取Singleton模式,ServiceLocator属于资源定位,理所当然应该使用Singleton模式。但是在EJB中,Singleton模式已经失去作用,所以ServiceLocator才分成两种,一种面向WEB服务的,一种是面向EJB服务的。
Singleton模式看起来简单,使用方法也很方便,但是真正用好,是非常不容易,需要对Java的类 线程内存等概念有相当的了解。
总之:如果你的应用基于容器,那么Singleton模式少用或者不用,可以使用相关替代技术。
1.两种配置文件:
A.hibernate.cfg.xml和B.hibernate.properties
A中可含映射文件的配置,而B中hard codes加映射文件。
A.Configuration config=new Configuration().config();
B. Configuration config=new Configuration();
config.addClass(TUser.class);
2.你不必一定用hibernate.cfg.xml或hibernate.properties这两文件名,你也不一定非得把配置文件放在Classes下, File file=new File("c:\\sample\\myhibernate.xml"); Configuration config=new Configuration().config(file);
3. session.Flush() 强制数据库立即同步,当用事务时,不必用flush,事务提交自动调用flush在session关闭时也会调用flush
4. Hibernate总是使用对象类型作为字段类型
5. XDoclet专门建立了hibernate doclet,就是在java代码上加上一些java docTag,后来再让XDoclet分析该java代码,生成映射文件;
6.HQL子句本身大小写无关,但是其中出现的类名和属性名必须注意大小写区分。
7.关系: Constrained : 约束,表明主控表的主键上是否存在一个外键(foreigh key)对其进行约束。
property-ref:关联类中用于与主控类相关联的属性名,默认为关联类的主键属性名
单向一对多需在一方配置,双向一对多需在双方进行配置
8.lazy=false:被动方的记录由hibernate负责记取,之后存放在主控方指定的Collection类型属性中
9. java.util.Set或net.sof.hibernate.collecton.Bag类型的Collection
10.重要:inverse:用于标识双向关联中的被动方一端。
inverse=false的一方(主控方)负责维护关联关系.默认值:false
11.batch-size:采用延迟加载特征时,一次读入的数据数昨。
12.一对多通过主控方更新(主控方为一方时)
user.getAddresses().add(addr);
session.save(user);//通过主控对象级联更新
13.在one-to-many 关系中,将many 一方设为主动方(inverse=false)将有助性能的改善。在一方设置关系时,inverse=true,即将主控权交给多方, 这样多方可主动从一方获得foreign key,然后一次insert即可完工。
addr.setUser(user);//设置关联的TUser对象
user.getAddresses().add(addr);
session.save(user);//级联更新
14.只有设为主控方的一方才关心(访问)对方的属性,被动方是不关心对方的属性的。
15.one-to-many与many-to-one节点的配置属性不同:
一对多关系多了lazy和inverse两个属性多对多节点属性:
column:中间映射表中,关联目标表的关联字段
class:类名,关联目标类
outer-join:是否使用外联接
注意:access是设置属性值的读取方式。
column是设置关联字段。
16.多对多,注意两方都要设置inverse和lazy,cascade只能设为insert-update
多对多关系中,由于关联关系是两张表相互引用,因此在保存关系状态时必须对双方同时保存。
group1.getRoles().add(role1); role1.getGroups().add(group1);
session.save(role1); session.save(group1);
17.关于vo和po vo经过hibernate容量处理,就变成了po(该vo的引用将被容器保存,并且在session关闭时flush,因此po如果再传到其它地方改变了,就危险了) vo和po相互转换:BeanUtils.copyProperties(anotherUser,user);
18.对于save操作而言,如果对象已经与Session相关联(即已经被加入Session的实体容器中),则无需进行具体的操作。因为之后的Session.flush过程中,Hibernate 会对此实体容器中的对象进行遍历,查找出发生变化的实体,生成并执行相应的update 语句。
19.如果我们采用了延迟加载机制,但希望在一些情况下,实现非延迟加载时的功能,也就是说,我们希望在Session关闭后,依然允许操作user的addresses 属性 Hibernate.initialize方法可以通过强制加载关联对象实现这一功能: 这也正是我们为什么在编写POJO时,必须用JDK Collection接口(如Set,Map), 而非特定的JDK Collection实现类(如HashSet、HashMap)申明Collection属性的 原因。
20.事务:从sessionFactory获得session,其自动提交属性就已经关闭(AutoCommit=false),此时若执行了jdbc操作,如果不显式调用session.BeginTransaction(),是不会执行事务操作的。
jdbc transaction:基于同一个session(就是同一个connection)的事务;
jta transaction:跨session(跨connection)事务.
对于jta事务,有三种实现方法:
A。UserTransaction tx=new InitialContext().lookup("...");
tx.commit();
B. 使用hibernate封装的方法:(不推荐)
Transaction tx=session.beginTransaction();
tx.commit();
C. 使用ejb之sessionBean的事务技持方法,你只要在把需要在发布描述符中,把需要jta事务的方法声明为require即可
21.悲观锁,乐观锁: 乐观锁一般通过version来实现,注意version节点必须出现在id后。
22.Hibernate中,可以通过Criteria.setFirstResult和Criteria.setFetchSize方法设定分页范围。
Query接口中也提供了与其一致的方法,hibernate主要在dialect类中实现在这个功能。
23.cache
……
net.sf.ehcache.hibernate.Provider
还需对ecache本身进配置
之后在映射文件中指定各个映射实体的cache策略
....
....
***************************************************** Query.list()跟Query.iterate()的不同:对于query.list()总是通过一条sql语句获取所有记录,然后将其读出,填入pojo返回; 但是query.iterate(),则是首先通过一条Select SQL 获取所有符合查询条件的记录的 id,再对这个id 集合进行循环操作,通过单独的Select SQL 取出每个id 所对应的记 录,之后填入POJO中返回。
也就是说,对于list 操作,需要一条SQL 完成。而对于iterate 操作,需要n+1 条SQL。,list方法将不会从Cache中读取数据。iterator却会。
24.ThreadLocal:它会为每个线程维护一个私有的变量空间。实际上, 其实现原理是在JVM 中维护一个Map,这个Map的key 就是当前的线程对象,而value则是线程通过ThreadLocal.set方法保存的对象实例。当线程调用ThreadLocal.get方法时, ThreadLocal会根据当前线程对象的引用,取出Map中对应的对象返回。
这样,ThreadLocal通过以各个线程对象的引用作为区分,从而将不同线程的变量隔离开来。
25.Hibernate官方开发手册标准示例:
public class HibernateUtil { private static SessionFactory sessionFactory;
static { try { // Create the SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (HibernateException ex) { throw new RuntimeException( "Configuration problem: " + ex.getMessage(), ex );
} } public static final ThreadLocal session = new ThreadLocal();
public static Session currentSession() throws HibernateException { Session s = (Session) session.get();
// Open a new Session, if this Thread has none yet if (s == null) { s = sessionFactory.openSession();
session.set(s);
} return s;
} public static void closeSession() throws HibernateException { Session s = (Session) session.get();
session.set(null);
if (s != null) s.close();
} }
26.通过filter实现session的重用:
public class PersistenceFilter implements Filter { protected static ThreadLocal hibernateHolder = new ThreadLocal();
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { hibernateHolder.set(getSession());
try { …… chain.doFilter(request, response);
…… } finally { Session sess = (Session)hibernateHolder.get();
if (sess != null) { hibernateHolder.set(null);
try { sess.close(); } catch (HibernateException ex) { throw new ServletException(ex);
} } } } ……}
Eclipse快捷键指南
有些还是比叫有用的,不过不是很全
编辑
作用域 功能 快捷键
全局 查找并替换 Ctrl+F
文本编辑器 查找上一个 Ctrl+Shift+K
文本编辑器 查找下一个 Ctrl+K
全局 撤销 Ctrl+Z
全局 复制 Ctrl+C
全局 恢复上一个选择 Alt+Shift+↓
全局 剪切 Ctrl+X
全局 快速修正 Ctrl1+1
全局 内容辅助 Alt+/
全局 全部选中 Ctrl+A
全局 删除 Delete
全局 上下文信息 Alt+?
Alt+Shift+?
Ctrl+Shift+Space
Java编辑器 显示工具提示描述 F2
Java编辑器 选择封装元素 Alt+Shift+↑
Java编辑器 选择上一个元素 Alt+Shift+←
Java编辑器 选择下一个元素 Alt+Shift+→
文本编辑器 增量查找 Ctrl+J
文本编辑器 增量逆向查找 Ctrl+Shift+J
全局 粘贴 Ctrl+V
全局 重做 Ctrl+Y
查看
作用域 功能 快捷键
全局 放大 Ctrl+=
全局 缩小 Ctrl+-
窗口
作用域 功能 快捷键
全局 激活编辑器 F12
全局 切换编辑器 Ctrl+Shift+W
全局 上一个编辑器 Ctrl+Shift+F6
全局 上一个视图 Ctrl+Shift+F7
全局 上一个透视图 Ctrl+Shift+F8
全局 下一个编辑器 Ctrl+F6
全局 下一个视图 Ctrl+F7
全局 下一个透视图 Ctrl+F8
文本编辑器 显示标尺上下文菜单 Ctrl+W
全局 显示视图菜单 Ctrl+F10
全局 显示系统菜单 Alt+-
导航
作用域 功能 快捷键
Java编辑器 打开结构 Ctrl+F3
全局 打开类型 Ctrl+Shift+T
全局 打开类型层次结构 F4
全局 打开声明 F3
全局 打开外部javadoc Shift+F2
全局 打开资源 Ctrl+Shift+R
全局 后退历史记录 Alt+←
全局 前进历史记录 Alt+→
全局 上一个 Ctrl+,
全局 下一个 Ctrl+.
Java编辑器 显示大纲 Ctrl+O
全局 在层次结构中打开类型 Ctrl+Shift+H
全局 转至匹配的括号 Ctrl+Shift+P
全局 转至上一个编辑位置 Ctrl+Q
Java编辑器 转至上一个成员 Ctrl+Shift+↑
Java编辑器 转至下一个成员 Ctrl+Shift+↓
文本编辑器 转至行 Ctrl+L
搜索
作用域 功能 快捷键
全局 出现在文件中 Ctrl+Shift+U
全局 打开搜索对话框 Ctrl+H
全局 工作区中的声明 Ctrl+G
全局 工作区中的引用 Ctrl+Shift+G
文本编辑
作用域 功能 快捷键
文本编辑器 改写切换 Insert
文本编辑器 上滚行 Ctrl+↑
文本编辑器 下滚行 Ctrl+↓
文件
作用域 功能 快捷键
全局 保存 Ctrl+X
Ctrl+S