美文网首页
Hibernate管理Session

Hibernate管理Session

作者: BlueSkyBlue | 来源:发表于2020-03-25 13:18 被阅读0次

Hibernate自身提供了三种管理Session对象的方法:

  • Session对象的生命周期与本地线程绑定。
  • Session对象的生命周期与JTA事务绑定。
  • Hibernate委托程序管理Session对象的生命周期。

在Hibernate配置文件中,hibernate.current_session_context_class属性用于指定Session的管理方式,可选值包括

  • thread: Session对象的生命周期与本地线程绑定。
  • jta*:Session对象的生命周期与JTA事务绑定。
  • managed:Hibernate委托程序管理Session对象的生命周期。

我们来考虑一个需求,如何在一个DAO类中添加Department对象到数据库中。我们也许会使用构造函数的方式添加。

public void save(Session session, Department dept){
    session.save(dept);
}

若需要传入一个Session,则意味上上一层可能是Service,需要获取到Session对象,上一层需要和Hibernate的API紧密耦合。所以不推荐使用此种方式。我们希望提供一个干净的save方法。

可以获取和当前线程绑定的Session对象,这样做有两个好处:

  1. 不需要从外部传入Session对象。
  2. 多个DAO方法可以使用同一个事务。

使用当前线程绑定的Session来改造上述的程序
首先我们先创建一个HIbernate工具类(HibernateUtil)。该类为单例模式的。

public class HibernateUtils {
    private SessionFactory sessionFactory;

    public static HibernateUtils instance = new HibernateUtils();

    public static HibernateUtils getInstance(){
        return instance;
    }

    public SessionFactory getSessionFactory() {
        if(sessionFactory == null){
            //1.1 Create configuration object.
            Configuration configuration = new Configuration().configure();
            sessionFactory = configuration.buildSessionFactory();
        }
        return sessionFactory;
    }

    public Session getSession(){
        return getSessionFactory().getCurrentSession();
    }
}

之后在DAO中执行保存操作

public class HelloWorldDAO {
    public void save(HelloWorld helloWorld){
        Session session = HibernateUtils.getInstance().getSession();
        session.save(helloWorld);
    }
}

测试类

public void test(){
    Session session = HibernateUtils.getInstance().getSession();
    System.out.println(session.hashCode());
    Transaction transaction = session.beginTransaction();
    HelloWorldDAO dao = new HelloWorldDAO();

    HelloWorld helloWorld = new HelloWorld();
    helloWorld.setTitle("Hello Session");
    helloWorld.setDate(new Date());
    helloWorld.setTitle("Title");
    helloWorld.setAuthor("HFR");
    dao.save(helloWorld);
    transaction.commit();
    System.out.println(session.isOpen());
}

Session是由Thread管理的,则在提交,回滚事务时已经关闭。

Hibernate按照以下规则将Session与本地线程绑定在一起:

  • 当一个线程(thread A)第一次调用SessionFactory对象的getCurrentSession方法时,该方法会创建一个新的Session(sessionA)对象,把该对象与threadA绑定,并将sessionA返回。
  • 当thread A再一次调用SessionFactory对象的getCurrentSession方法时,该方法返回session A对象。
  • 当thread A 提交session A关联的事务时,Hibernate会自动flush session A的缓存,然后提交事务,关闭session A对象。当thread A撤销session A关联的事务时,也会自动关闭session A对象。
  • 当thread A再次调用SessionFactory对象的getCurrentSession方法时,该方法会创建一个新的session B对象,把该对象与thread A绑定,并将session B对象返回。

批量处理数据

通常指批量的添加,删除和修改。
在应用层进行批量操作,有以下几种方式:

  • 通过Session
  • 通过HQL
  • 通过StatelessSession
  • 通过JDBC API

凡是批量操作,使用原生的JDBC API是最快的,而且效率高,速度快。

通过Session

不推荐使用Session进行批量操作:因为Session的save和update方法会把处理的对象放入缓存中,如果通过一个Session来处理大量的持久化对象,应该及时从缓存中清空已处理完毕并不再使用的对象,具体做法是处理完一个对象或小批量的对象后,立即调用flush方法刷新缓存,然后调用clear方法清空缓存。

News news = null;

for(int i=0;i<1000;i++){
  news = new News();
  news.setTitle("title" + i);
  session.save(news);
  if((i+1)%20 == 0){
    session.flush();
    session.clear();
  }
}

通过Session处理操作会遇到记下几种限制:

  • 需要在Hibernate配置文件中指定JDBC单批量处理的数目,应保证每次向数据库发送的批量的SQL的数目要与batch_size属性一致。
  • 若对象采用identity生成器,则Hibernate无法在JDBC进行批量操作。
  • 进行批量操作建议关闭Hibernate二级缓存。

通过StatelessSession

StatelessSeesion和Session有以下的区别:

  • StatelessSession没有缓存,通过StatelessSession加载,保存或更新后的对象处于游离状态。
  • StatelessSession不与Hibernate的二级缓存交互。
  • 当调用StatelessSession的update, insert或delete方法时,这些方法会立即执行相应的SQL语句,而不会仅执行一条SQL语句。
  • StatelessSession不会进行脏检查,因此修改了一个对象后,还需要调用StatelessSession的update对象确保数据的一致性。
  • StatelessSession不会对关联对象进行任何级联操作。
  • 通过一个StatelessSession对象加载两次OID为1的对象,得到的两个对象的内存地址不同。
  • StatelessSession所做的操作可以被Interceptor拦截器拦截,但会被HIbernate的事件处理系统忽略掉。

注意:HQL只支持INSERT INTO ...SELECT形式的插入语句,但不支持INSERT INTO...VALUES形式的插入语句。所以HQL不能进行批量插入操作。

相关文章

网友评论

      本文标题:Hibernate管理Session

      本文链接:https://www.haomeiwen.com/subject/pwutuhtx.html