【Hibernate中的Session】
第一点申明, Hibernate的session和HTTP的session会话是两码事。Session是Java应用程序和Hibernate进行交互时使用的主要接口,也是持久化操作的核心。它提供了很多持久化的方法,如save update delete等。通过这些方法我们就可以透明的完成对象的增删改查CRUD。透明是指Session在读取,创建,和删除映射实体对象的实例时,这些操作将回被转换为数据库表中数据的读取、创建、删除操作。
Session对象是有生命周期的,它以transaction对象的开始和结束作为边界。Session是由SessionFactory生产出来的,SessionFactory是线程安全的,多个线程并发可以同时访问一个SessionFactory并从中获取Session实例。但是Session不是线程安全的,多线程同时使用一个实例进行数据存取操作的时候,就会导致混乱。所以我们需要保证每个线程一个session。
【持久化对象的三种状态】
☆Transient 瞬时状态:我们使用new操作符初始化对象,不是立刻就持久的。它们的状态是瞬时的,也是他们没和数据库表发生任何关系。如果应用不再引用这些对象或也不再被其他任何对象所引用,它们的状态就会丢失,并由垃圾回收机制回收。
Transient 状态,因为没有被session管理,所以数据库里没有数据。
☆Persistent 持久状态:
持久实例是任何具有数据库标识的实例。它由持久化管理器Session统一管理,持久实例在事务中进行操作,它们的状态在事务结束时,同数据库进行同步。当事务提交时,通过执行SQL的insert、update、delete语句把内存中的状态同步到数据库中。
对象属性发生改变,也就是数据发生变化,再提交事务。事务提交的时候会清理缓存,就是检查脏数据(数据变了,数据库没变),检查哪些数据变化了。完成数据和内存的同步,不需要再写update语句。
☆Detached 离线(托管)状态:
Session对象关闭之后,持久状态就变为离线状态。离线就表示这个对象不能再和数据库保持同步,它们就脱离了Hibernate的管理。
Detached状态下, 数据库里是有数据的,只是不被session管理。我们可以执行update操作,就可以将detached状态对象重新纳入session管理,变为persistent状态对象。persistent状态下,清理缓存是会和数据库同步。(关于缓存的知识后面会详细介绍)
我们发现这三种状态就是针对session来说的,是否受session的管理,是在session里,还是在session外。
代码举例:
User.hbm.xml 关联映射
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping > <!-- hibernate关联映射 -->
<class name="com.bjpowernode.hibernate.User">
<id name="id"> <!-- 主键生成策略 -->
<generator class="uuid"/>
</id>
<property name="name"/>
<property name="password"/>
<property name="createTime"/>
<property name="expireTime"/>
</class>
</hibernate-mapping>
hibernate.cfg.xml配置
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- MySQL数据库连接 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_basicmapping</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!-- MySQL方言配置 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<!-- Hibernate映射文件配置 -->
<mapping resource="com/bjpowernode/hibernate/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
结合三种状态在Test中对User的增加、更新代码举例:
import org.hibernate.Session;
public void testSave1(){
Session session=null;
Transaction tx=null;
User user=null;
try{
session =HibernateUtils.getSession();//获得session
tx=session.beginTransaction();//事务建立
//Transient
user=new User();
user.setName("辛巴");
user.setPassword("123");
user.setCreateTime(new Date());
user.setExpireTime(new Date());
//Persistent
session.save(user);
user.setName("娜拉");
tx.commit();//事务提交
}catch (Exception e) {
e.printStackTrace();//打印堆栈
if(tx!=null){
tx.rollback();//事务回滚
}
}finally{
HibernateUtils.closeSession(session);//关闭session
}
//detached,此时已脱离session
user.setName("丁满");
try{
//将detached状态对象重新纳入session管理
session=HibernateUtils.getSession();
session.beginTransaction();//事务建立
//此时变为persistent状态对象,persistent状态下,清理缓存是会和数据库同步。
session.update(user);
session.getTransaction().commit();//事务提交
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);//关闭session
}
}
【Hibernate 的CRUD】
结合上面提到的session知识,我们所有的增删改操作都需要放到事务内执行。Delete :只能删除数据库里存在的数据,需要先加载再删除。
1.先使用load/get方法查询。
2.再使用delete方法。
Update:只能更新数据库里存在数据。只有在没被session管理的时候,也就是detached状态才能更新。
怎么得到detached对象?
1.先查,使用load或get方法,先加载出数据。
2.再使用update更新。
对User 执行update举例:
public void testUpdate(){
Session session=null;
try{
session=HibernateUtils.getSession();
session.beginTransaction();
//建议采用load方式更新,先加载再更新
User user=(User)session.load(User.class, "4028168160bab3280160bab378980001");
user.setName("穆法沙");
//可以显示的update
session.update(user);
session.getTransaction().commit();
}catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
【get方法和load方法区别】
上面提到了加载时load和get两种方法,它们的区别也是很重要的。·get只能根据主键进行查询,加载上来的对象为持久对象,执行get方法时会马上发出查询语句,所以get不支持延迟加载。如果查询不存在的数据,返回null。
· load也只能根据主键查询。但不会马上发出查询语句,load支持延迟加载。只有真正使用对象时,对Hibernate来说才真正发出查询语句,这样做主要为了提高性能。lazy是Hibernate中非常重要的特性,主要通过代理对象实现,采用的是CGLIB库生成的,并不是jdk的动态代理。因为jdk的动态代理只能对实现了接口的类生成代理,而CGLIB可以直接对类生成代理,采用的是继承方式。如果load查询不存在的数据,Hibernate会抛异常ObjectNotFoundException。