• Hibernate的执行流程——SessionFactory的创建


    Hibernate的执行流程:

    1、创建Configuration类实例,用来读取并解析配置文件(如Hibernate.cfg.xml),一个Configuration实例代表hibernate所有Pojo类到SQL数据库映射的集合;

    2、创建SessionFactory对象,用来读取并解析映射信息,同时将上一步Configuration对象中的所有配置信息copy到SessionFactory缓存中;

    3、通过上一步创建的SessionFactory对象,打开Session;

    4、开始事务,事务指Session提供的接口对数据库进行CRUD操作。

    只有了解Hibernate的执行流程,才能够更好的理解SessionFactory的创建过程。

    先放代码:

    package com;
    
    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 HibernateSessionFactory {
        private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
        private static final ThreadLocal<Session> sessionThreadLocal = new ThreadLocal<Session>();//创建一个ThreadLocal<Session>对象用来存放当前Session对象
        private static Configuration configuration = new Configuration();
        private static SessionFactory sessionFactory;
        private static String configFile = CONFIG_FILE_LOCATION;
        
        static
        {
            try{
                configuration.configure();//读取并解析hibernate.cfg.xml文件
           //在Hibernate4.x会使用注册机来解析映射信息,所以会先创建ServiceRegistry对象 ServiceRegistry serviceRgistry
    = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
           //ServiceRegister对象作为参数,使用configuration对象创建sessionFactory对象,即将configuration对象里的信息copy到sessionFactory缓存中 sessionFactory
    = configuration.buildSessionFactory(serviceRgistry); }catch(Exception e){ e.printStackTrace(); } }
      //声明一个私有无参构造函数
    private HibernateSessionFactory(){} public static SessionFactory getSessionFactory(){ return sessionFactory; } public static void rebuildSessionFactory(){ synchronized(sessionFactory){ try{ configuration.configure(configFile); ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry(); sessionFactory = configuration.buildSessionFactory(serviceRegistry); }catch(Exception e){ e.printStackTrace(); } } }
      //打开session
    public static Session getSession(){
          //获取当前线程的session对象 Session session
    = sessionThreadLocal.get(); try{ if(session == null || !session.isOpen()){ if(sessionFactory == null){//如果sessionFactory为null,创建一个 rebuildSessionFactory(); }
              //如果session没有打开,就用sessionFactory打开 session
    = (sessionFactory!=null)?sessionFactory.openSession():null;
              //将session对象放到ThreadLocal对象里,以便使用 sessionThreadLocal.set(session); } }
    catch(Exception e){ e.printStackTrace(); } return session; } public static void closeSession(){ Session session = sessionThreadLocal.get(); sessionThreadLocal.set(null); try{ if(session != null && session.isOpen()){ session.close(); } }catch(Exception e){ e.printStackTrace(); } } public static void setConfigFile(String configFile){ HibernateSessionFactory.configFile = configFile; sessionFactory = null; } public static Configuration getConfiguration(){ return configuration; } }

    代码里已经有部分注释,相信足够理解代码了。这里特别注意的一点就是,这个SessionFactory创建代码使用的jar包是Hibernate4.x,如果使用5.x以上版本,需要对创建SessionFactory过程做出以下改变:

    //添加add(User.class),这个User类是一个POJO类,对应数据库的一个user表,hibernate.cfg.xml里面有配置的,如果没有这一条语句,将会报错:Unknow Entity xxx
    configuration。add(User.class); configuration.configure();//读取并解析hibernate.cfg.xml文件 //在Hibernate5.x会使用注册机来解析映射信息,所以会先创建ServiceRegistry对象,使用StandardServiceRegistryBuilder() ServiceRegistry serviceRgistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build(); //ServiceRegister对象作为参数,使用configuration对象创建sessionFactory对象,即将configuration对象里的信息copy到sessionFactory缓存中 sessionFactory = configuration.buildSessionFactory(serviceRgistry);

    细心的读者可以看出,创建出来的SessionFactory是线程安全的,因此SessionFactory可以同时被多个线程共享,但是正常情况下,session并不是线程安全,每个线程都会使用这个session实例,如果多个线程同时操作数据库时,某个线程将session关闭了,正在操作数据库的线程就会出现异常,为了解决这个问题,代码中使用ThreadLocal对象来保证session的线程安全,这样的话,每个线程只会操作当前session实例的副本,不影响其他线程。

  • 相关阅读:
    hdu1087Super Jumping! Jumping! Jumping!(dp)
    划分树 hdu4417Super Mario
    poj2240Arbitrage(map+floyd)
    hdu4282A very hard mathematic problem
    hdu1421搬寝室(dp)
    【洛谷P3806】【模板】点分治1
    【CF914E】Palindromes in a Tree
    GDOI2020 游记
    【POJ2296】Map Labeler
    【洛谷P6623】树
  • 原文地址:https://www.cnblogs.com/SysoCjs/p/9496358.html
Copyright © 2020-2023  润新知