Session接口的基础知识
Session接口时Hibernate5中的核心接口,Session对象是Hibernate5技术的核心,持久化对象的生命周期、事务的管理及持久化对象的增加、修改和删除都是通过Session对象来完成的。Hibernate5在操作数据库之前必须先取得Session对象。
Session对象不是线程安全的,一个Session对象最好只由一个单一线程来使用。同时该对象的生命周期要比SessionFactory短,其生命通常在完成数据库中一个短暂的系列操作之后结束。一个应用系统中可以自始自终只有一个SessionFactory对象。Session对象通过SessionFactory对象的getCurrentSession()或者openSession()方法获取,代码如下:
Configuration cfg=new Configuration().configure("hibernate.cfg.xml");
SessionFactory sf=cfg.buildSessionFactory();
Session session=sf.openSession()
获取Session对象后,Hibernate5内部并不会立即获取操作数据库的java.sql.Connection对象,而是等待Session对象真正需要对数据库进行增、删、改、查等操作时,才会从数据库连接池中的获取Connection对象。
Session类在定义上与普通的JavaBean类没有区别,但他也有独特的方法,其方法按用途可分为以下5类:
- 获取持续化对象:get()和load()等方法。
- 持久化对象的保存、更新和删除:save()、update()、saveOrUpdate()和delete()等方法。
- createQuery()方法:用来从Session生成Query对象。
- beginTransaction()方法:用来从Session生成Transaction对象。
- 管理Session的方法:isOpen()、flush()、clear()、evict()和close()等方法。其中isOpen()方法用来检查Session是否仍然打开;flush()方法用来清理Session缓存,并把缓存中的SQL语句发送出去;clear()方法用来清除Session中的所有缓存对象;evict()方法用于清除Session缓存中的某个对象;close()方法用来关闭Session。
通过方法获取持久化对象
获取持久化对象的方法只要有两种:get()方法和load()方法,它们都是通过主键id来获取持久化对象的。
1、使用get()方法获取持久化对象
例如:
public Object get(Class className,Serializable id)
className是类名,id是对象的主键,如果id的类型是int,可通过new Integer(id)的方法生成一个Integer对象。
以下代码是获取一个主键id为66的UserInfoPO对象:
UserInfoPO ui=(UserInfoPO)session.get(UserInfoPO.class,new Integer(66));
get()方法获取持久化对象时的执行过程如下:
- 通过id在Session缓存中查找对象,如果存在与id主键-值对应的对象,直接将其返回;
- 如果在Session缓存中没有查询到对应的对象,则在二级缓存中查找,找到后将其返回;
- 如果在前两个步骤的操作中都没有找到该对象,则从数据库中加载拥有此id的对象;
从上面步骤可以看出,get()方法并不总是发送SQL语句查询数据库,只有缓存中无此数据时,才向数据库发送SQL语句获取数据。
2、使用load()方法获取持久化对象
基本作用和get()方法差不多,其主要区别如下:
(1)、当立即加载PO时,如果对象存在,get()方法和load()方法没有区别,他们都可以取得已初始化的对象;但当对象不存在且是立即加载时,get()方法返回null,而load()方法则弹出一个异常。因此使用load()方法时,要确认查询的主键id一定是存在的。
(2)、当延迟加载对象时,get()方法仍然使用立即加载的方式发送SQL语句,并得到已初始化的对象,而load()方法则根本不发送SQL语句,它返回一个代理对象,这个对象直接被访问使用时才被初始化。
操作持久化对象的常用方法
1、使用save()方法操作持久化对象
使用save()方法可将一个持久化对象的属性取出放入PreparedStatement(具有预编译功能的SQL类)语句中,然后向数据库表中插入一条记录。下面的代码把一个新建UserInfoPO对象持久化到数据库中,即把一条记录插入到数据库中。
UserInfoPO ui=new UserInfoPO();
ui.setID(66); //为对象设定一个id值
Session session=sf.openSession(); //打开Session
Transaction tx=session.beginTransaction(); //开启事务
session.save(ui); //调用save()方法保存数据
tx.commit(); //提交事务
session.close(); //关闭Sessioon
当Session保存一个持久化对象时,按照如下步骤进行操作
(1)、根据映射文件中的配置为主键id设置生成算法,为info指定一个id。
(2)、将UserInfoPO对象存入Session对象的内部缓存中。
(3)、当事务提交时,清理Session对象缓存中的数据,并将新对象通过Hibernate5框架生成的insert into语句持久化到数据库中。
在调用save()方法时,并不立即执行SQL语句,而是等到清理完缓存后在执行。如果在调用save()方法后又修改了UserInfoPO的属性,则Hibernate5框架将会发送一条insert into语句和一条update语句来完成持久化操作。
UserInfoPO ui=new UserInfoPO();
ui.setID(66); //为对象设定一个id值
ui.setUserName("李想一"); //设定用户名的值
Session session=sf.openSession(); //打开Session
Transaction tx=session.beginTransaction(); //开启事务
session.save(ui); //调用save()方法保存数据
ui.setUserName("李想二"); //设定用户名的值
tx.commit(); //提交事务
session.close(); //关闭Sessioon
因此,最好是在对象状态稳定(即属性不再发生变化)时在调用save()方法,这样可以少执行一条update语句。
2、使用update()方法操作持久化对象
Session的update()方法可以用来更新脱管对象到持久化对象。
UserInfoPO ui=new UserInfoPO();
Session session=sf.openSession(); //打开Session
Transaction tx=session.beginTransaction(); //开启事务
ui=(UserInfoPO)session.get(UserInfo.class,new Integer(66));
ui.setUserName("李想");
session.update(ui); //更新脱管对象
tx.commit(); //提交事务
session.close(); //关闭Sessioon
使用update()方法时,HIbernate5框架并不会立即发送SQL语句,而是将对象的更新操作积累起来,在事务提交时由flush()清理缓存,并发送一条SQL语句完成全部更新操作。
3、使用saveOrUpdate()方法操作持久化对象
对脱管对象使用save()方法是不对的,对临时对象使用update()方法也是不对的,所以为了解决这个问题,便产生了saveOrUpdate()方法。
UserInfoPO ui=new UserInfoPO();
ui.setId(66);
Session session=sf.openSession(); //打开Session
Transaction tx=session.beginTransaction(); //开启事务
ui=(UserInfoPO)session.get(UserInfo.class,new Integer(66));
session.saveOrUpdate(ui); //使用方法保存数据
tx.commit(); //提交事务
session.close(); //关闭Sessioon
4、使用delete()方法操作持久化对象
Sessiondedelete()方法负责删除一个对象(包括持久化对象和脱管对象)。
UserInfoPO ui=new UserInfoPO();
Session session=sf.openSession(); //打开Session
Transaction tx=session.beginTransaction(); //开启事务
ui=(UserInfoPO)session.get(UserInfo.class,new Integer(66));
session.delete(ui); //删除持久化对象
tx.commit(); //提交事务
session.close(); //关闭Sessioon
使用delete()方法删除对象时,会出现一些性能上的问题。例如从以上代码中可以看出,当删除一个对象时,先调用get()方法加载这个对象,然后调用delete()方法删除对象,但此过程发送了一条select和delete语句。实际上select语句是不必要的,这种情况在批量删除时尤为明显。为了解决批量删除时产生的性能问题,常用的方法是使用批量删除操作。
UserInfoPO ui=new UserInfoPO();
Session session=sf.openSession(); //打开Session
Transaction tx=session.beginTransaction(); //开启事务
Query q=session.createQuery("delete from UserInfoPO"); //使用HQL语句进行删除
q.executeUpdate(); //删除对象
tx.commit(); //提交事务
session.close(); //关闭Sessioon