1.Session的缓存
只要Session实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。
1.1.Session缓存的作用
(1)减少访问数据库频率;
(2)当缓存中的持久化对象之间存在循环关联关系时,Session会保证不出现访问对象图的死循环,以及由死循环引起的JVM堆栈溢出异常;
(3)保证数据库中的相关记录与缓存中的相应对象保持同步。
1.2.清理缓存机制
当Session缓存中对象的属性每次发生了变化,Session并不会立即清理缓存以及执行相关的SQL update语句,而是在特定的时间点才清理缓存。
默认情况下,Session会在以下时间点清理缓存:
(1)应用程序调用Transaction的commit()方法;
(2)应用程序执行一些查询操作时,若缓存中持久化对象的属性已发生变化,会清理缓存,保证查询结果正确;
(3)应用程序显式调用Session的flush()方法。
Transaction的commit()方法与Session的flush()方法的区别:
flush()方法进行清理缓存的操作,执行一系列的SQL语句,但不会提交事务;commit()方法会先调用flush()方法,然后提交事务。
例外情况:
若对象使用native生成器来生成OID,当调用Session的save()方法保存该对象时,会立即执行insert语句。
若不想Session在默认的时间点清理缓存,可以通过Session的setFlushMode()方法显式设定清理缓存的时间点。
三种清理模式:
模式 各种查询方法 Transaction的commit() Session的flush()
FlushMode.AUTO(默认) 清理 清理 清理
FlushMode.COMMIT 不清理 清理 清理
FlushMode.NEVER 不清理 不清理 清理
2.Java对象在Hibernate持久化层的状态
临时状态(transient):刚用new语句创建,还没有被持久化,并且不处于Session缓存中;
持久化状态(persistent):已被持久化,并且加入到Session的缓存中;
游离状态(datached):已被持久化,但不处于Session缓存中;
删除状态(removed):不处于Session缓存中,并且Session已经计划将其从数据库中删除;
同一个Session实例的缓存,数据库表中的每条记录只对应唯一的持久化对象。
3.Session接口的用法
3.1.Session的save()和persist()方法
Session的save()和persist()方法均使一个临时对象转变为持久化对象,并计划执行一条insert语句。
Customer customer = new Customer();
customer.setId(new Long(9));
customer.serName("Tom");
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.save(customer); //计划执行insert
tx.commit(); //真正执行insert
session.close();
若使用代理主键(如increment)而非自然主键的情况下,setId()方法为临时变量设置OID是无效的。
save()方法并不会立即执行insert语句,只有当Session清理缓存时,才会执行insert语句。
save()方法是用来持久化一个临时变量的,不应该把持久化对象或游离对象传递给save()方法,否则会使操作多余,或导致数据库表中存在多条代表相同业务实体的记录。
Customer customer = new Customer();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTranasaction();
session.save(customer);
customer.setName("Tom");
session.save(customer); //多余操作
tx.commit();
Customer customer = new Customer();
customer.setName("Tom");
Session session1 = sessionFactory.openSession();
Transaction tx1 = session1.beginTranasaction();
session1.save(customer); //ID为1
tx1.commit();
session1.close(); //Customer对象变为游离对象
Session session2 = sessionFactory.openSession();
Transaction tx2 = session2.beginTranasaction();
session2.save(customer); //ID为2
tx2.commit();
session2.close();
persist()与save()的不同之处:
persist()方法不保证立即为持久化对象的OID赋值,而是可能在Session清理缓存时才为OID赋值;
如果在事务边界以外调用persist()方法,那么该方法不会计划执行insert语句。
3.2.Session的load()和get()方法
Session的load()和get()方法都能根据给定的OID从数据库中加载一个持久化对象,但当数据库中不存在与OID对应的记录时,load()方法抛出ObjectNotFoundException,get()方法返回null。
load()方法会根据<class>元素的lazy属性值"true"或"false"(默认为"true"),采取延迟或立即检索策略,get()总是采用立即检索策略。
3.3.Session的update()方法
Session的update()方法使一个游离对象转变为持久化对象,并计划执行一条update语句。
Customer customer = new Customer();
customer.setName("Tom");
Session session1 = sessionFactory.openSession();
Transaction tx1 = session1.beginTranasaction();
session1.save(customer);
tx1.commit();
session1.close(); //Customer对象变为游离对象
Session session2 = sessionFactory.openSession();
Transaction tx2 = session2.beginTranasaction();
customer.setName("Jack");
customer.serName("Linda");
session2.update(customer); //计划执行update
tx2.commit(); //真正执行update
session2.close();
Session只有在清理缓存时才会执行update语句。即使程序中多次修改了对象的属性,在清理缓存时也只会执行一次update语句。
只有通过update方法使游离对象被一个Session关联,即使没有修改该对象的任何属性,Session在清理缓存时也会执行update语句。
如果希望Session仅当修改了对象的属性时,才执行update语句,可以把<class>元素的select-before-update设为true。
3.4.Session的saveOrUpdate()方法
Session的saveOrUpdate()方法同时包含了save()与update()方法的功能,如果传入的参数是临时变量,就调用save()方法;如果传入的参数是游离对象,就调用update()方法;如果传入的是持久化对象,就直接返回。
3.5.Session的delete()方法
Session的delete()方法用于从数据库中删除一个对象。
Session只有在清理缓存时才会执行delete语句。
Session的delete()方法一次只能删除一个对象。
3.6.Session的merge()方法
Session的merge()方法能够把一个游离对象的属性复制到一个持久化对象中。
3.7.Session的replicate()方法
Session的replicate()方法能够把一个数据库中的对象复制到另一个数据库中。
session.replicate(object,ReplicationMode.LATEST_VERSION);
第二个参数决定复制模式:
ReplicationMode.IGNORE:若目标数据库存在OID相同的对象,就什么也不做;
ReplicationMode.OVERWRITE:若目标数据库中存在OID相同的对象,就覆盖已存在的对象;
ReplicationMode.EXCEPTION:若目标数据库中存在OID相同的对象,就抛出异常;
ReplicationMode.LATEST_VERSION:若目标数据库中存在OID相同的对象,就比较两者的版本,保存新版本的数据。
4.操作级联对象
对象-关系映射文件中,用于映射持久化类之间关联关系的元素,如<set>、<many-to-one>等,都有一个cascade属性,用来指定如何操作与当前对象关联的其他对象。
cascade属性值:
none cascade的默认值,Session操作当前对象时,忽略其他关联对象;
save-update 通过Session的save()、update()、saveOrUpdate()方法保存或更新当前对象时,级联保存所有与之关联的
临时对象,级联更新所有与之关联的游离对象;
persist 通过Session的persist()方法保存当前对象时,级联保存所有与之关联的临时对象;
merge 通过Session的merge()方法融合当前对象时,级联融合所有与之关联的游离对象;
delete 通过Session的delete()方法删除当前对象时,级联删除所有与之关联的对象;
lock 通过Session的lock()方法把当前游离对象加入到Session缓存中时,把所有与之关联的游离对象也加入
到Session缓存中;
replicate 通过Session的replicate()方法复制当前对象时,级联复制所有与之关联的对象;
evict 通过Session的evict()方法从Session缓存清除当前对象时,级联清除所有与之关联的对象;
refresh 通过Session的refresh()方法刷新当前对象时,级联刷新所有与之关联的对象;
all 包含save-update、persist、merge、delete、lock、replicate、evict及refresh的行为;
delete-orphan 删除所有与当前对象解除关联关系的对象;
all-delete-orphan 包含all和delete-orphan的行为。
5.更新数据库对象的两种方式
(1)先加载持久化对象,修改持久化对象的属性,然后Session清理缓存时自动同步更新数据库中的相应数据:
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Customer customer = (Customer)session.get(Customer.class,new Long(9));
customer.setName("Jack"); //修改name属性
tx.commit(); //更新数据库
session.close(); //customer变为游离对象
(2)更新游离对象,然后通过Session的update()方法更新数据库中的相应数据:
Customer customer = ... //假定customer为游离对象
customer.serName("Tom");
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.update(customer); //计划执行update
tx.commit(); //真正执行update,更新数据库
session.close();