本文主要讲解:

1 级联 cascade 关键字

2 级联删除

3 inverse 关键字

4 懒加载

5 缓存的模拟

6 Hibernate 的一级缓存

7 Hibernate 的二级缓存

一、级联 cascade 关键字

 public static  void add(){
NiGuAn niguan=new NiGuAn();
niguan.setName("九峰寺"); NiGu nigu1=new NiGu();
nigu1.setNiguan(niguan);
nigu1.setFahao("空空大师"); NiGu nigu2=new NiGu();
nigu2.setNiguan(niguan);
nigu2.setFahao("玄玄"); NiGu nigu3=new NiGu();
nigu3.setNiguan(niguan);
nigu3.setFahao("灭绝"); try{
Session s=HibUtil.getSession();
Transaction tx=s.beginTransaction(); List<NiGu> niguList=new ArrayList<NiGu>();
niguList.add(nigu1);
niguList.add(nigu2);
niguList.add(nigu3); niguan.setNiguList(niguList); s.save(niguan); /*s.save(nigu1);
s.save(nigu2);
s.save(nigu3); 如果这里不写,将出错 */ tx.commit();
}

可以使用 cascade (级联) 的方式进行处理

在 NiGuAn.hbm.xml 中 添加

<bag name="niguList" cascade="save-update">  //添加的是级联保存
<key column="niguan_id" />
<one-to-many class="NiGu" />
</bag>

级联 cascade 的几个配置

-- none // 忽略其他关联的对象,默认值

-- all  //级联删除, 级联更新,但解除父子关系时不会自动删除子对象.

-- save-update //当session通过save(),update(),saveOrUpdate()方法来保存或更新对象时,级联保存所有关联的新建的临时对象,并且级联更新所有关联的游离对象

-- delete  //级联删除, 但不具备级联保存和更新

-- lock //通过lock()把当前游离对象加入session缓存时,会把所有的游离对象也加入Session缓存中。

-- refresh //:通过refresh()刷新当前对象时,会级联刷新所有关联的对象。(刷新是指同步更新session缓存中数据)

-- evict //通过evict()清除session缓存中对象时,会级联清除所有关联的对象

-- replicate //通过replicate()复制当前对象时,会级联复制所有关联的对象

-- persist //当session通过persist()方法来保存当前对象时,会级联保存所有关联的新建的临时对象。

-- merge //通过Session的merge()方法来保存当前对象时,会级联融合所有关联的游离对象。

-- delege-orphan(one-to-many)  //删除所有和当前对象时,解除关联行为的对象。

二、级联删除

//删除尼姑庵
public static void delNiGuAn(){
try{
Session s=HibUtil.getSession();
Transaction tx= s.beginTransaction();
NiGuAn niguan=new NiGuAn();
niguan.setId(13); //删除13号 尼姑庵,并且将其关联的所有的尼姑删除
s.delete(niguan);
tx.commit(); }finally{
HibUtil.closeSession();
} }
//在 NiGuAn.hbm.xml 中 添加
<bag name="niguList" cascade="delete" > //这里指明要级联删除
<key column="niguan_id" />
<one-to-many class="NiGu" />
</bag>

运行发现.它生成两条sql语句

Hibernate: update NiGu set niguan_id=null where niguan_id=?

Hibernate: delete from NiGuAn where id=?

可以看到,并没有真正的级联删除

//真正的级联删除
public static void delNiGuAn(){
try{
Session s=HibUtil.getSession();
Transaction tx= s.beginTransaction();
NiGuAn niguan =(NiGuAn) s.get(NiGuAn.class, 11); //要把主对象查询出来再删除
s.delete(niguan);
tx.commit();
}
}

三、inverse 关键字

inverse 关键字 表示是否放弃关联关系,(在java对象上建立关联的时候,对数据库产生的影响)

在 one-to-manay 和 many-to-many 这两个集合中定义,在 many -to -one 中不可以

inverse = true  表示对象不维护关联关系

维护 one-to-manay 的时候就是更新外键

维护 many-to-many  就是往中间表里添数据

例如: 多对多映射中

<set name="teacherList" table= "teacher_student" inverse="true" >  //让学生放弃关联关系的维护
<key column="student_id" />
<many-to-many class="Teacher" column="teacher_id" />
</set>

在Many2Many 的save方法中,写上下面的内容,也不会出错 ,因为学生已经放弃了关联关系,它不会再产生sql语句了

 //////////////////////
stu1.setTeacherList(teacherList);
stu2.setTeacherList(teacherList);
//////////////////////

说明:它不允许在多对一映射的时候,在多的一方,放弃关联关系。

四、懒加载

public static NiGuAn  search2(){
try{
Session s=HibUtil.getSession();
NiGuAn niguan= (NiGuAn) s.get(NiGuAn.class, 4);
Hibernate.initialize(niguan.getNiguList()); //因为它默认是用懒加载的
return niguan; }finally{
HibUtil.closeSession();
}
}

如果默认想不使用懒加载可以在配置文件中

NiGuAn.hbm.xml 中

 <bag name="niguList"  lazy="false" >
<key column="niguan_id" />
<one-to-many class="NiGu" />
</bag> //默认:
<bag name="niguList" >
<key column="niguan_id" />
<one-to-many class="NiGu" />
</bag> //相当于
<bag name="niguList" lazy="true" fetch="select" > // fetch 抓取策略
<key column="niguan_id" />
<one-to-many class="NiGu" />
</bag>

fetch="select" 它的另一个取值是 join  ,如果  fetch="join" 则它是以关联查询的方式查询数据,即始 lazy="true" 它也能把从对象的数据查询出来

五、缓存的模拟

public class CacheDemo {
private static Map userCache=new HashMap(); //缓存容器 public static Userinfo getUserById(int id){
Userinfo userInfo =null; //先到缓存中去查询用
String key=Userinfo.class.getName()+id;
userInfo=(Userinfo)userCache.get(key); //如果缓存中没有查到,就去数据库中查
if(userInfo==null){
userInfo=(Userinfo) HibUtil.get(Userinfo.class, id);
userCache.put(key,userInfo);
System.out.println("从数据库中查的");
}
else{
System.out.println("命中缓存 ,从缓存中查的");
} return userInfo;
} //在进行update的时候对缓存进行更新
public static void update(Userinfo user){
HibUtil.update(user);
String key=Userinfo.class.getName()+user.getId();
// userCache.remove(key); //把对应的对象从缓存中移除
userCache.put(key, user) ; //也可以这样,以新换旧,也可以
} //在删除的时候对缓存进行更新
public static void delete(Userinfo user){
HibUtil.del(user);
String key=Userinfo.class.getName()+user.getId();
userCache.remove(key); //移除
} //在添加的时候对缓存进行更新
public static void add(Userinfo user){
HibUtil.add(user);
String key=Userinfo.class.getName()+user.getId();
userCache.put(key, user);
} public static void main(String[] args) {
getUserById(101); //从数据库中查的
getUserById(101); //命中缓存 ,从缓存中查的
Userinfo user= getUserById(101); //命中缓存 ,从缓存中查的
user.setUserName("这是换过之后的名字");
HibUtil.update(user); //更新用户信息 Userinfo user2=getUserById(101); //命中缓存 ,从缓存中查的
System.out.println(user2.getUserName()); //这是换过之后的名字 getUserById(101); //命中缓存 ,从缓存中查的
}
}

六、Hibernate 的一级缓存

Hibernate 中的缓存有两种, 一级缓存,二级缓存

一级缓存 Session 范围内的

二级缓存 SessionFactory 范围内的

//例 一
public static void test(){
Session s=HibUtil.getSession(); Userinfo user=(Userinfo) s.get(Userinfo.class, 1); //会添充一级缓存
Userinfo user2=(Userinfo) s.get(Userinfo.class, 1);
Userinfo user3=(Userinfo) s.get(Userinfo.class, 1);
Userinfo user4=(Userinfo) s.get(Userinfo.class, 1); s.close(); //可以发现,最后只输出一条sql语句,因为后面的都是从一级缓存中取的
}

关于一级缓存的说明

1) 它的 key Userinfo.class+id

2) 一级缓存是 Session范围的,生命周期短,不实用

3) save ,update ,saveOrUpdate,load,get,list,lock,iterator 等方法都会把对象添到一级缓存中

4) 可以用  Session 的 evict,  clear 等方法清除一级缓存

s.evict(user)  //接收参数,只请一个

s.clear();  //不用传参.会把所有的都清掉

5) 一级缓存不能控制缓存对象的个数,所以有大量操作的时候,可能会造成内存溢出,要注意处理

for(int i=0;i<910000000;i++){
if(i%1000==0){
s.flush(); //同步一级缓存中的数据到数据库中
s.clear();
}
s.save(useri ...)
}

七、Hibernate 的二级缓存

SessionFactory 范围的

Hibernate 把缓存交给别的缓存框架实现 (  有  对应的jar )

配置文件

hibernate.cache.use_second_level_cache   false  //是否合用二级缓存

## choose a cache implementation 请选择缓存提供者
#hibernate.cache.provider_class org.hibernate.cache.EhCacheProvider
#hibernate.cache.provider_class org.hibernate.cache.EmptyCacheProvider
hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider  //hibernate 默认使用
#hibernate.cache.provider_class org.hibernate.cache.TreeCacheProvider
#hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider
#hibernate.cache.provider_class org.hibernate.cache.SwarmCacheProvider

在hibernet中使用  EhCacheProvider 二级缓存

1) 导包 ehcache-1.2.3.jar

2) 配置主配置文件

<property name="hibernate.cache.use_second_level_cache">true</property>  //声明打开二级缓存,默认就是打开
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property> //指明缓存提供者
<property name="hibernate.generate_statistics">true</property> //生成关于缓存的统计信息
省略....
<class-cache usage="read-only" class="cat.beans.Userinfo"/>
//在后面加这句,指明哪个类使用二级缓存
//不写这句也可以 ,可以加在映射文件Userinfo.hbm.xml 中, <cache usage="read-write"/>

测试代码:

public class SecondCacheTest {
public static void main(String[] args) {
HibUtil.get(Userinfo.class, 1);
HibUtil.get(Userinfo.class, 1);
HibUtil.get(Userinfo.class, 2); //如果为null不会往缓存中放
HibUtil.get(Userinfo.class, 1);
HibUtil.get(Userinfo.class, 1);
HibUtil.get(Userinfo.class, 2); //得到统计信息
Statistics totalInfo=HibUtil.getSessionFactory().getStatistics();
System.out.println(totalInfo); System.out.println("二级缓存放入 "+totalInfo.getSecondLevelCachePutCount()+"次");
System.out.println("二级缓存命中 "+totalInfo.getSecondLevelCacheHitCount()+"次");
System.out.println("二级缓存msiss "+totalInfo.getSecondLevelCacheMissCount()+"次");
}
}

二级缓存放入 2次   //前题是查出来的对象都不为null

二级缓存命中 4次

二级缓存msiss 2次

正常来说,还要有缓存配置文件  ehcache.xml

<diskStore path="java.io.tmpdir"/>  //用来指定缓存的存放位置        <diskStore path="c:/cache/xxx"  />
... <defaultCache
maxElementsInMemory="10000" //内存中最多可以少多少个对象
eternal="false" //指定缓存是不是永不过期
timeToIdleSeconds="120" //指的是缓存在空闲时间(秒) 过期以后会被删除
timeToLiveSeconds="120" //指的是缓存对象一共存在的时间
diskPersistent="true" //指定jvm 结束的时候是不是要把缓存存到磁盘上
overflowToDisk="true" //超出个数(maxElementsInMemory 指定的) 以后,是不是往磁盘上存
diskExpiryThreadIntervalSeconds ="60" //清除过期缓存的线程的轮循时间
/>

关于二级缓存的说明

1) 哪些方法可以填充二级缓存

get  , save (它不适合于native 主键的类 ,因为这样的主键,不把数据存到数据库的时候是得不到的,所以没有办法生成key,但 uuid,hilo 都可以)

update,saveOrupdate, get, load,list,iterator ,以及 Query,Cirteria 都会填充二级缓存。

但查询的时候,只有 session iterator ,get,load 会从二级缓存中取数据。

iterator 可能会存在 N+1 查询的问题

Query,Cirteria 缓存的命中率比较低, 在hibernate默认是关闭 ,因为它的查询条件复杂,而且缓存的数据量大

可以用

<property name="hibernate.cache.use_query_cache">true</property>  // 可以打开Query,Cirteria 查询的二级缓存支持

2) 清除二级缓存

HibUtil.getSessionFactory().evict(Userinfo.class,1);   //清id为1的 Userinfo 对象的缓存
HibUtil.getSessionFactory().evict(Userinfo.class,); //清除所有的 Userinfo 对象的缓存 //注意:它没有清除所有的缓存的方法

3) 关于Query 的缓存

public static void main(String[] args) {
QueryCacheTest(1);
QueryCacheTest(1);
QueryCacheTest(1); // ...打印缓存命中信息 public static UserInfo QueryCacheTest(int id){
Session s=HibUtil.getSession();
Query q=s.createQuery("from UserInfo as u where u.id="+id); //它会把查询条件当做Key
q.setCacheable(true); //注意要有这句
UserInfo u=(UserInfo)q.uniqueResult(); s.close();
return u;
}

说明,Query q=s.createQuery("from UserInfo as u where u.id="+id)  这种,它会把查询条件当做key,把 usersId 列表做为一个key

然后再根据key中的 user id 去缓存中找 UserInfo的信息,最差的情况是它失效了,如果有一百个id 就会去数据库中找一百次。

Java框架之Hibernate(三)的更多相关文章

  1. java框架篇---hibernate入门

    Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库. Hibernate可以应用在任何使用JDB ...

  2. Java框架之Hibernate(一)

    一.Hibernate - 核心接口 它是  JBoss Community team (社区团队) 开发的.Hibernate 是一个开源的,对象关系模型框架 (ORM),它对JDBC进行了轻量的封 ...

  3. java框架之Hibernate(2)-持久化类&主键生成策略&缓存&事务&查询

    持久化类 概述 持久化:将内存中的对象持久化到数据库中的过程就是持久化.Hibernate 就是用来进行持久化的框架. 持久化类:一个 Java 对象与数据库的表建立了映射关系,那么这个类在 Hibe ...

  4. java框架篇---hibernate之缓存机制

    一.why(为什么要用Hibernate缓存?) Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数 ...

  5. Java框架之Hibernate(四)

    本文主要介绍: 1 悲观锁和乐观锁 2 使用版本号控制并发访问 3 flush方法和批量更新的问题 4 DetachedCriteria 5 N + 1 次查询 6 使用sql进行查询 7 注解方式 ...

  6. Java框架之Hibernate(二)

    本文主要介绍: 1 Criteria 接口 2 用 myeclipse 反向生成 3 hibernate  主键生成策略 4 多对一 5 一对多 6 使用List 集合的一对多 7 多对多 一.Cri ...

  7. SSH框架之-hibernate 三种状态的转换

    一.遇到的神奇的事情 使用jpa操作数据库,当我使用findAll()方法查处一个List的对象后,给对这个list的实体进行了一些操作,并没有调用update 或者 saveOrUpdate方法,更 ...

  8. JAVA框架之Hibernate框架的学习步骤

    首先介绍一下Java三大框架的关系 以CRM项目即客户关系管理项目示例 hibernate框架的学习路线: 1.学习框架入门,自己搭建框架,完成增删改查的操作 2.学习一级缓存,事物管理和基本查询 3 ...

  9. java框架之Hibernate(1)-简介及初使用

    简介 hibernate 是一个开源 ORM ( Object / Relationship Mipping ) 框架,它是对象关联关系映射的持久层框架,它对 JDBC 做了轻量级的封装,而我们 ja ...

随机推荐

  1. HDU 1908 Double Queue(set)

    Problem Description The new founded Balkan Investment Group Bank (BIG-Bank) opened a new office in B ...

  2. Cairo-Dock 系统关机无效

    正文 背景 Cairo-Dock 设置为开机自己主动启动后.系统菜单条里的关机选项就无效了,命令行里能够使用命令关机. 搜索过程 这次google找到的结果让我非常失望,于是仅仅好百度了. 在百度贴吧 ...

  3. Machine Learning - XV. Anomaly Detection异常检測 (Week 9)

    http://blog.csdn.net/pipisorry/article/details/44783647 机器学习Machine Learning - Andrew NG courses学习笔记 ...

  4. Swift开发教程--使用Storyboard进行界面跳转

    使用storyboard结合代码来做确实能够给开发带来非常多的便利. 在实践的过程中,我们常常会遇到界面的跳转问题. 通过控件和界面的建立的"连接"就能够了. 假设是navigat ...

  5. Bayan 2015 Contest Warm Up D题(GCD)

    D. CGCDSSQ time limit per test 2 seconds memory limit per test 256 megabytes input standard input ou ...

  6. 在应用中更新App版本号

    在应用中, 为了提高用户体验, 会提供更新版本号的功能. 那么怎样实现呢? 我写了一个简单的Demo, 说明一下, 须要注意几个细节. 使用了Retrofit和Rx处理网络请求. Github下载地址 ...

  7. java并发编程的艺术——第一章总结

    并发编程的挑战 1.1上下文切换 1.2死锁 1.3资源限制的挑战 1.4本章小结 1.1上下文切换 1.1.1多线程一定快吗 1.1.2测试上下文切换次数和时长 1.1.3如何减少上下文切换 1.1 ...

  8. idea 配置热部署

    1. 2.

  9. 虚拟机修改静态ip

    1.设置虚拟机的网络选择方式,使用NAT模式,选择这个模式后网段与主机的网段不是一个网段,一般选择桥接模式 2.选择VMnet8, 去掉 使用本地DHCP服务将ip分配给虚拟机 这个选项,不然设置ip ...

  10. Android查缺补漏--ContentProvider的使用

    ContentProvider (内容提供者)是一种共享型组件,可以为系统内应用于与应用之间提供访问接口. ContentProvide要想正常工作需要三个关键点: ContentProvider:对 ...