第七八九十章文档.docx
- 文档编号:29565322
- 上传时间:2023-07-24
- 格式:DOCX
- 页数:14
- 大小:22.14KB
第七八九十章文档.docx
《第七八九十章文档.docx》由会员分享,可在线阅读,更多相关《第七八九十章文档.docx(14页珍藏版)》请在冰豆网上搜索。
第七八九十章文档
上周问题回顾2
7第7章2
7.1Java对象在JVM中的生命周期2
7.2理解Session的缓存3
7.3Hibernate应用中Java对象的状态4
7.3.1临时对象的特征4
7.3.2持久化对象的特征4
7.3.3游离对象的特征5
7.4.1Session的save()方法5
7.4.2Session的update()方法6
7.4.3Session的saveOrUpdate()方法8
7.4.4Session的load()和get()方法8
7.4.5Session的delete()方法8
7.5级联操纵对象图9
7.5.1级联保存临时对象9
7.5.2更新持久化对劲象9
7.5.3持久化临时对象9
7.5.4更新游离对象9
7.5.5遍历对象图9
7.6与触发器协同工作9
7.7利用拦截器(Interceptor)生成审计日志9
上周问题回顾
●说明为什么类属性的类型表达同一数据时,在基本类型与包装类型中优选择包装类型?
例如1不用long而用Long表示?
●当主键生成方式定义为native时,在oracle中默认取的序列名字是什么?
●一个客户对应多个订单,客户表A定单表B,从A表看向B表,是一对多单向关系还是多对一单向关系?
●hibernate当用load方法取数据时hibernate可以直接访问持久化类的set属性吗?
●多对一能做级联删除吗?
●游离状态和临时状态区分?
●hibernate也是按内存地址还是标识符(OID)分配对象吗?
●sequece的用法和native比较各有什么好处?
●派生属性,数据库里面有对应的字段吗?
●一对多能做级联删除吗?
7第7章
Session是Hibernate向应用程序提供的操纵数据库的主要接口,Session具有一缓存,位于缓存中的对象处于持久化状态,Session能够按照缓存中持久化对象的属性变化来同步更新数据库,这一过程被称为清理缓存.前面章节介绍了Hibernate持久化类对象的另两种状态:
临时状态和游离态,也就是说Hibernate持久化类对象有三种状态:
临时状态、持久化状态、游离状态。
本章主要介绍持久化类对象三种状态的转化,级联,hibernate与触发器协同工作,hibernate拦截器的用法。
7.1Java对象在JVM中的生命周期
●JVM:
java虚拟机,全称javavirtualmachine
Customerc=newCustomer(“Tom”,newHashSet());
Order1o1=newOrder(“Tom_order001”,null);
Order2o2=newOrder(“Tom_order002”,null);
O1.setCustomer(c);
c.getOrders().add(o1);
o1=null;-------------------c还的的集合属性还在引用o1,所以这之后Order1对象还没有结束生命周期(见示例:
testObjCyclemain.java)
o2=null;-------------------结束对象o2的生命周期
c=null;---------------------结束对象o1和c结束生命,o1结束生命周期是因为结束被引用
生命周期的结束亦味着对应内存的回收。
凡是用=连接某两个对象或初始化对象,那都是引用.
7.2理解Session的缓存
在hibernate中当用load()方法去加载某个对象时,首先是对Session中判断当前对象是否存在,如果存在就直接引用而不需要访问数据库,如果不存在才在数据加载。
Testtest1=newTest1();
Testtest2=null
Sessionsession=sessionFactory.openSession();
Transactiontx=null;
session.save(test1);
Longid=test1.getId();
test1=null;--------此时Test1对象还在
test2=(Test1)session.load(Test1.class,id);
System.out.println(test2);
mit();
if(session!
=null)session.close();
test2=null;此时Test对象结束生命周期,因为该对象结束被引用
注意:
本行代码自始至终只有一个Test1对象.所以test1和test2引用的都是同一个对象,开始生成一个Testtest1=newTest1()生成一个Test对象,通过session.save(test1)把session对象加入缓存,虽然有test1=null,结束test1的引用,但ssion缓存还在引用Test对象.test2=session.load(Test1.class,id)实质对应的是同一个对象,此时被test2引用.调用load(Test1.class,id)方法时,先根据id在缓存中查找没有当前标识相同的对象,如果则不检索数据,所以test2=session.load(Test1.class,id)没有检索数据,而是直接对Test对象进行引用.
Session缓存三大作用:
●减少访问数据库的频率.
●保证缓存中的对象与数据库中的相关记录保持同步.
●当缓存中的持久化对象之间存在循环关联关系时,Session会保证不出现访问对象图的死循环,以及由死循环引起的JVM堆栈溢出异常(OID的唯一性)
Session在清理缓存时,按照以下顺序执行sql语句.
●按照应用程序调用session.save()方法的先后顺序,执行所有对实体进行插入的insert语句
●执行所有对实体进更新的update语句
●执行所有对集合进行删除的delete语句
●执行所有对集合元素进行删除,更新或者插入的SQL语句
●执行所有对集合进行插入的insert语句
●按照应用程序调用session.delete()方法的先后顺序,执行所有对实体进行删除的delete语句
默认情况下,Session会在下面的时间点清理缓存.
●当用应程序调用Transaction的commit()方法的时侯,commit()方法先清理缓存,然后再向数据库提交事务
●当应用程序调用Session的find()和iterate()时,如果缓存中持久化对象的属性发生成了变化,就会清理缓存,以保证查询结果能反映持久化对象的最新状态.
●当应用程序显式调用Session的flush()方法的时侯
Flush与commit的区别,Flush清缓存,执行相应的SQL,但不提交对数据进行的操作。
Commit除了执行上面的sql同时也提交。
(见示例)
以下是通过Session的setFlushMode方法设定清理缓存的时间点:
清理缓存的模式
Session的查询方法
Session的commit()
Session的Flush()
FlushMode.AUTO
清理
清理
清理
FlushMode.COMMIT
不清理
清理
清理
FlushMode.NEVER
不清理
不清理
清理
7.3Hibernate应用中Java对象的状态
Hibernate持久化对象的三种状态:
●临时状态:
new语句创建,不在Session缓存中,没有被持久化。
●持久化状态:
已经被持久化,加入到Session的缓存中.
●游离状态:
已经被持久化但不处于Session的缓存中.
7.3.1临时对象的特征
临时对象的特征:
●不处于Session的缓存中,也可以说,不被任何一个Session实例关联
●在数据库中没有地对应的记录
在以下情况下,java对象进入临时状态:
●当通过new语句创建一个java对象,它处理临时状态,在数据库中没有对应记录
●Session的delete方法能使一个持久化对象或游离对象转变为临时对象,对于游离对象,delete()从数据库中删除对应记录;对于持久化对象,delete()方法从数据库删除对应记录并且把它从Session的缓存中删除.
7.3.2持久化对象的特征
持久化对象以下特征:
●位于Session的实例的缓存中,也可以说,持久化对象总是被一个Session实例关联.
●持久化对象和数据库中的相关记录对应
●Session在清理缓存时,会根据持久化对象的属性变化,来同步更新数据库.
●Session的许多方法都能触发java对象转变为持久化对象:
●Session的save()方法把临时对象转变化持久化对象.
●Session的load()和get()方法返回的都是持久化对象
●Session的find()的方法返回的List集合存放的都是持久化对象
●Session的update()、saveUpdate()和lock()方法都能使一个游离对象转化成一个持久化对象.
●当一个持久化对象关联一个到一个临时对象时,在级联保存时,Session在清理缓存时会把这个临时对象也转变为持久化对象
7.3.3游离对象的特征
游离对象以下特征:
●不再位于Session中,也就是 游离对象不被Session引用
●游离对象是持久化对象转变而来的,所以数据库中可能还在相关记录(这里说可能是因为,调用detete()方法后就没有相关记录)
游离对象和持久化对象都不被Session关联,游离对象是由于持久化对象转变过来的,临时对象在数据库没有对应记录.
Session的以下方法使持久化对象转变为游离对象:
●当用调Session的close()方法时,Session的缓存被清空,缓存中的所有持久化对象都变为游离对象.如果应用程序没有引用这个对象,它生命周期就结束.
●Session的evict()方法能够从缓存中删除一个持久化对角,使它变为游离状态.Session的保存更新删除和查询方法,有时Session对象过多会消耗资源,可以用evict()方法删除,但不推荐使用.
7.4.1Session的save()方法
把对象加入缓存中,使之变为持久化对象
如OID生成方式为非assigned方式,选用映射文件指定的标识符生成器为持久化对角分配唯一的OID.书中提到save(customer,newLong(9))不行,可能是hibernate去掉这个功能
Save()方法并不立即SQLinsert语句,而是清理缓存时执行,因此以下写法
session.save("1",test1);----insert的SqL已经形成
test1.setTestName("dssfds");---再次修改,形成修改的udpate的sql
test1=null;
mit();
带来如下后果:
Hibernate:
insertintoTSIOMS.TEST1(TEST_NAME1,TEST_NAME,TEST_NAME2,DATE_TIME,TEST_NAME3,TEST_CLOB,VERSION,ID)values(?
?
?
?
?
?
?
?
)
Hibernate:
updateTSIOMS.TEST1setTEST_NAME1=?
TEST_NAME=?
TEST_NAME2=?
DATE_TIME=?
TEST_NAME3=?
TEST_CLOB=?
VERSION=?
whereID=?
一个保存执行两个sql.
如下写法:
test1.setTestName("dssfds");
session.save("1",test1);
test1=null;
mit();
只会执行一个:
Hibernate:
insertintoTSIOMS.TEST1(TEST_NAME1,TEST_NAME,TEST_NAME2,DATE_TIME,TEST_NAME3,TEST_CLOB,VERSION,ID)values(?
?
?
?
?
?
?
?
).
●OID已经生成就不要更改,实际上hibernate不允许修改持久化对象的OID,如下:
test1.setTestName("dssfds");
session.save("1",test1);
test1.setId(newLong(100));
test1=null;
mit();
session.save("1",test1);OID已经生成,这时hibernate持久化对象的OID与数据库保持一一对应,test1.setId(newLong(100))作了修改,提交时就会抛出异常:
saveTest1()存储异常:
org.hibernate.HibernateException:
identifierofaninstanceofcom.starit.pojo.Test1wasalteredfrom122to100
●持久化对象和游离对象不应该传给save方法:
session.save(test1);
test1.setTestName("dssfds");
session.save(test1);
实际上只执行一个insert和一个update的sql.后面的session.save(test1)多余.
下面内容想把一个游离对象传给save()方法,导同一业执行两次插入,不合业务需求.
Sessionsession=sessionFactory.openSession();//session.load(Test1.class,newLong
(1));
Transactiontx=null;
tx=session.beginTransaction();
session.save(test1);
mit();
session.close();
Sessionsession1=sessionFactory.openSession();//session.load(Test1.class,newLong
(1));
Transactiontx1=null;
tx1=session1.beginTransaction();
session1.save(test1);
mit();
session1.close();
导致两个sql如下:
(从业务上来说,游离对象都是数据库里有过的数据就没必要再插入了。
)
Hibernate:
insertintoTSIOMS.TEST1(TEST_NAME1,TEST_NAME,TEST_NAME2,DATE_TIME,TEST_NAME3,TEST_CLOB,VERSION,ID)values(?
?
?
?
?
?
?
?
)
Hibernate:
insertintoTSIOMS.TEST1(TEST_NAME1,TEST_NAME,TEST_NAME2,DATE_TIME,TEST_NAME3,TEST_CLOB,VERSION,ID)values(?
?
?
?
?
?
?
?
)
7.4.2Session的update()方法
Update()使一个游离对象转变为持久化对象
●Update()把对象加入到缓存使之变成持久化对象
●计划执行一个update()语句.
Session在清理缓存时老会执行update()语句,在清理缓存时才把条件组装到update语句中,所以如下尽管调用update(),之后要调用set方法,但只执行一个update语句.
test2=(Test1)session.load(Test1.class,newLong(119));
此时test2已经是持久化对象了,session缓存中已经有了
test2.setTestName("333");
session.update(test2);
test2.setTestName("fff");
●书上提到下面这个内容:
Sessionsession1=sessionFactory.openSession();//session.load(Test1.class,newLong
(1));
Transactiontx1=null;
tx1=session1.beginTransaction(); session1.update(test2);
mit();
session1.close();
会执行update的sql,但这时没有修改,显得执行冗余,可以作如下配置
配置自动检测,也就是执行select进行比对,对象属性内容与数据一致才执行修改语句.当然这种设置有个毛病就是每次都要检查执行一个select,如果一个表数据会经常进行数据变更,这时这样设置就有个问题,每次修改不仅执行一个update语句,之前还要执行一个select语句,显得执行冗余,所以到底要不要设作这种设置看实际需求.
●下面:
test2=(Test1)session.load(Test1.class,newLong(119));
mit();
session.close();
Sessionsession1=sessionFactory.openSession();//session.load(Test1.class,newLong
(1));
Transactiontx1=null;
System.out.println(test2.getTestName());
tx1=session1.beginTransaction();
test3=(Test1)session1.load(Test1.class,newLong(119));
session1.update(test2);//缓存中已有一个119的test3,然后又加进来一个119的test2,当然有问题,不能保存OID的唯一性
mit();
session1.close();
会报错,原因是 test3,test2引用是两个不同的对象,但对应数据库里面的是同一条数据(注意这时必须是赖加载,否该实验失败),对应的OID是一样的,这不合符hibernate中持久化对象OID唯一性的要求.
7.4.3Session的saveOrUpdate()方法
saveOrUpdate()方法实质里面包含save()和update()方法,如果传入的参数是临时对象测调用save(),如果传入参数是游离对象,则调用update()方法.
满虽以下条件,hibernate把其作为临时对象:
●Java对象Oid取值为null
●Java对象有如下设置unsaved-value="null"
●在映射文件中为
●在映射文件中为version属性设置了unsaved-value属性,并且version属性取值与unsaved-value属性值匹配(这个当时测过,暂时没找到原因)
●自定义了Hibernate的Interceptor实现类,并且Interceptor的isUnsaved()方法返回Boolean.TRUE
7.4.4Session的load()和get()方法
Load()和get()方法都是通过OID从数据库加一个持久化对象.如果数据库存在当OID对应的记录,get()方法返回null,Load()则会抛出如下异常:
org.hibernate.ObjectNotFoundException:
Norowwiththegivenidentifierexist.
Load()和get()方法返回的对象都在Session中,因此清理缓存时,对返回对象的修改都会同步到数据库中.
7.4.5Session的delete()方法
只有当清理缓存时才会执行delete语句.
在调用delete()时,当传入参数是游离对象,对象Session关联转化为持久化对象,然后计划执行一个delete语句,如果传入参数为持久化对象Session就计划执行一个delete语句.当Session执行close()时才会从Session中删除该对象.
Sessionsession=sessionFactory.openSession();//session.load(Test1.class,newLong
(1));
Transactiontx=null;
tx=session.beginTransaction();
test2=(Test1)session.load(Test1.class,newLong(119));
System.out.println(test2.getTestName());
session1.delete(test2);----对持久化对象的操作
mit();
session.close();
Sessionsession1=sessionFactory.openSession();//session.load(Test1.class,newLong
(1));
Transactiontx1=null;
System.out.println(test2.getTestName());
tx1=session1.beginTransaction();
test3=(Test1)session1.load(Test1.class,newLong(119));
session1.delete(test2);----对游离对象的操作
mit();
session1.close();
7.5级联操纵对象图
Cascade属性值
描述
none
保存,更新,删除当前对象时,忽略其他关联对象,它是cascade属性的默认值
Save-update
当Session通过save(),update(),sav
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 七八 九十 文档