session对象是操作数据库的主要接口,可以对数据库进行保存、更新和删除等一系列的操作,并且可以将数据库中的数据加载到java对象中。
session对象中有一个缓存,是session级别的,也称之为一级缓存。缓存中存储的java对象被称之为持久化对象。持久化对象和数据库中的相关记录相互对应。
看一段代码:
private SessionFactory sessionFactory;
private Session session;
private Transaction transaction;
@Before
public void onLoad() {
// 0.创建configuration对象,该对象保存着hibernate的配置信息和对象关系映射的信息。
Configuration cfg = new Configuration().configure();
// 1.创建sessionfactory对象
StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder()
.applySettings(cfg.getProperties());
StandardServiceRegistry registry = builder.build();
sessionFactory = cfg.buildSessionFactory(registry);
// 2.创建session对象
session = sessionFactory.openSession();
// 3.开始事务
transaction = session.beginTransaction();
}
@After
public void onUnLoad() {
// 1.提交事务
transaction.commit();
// 2.关闭session对象
session.close();
// 3.关闭sessionfactory对象
sessionFactory.close();
}
@Test
public void test() {
User user = (User)session.load(User.class, 1);
System.out.println(user);
// 第二次get时,是从session cache中获得的。
User user2 = (User)session.load(User.class, 1);
System.out.println(user2);
}
可以看到从数据库中查询了2次user对象,只输出了一条sql语句。第二次的get操作实际上是从缓存中获得的user对象,并没有从对数据库进行select查询。缓存减少了对数据库的操作。
缓存与数据库之间可以通过某些方法互相同步,session可以提取缓存中的对象向数据库进行操作,也可以将提取数据库中的记录来更新缓存中的对象。还可以对session缓存进行清空。
常用的操作session缓存的方法有3个,它们分别是:
flush
当调用flush方法时,session将保证缓存中的对象与数据表中的记录一致。也就是说,若缓存中的对象与数据库表中的记录不一致,则会发送update语句更新数据库。
若不显示调用flush方法,当事务进行commit的时候会自动的调用一次flush方法。
当然也有例外,在同一个事务中使用QBC或HQL语句也会隐士调用一次flush方法。
refresh
当调用refresh方法时,其实与flush大致相反。若缓存中的对象与数据库表中的记录不一致,则会发送一个select语句来更新session缓存中的对象。
clear
当调用clear的时候,将清空session缓存中的对象。
进行一些测试,来测试一下这几个方法,首先是flush方法:
@Test
public void testSessionFlush() {
// 从数据库中加载一个对象。
User user = (User)session.get(User.class, 1);
user.setName("Kobe");
System.out.println(user);
}
数据库中的保存的Name是"Jack"这个值,get到User对象后,进行一次set,然后commit后会发现生成了一条update语句,数据库中的值也改变了,这就是flush方法起到的作用,控制台输出如下图:
接下来测试一下refresh方法,写一段代码:
@Test
public void testSessionRefresh() {
User user = (User)session.get(User.class, 1);
System.out.println(user);
session.refresh(user);
User user2 = (User)session.get(User.class, 1);
System.out.println(user);
}
在session.refresh(user)处打一个短点,在程序暂停后,去数据库中手动修改name字段的值,在调用refresh方法后看看是否数据库的值会更新缓存中对象的值,操作过程如下:
程序运行到refresh方法之前,进行一次get,并且进行了输出。可以看到控制台输出了select和user的值。之后进入断点等待继续。
手动修改了数据库中name字段的值,将"Kobe"改成了"Mark"。
断点向下一步,执行了refresh,可以看到控制台又输出了一条select语句。说明对手动修改了数据库中的数据后,与session缓存中的对象不一致了。需要获取数据库中的数据对持久化对象进行覆盖。于是执行了一次select语句。
最后输出结构,这里可以看到虽然执行了select语句,但是并没有改变持久化对象中的数据。这是由于hibernate的事务隔离机制导致的。一共有4个隔离级别,分别是:
READ UNCOMMITED = 1
READ COMMITED = 2
REPEATABLE READ = 4
SERIALIZEABLE = 8
可以在配置文件中将隔离级别hibernate.connection.isolation设置成2,这样refresh就会有预期的效果。
<!-- 设置hibernate的事务隔离机制 -->
<property name="hibernate.connection.isolation">2</property>
设置后在进行一次测试,结果如下:
当改变隔离级别后,先修改数据库的值,在调用refresh方法,则会立即更新持久化对象。
最后测试一下clear方法,该方法会清空session的缓冲区:
@Test
public void testSessionClear() {
User user = (User)session.get(User.class, 1);
session.clear();
User user2 = (User)session.get(User.class, 1);
}
最初测试session缓存时,在一个事务中第二次调用get方法加载同一个对象,不会发送select语句到数据库进行查询。而在第二次调用get方法前,调用一次clear方法,则会清空session缓冲区中的持久化对象,在次调用get又需要到数据库进行select操作,控制台输出的sql如下:
可以看到有两个select语句被打印,证明了clear会清空缓冲区中的持久化对象。
以上就是常用的操作session缓冲区的三个方法的测试。