session对象是操做数据库的主要接口,能够对数据库进行保存、更新和删除等一系列的操做,而且能够将数据库中的数据加载到java对象中。java
session对象中有一个缓存,是session级别的,也称之为一级缓存。缓存中存储的java对象被称之为持久化对象。持久化对象和数据库中的相关记录相互对应。sql
看一段代码:
数据库
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
经常使用的操做session缓存的方法有3个,它们分别是:app
flush测试
当调用flush方法时,session将保证缓存中的对象与数据表中的记录一致。也就是说,若缓存中的对象与数据库表中的记录不一致,则会发送update语句更新数据库。ui
若不显示调用flush方法,当事务进行commit的时候会自动的调用一次flush方法。hibernate
固然也有例外,在同一个事务中使用QBC或HQL语句也会隐士调用一次flush方法。
code
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缓冲区的三个方法的测试。