Hibernate---Session管理和进行批处理

发现问题

  • 如果集合Hibernate来编写DAO类,那么会遇到这样一个问题,那就是:Hibernate的Session操作对象需要在哪里实例化完成?
  • 如果由Service层(也许是业务层)调用DAO方法的时候传入Session对象,这就需要业务层于Hibernate紧密耦合,但不希望业务层在调用方法的时候,知道底层是如何实现的,所以不应该由业务层实例化Session对象
    public boolean save(Session session, Department department){
        return session.save(department)!=null;
    }

使用当前线程管理Session对象

在这里插入图片描述

使用本地线程管理session的具体实现

  1. 将获取Session对象的操作包装为一个工具类,因为这个工具类于Hibernate有关,所以将这个类放在"util.hibernate"包下
package mao.shu.util.hibernate;


import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;


/**
 * 单例设计模式
 */
public class HibernateUtil {
    private SessionFactory sessionFactory;
    private static HibernateUtil instance = new HibernateUtil();

    /**
     * 私有化构造器
     */
    private HibernateUtil(){}


    public static HibernateUtil getInstance(){
        return instance;
    }
    publicSessionFactory getSessionFactory(){
        if(this.sessionFactory == null){
            Configuration configuration = new Configuration().configure();
            ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
                    .applySettings(configuration.getProperties()).buildServiceRegistry();
            this.sessionFactory =  configuration.buildSessionFactory(serviceRegistry);
        }
        return this.sessionFactory;
    }

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

  1. 修改hibernate.cfg.xml文件
    • 如果整个其他框架会有更简单的方法,不需要配置此配置项
<!--开启管理当前session对象-->
<property name="hibernate.current_session_context_class">thread</property>
  • 修改DAO方法
public boolean save(Department department){
    Session session = HibernateUtil.getInstance().getSession();
    return session.save(department)!=null;
}
  • 编写测试方法
    @Test
    public void save() {
        //测试获取的session是否为同一个对象
        System.out.println(HibernateUtil.getInstance().getSession().hashCode());
        System.out.println(HibernateUtil.getInstance().getSession().hashCode());
        System.out.println(HibernateUtil.getInstance().getSession().hashCode());

        Session session = HibernateUtil.getInstance().getSession();
        Transaction transaction = session.beginTransaction();
        DepartmentDAO departmentDAO = new DepartmentDAO();
        for (int i = 0; i < 10; i++) {
            Department dept = new Department();
            dept.setName("session测试"+i);
            departmentDAO.save(dept);
        }

        transaction.commit();
        System.out.println(session.isOpen());
    }
  • 从测试结果中可以看出,每个session都是同一线程的session
    在这里插入图片描述

  • 若 Session 是由 thread 来管理的, 则在提交或回滚事务时, 已经关闭 Session 了.

在这里插入图片描述

Session生命周期于本地线程绑定

在这里插入图片描述

批量处理数据

在这里插入图片描述

  • 如果要批量处理数据最快的速度还是使用原生sql的API,因为如果使用Hibernate提供的方式最后也是要转换为sql语句进行执行.

  • 使用原生sql语句进行批处理操作(推荐使用)

  @Test
    public void testBathSql(){

        long beginTime = System.currentTimeMillis();

        Session session = HibernateUtil.getInstance().getSession();
        Transaction transaction = session.beginTransaction();
        session.doWork(new Work() {
            @Override
            public void execute(Connection connection) throws SQLException {
                String sql = "INSERT INTO GG_DEPARTMENT(ID,NAME)VALUES(?,?)";
                PreparedStatement pstm = connection.prepareStatement(sql);
                for (int i = 0; i < 10000; i++) {
                   pstm.setInt(1,i);
                   pstm.setString(2,"sql批处理测试"+i);
                   pstm.addBatch();
                }
                System.out.println(pstm.executeBatch().length);
            }
        });
        transaction.commit();
        long endTime = System.currentTimeMillis();
        System.out.println("共花费:"+(float)(endTime - beginTime)/1000 + "s");
    }
  • 执行结果

在这里插入图片描述

  1. 通过 Session 来进行批量操作(不推荐)

在这里插入图片描述

    @Test
    public void testBath(){

        long beginTime = System.currentTimeMillis();

        Session session = HibernateUtil.getInstance().getSession();
        Transaction transaction = session.beginTransaction();
        for (int i = 0; i < 10000; i++) {
            Department dept = new Department();
            dept.setName("批处理测试"+i);
            session.save(dept);
            if ((i+1)%20==0){
                session.flush();//同步数据
                session.clear();//清理缓存
            }
        }
        transaction.commit();

        long endTime = System.currentTimeMillis();
        System.out.println("共花费:"+(float)(endTime - beginTime)/1000 + "s");
    }

在这里插入图片描述

  • 数据库中保存的数据不完整,

在这里插入图片描述

在这里插入图片描述

  1. 使用HQL进行批处理(不推荐)
    在这里插入图片描述

  2. 通过StatelessSession来进行批量操作(不推荐)
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_43386754/article/details/88017485