当前位置: 首页 > 知识库问答 >
问题:

如何在Hibernate 4.3.4中配置和获取会话。最终?

王宏深
2023-03-14

我最近将我的Hibernate版本升级到4.3.4。最终。基于Hibernate的上下文会话配置,这个新版本不再基于ThreadLocal。如果我到目前为止得到的是正确的,我需要做些什么来提高它的效率吗?如果它不正确,我该怎么办?我不知道。

请注意,文档中提到:Hibernate提供了三种当前会话跟踪方法。基于“线程”的方法不适用于生产使用;它只对原型和教程(如本教程)有用。

Hibernate.cfg.xml

<hibernate-configuration>

    <session-factory>

    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost/myDB</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password"></property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>

    <!-- Disable the second-level cache  -->
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

    <property name="show_sql">true</property>

    <property name="hibernate.c3p0.min_size">5</property>
    <property name="hibernate.c3p0.max_size">20</property>
    <property name="hibernate.c3p0.timeout">300</property>
    <property name="hibernate.c3p0.max_statements">50</property>
    <property name="hibernate.c3p0.idle_test_period">3000</property>
        <!--        <property name="hbm2ddl.auto">update</property>-->

        <mapping class="com.myProject.entities.users" />
        ...

当前配置和代码

根据答案吹了,这部分留档μ当前配置如下:

 public class HibernateUtil {

    private static SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
              Configuration configuration = new Configuration();
              return configuration.configure()
                                  .buildSessionFactory(
                                       new StandardServiceRegistryBuilder()  
                                          .applySettings(configuration.getProperties())
                                          .build());
        } catch (Throwable ex) {
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

}

代码如下

    final Session session = HibernateUtil.getSessionFactory().openSession();
    try {
        final Transaction tx = session.beginTransaction();
        try {
              ...

以前的配置和代码

public class HibernateUtil {

    private static ServiceRegistry serviceRegistry;
    private static final ThreadLocal<Session> threadLocal = new ThreadLocal();
    private static SessionFactory sessionFactory;

    private static SessionFactory configureSessionFactory() {
        try {
            Configuration configuration = new Configuration();
            configuration.configure();
            serviceRegistry = new StandardServiceRegistryBuilder()
                    .applySettings(configuration.getProperties())
                    .build();
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);
            return sessionFactory;
        } catch (HibernateException e) {
            System.out.append("** Exception in SessionFactory **");
            e.printStackTrace();
        }
        return sessionFactory;
    }

    static {
        try {
            sessionFactory = configureSessionFactory();
        } catch (Exception e) {
            System.err.println("%%%% Error Creating SessionFactory %%%%");
            e.printStackTrace();
        }
    }

    private HibernateUtil() {
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static Session getSession() throws HibernateException {
        Session session = threadLocal.get();

        if (session == null || !session.isOpen()) {
            if (sessionFactory == null) {
                rebuildSessionFactory();
            }
            session = (sessionFactory != null) ? sessionFactory.openSession() : null;
            threadLocal.set(session);
        }

        return session;
    }

    public static void rebuildSessionFactory() {
        try {
            sessionFactory = configureSessionFactory();
        } catch (Exception e) {
            System.err.println("%%%% Error Creating SessionFactory %%%%");
            e.printStackTrace();
        }
    }

    public static void closeSession() throws HibernateException {
        Session session = (Session) threadLocal.get();
        threadLocal.set(null);
        if (session != null) {
            if (session.isOpen()) {
                session.close();
            }
        }
    }
}

访问事务和提交命令的代码

 final Session session = HibernateUtil.getSession();
        try {
            final Transaction tx = session.beginTransaction();
            try {

                    //Commands related to query go here

             if (!tx.wasCommitted()) {
                    tx.commit();
                }

                if (session.isOpen()) {
                    session.close();
                }

                return true;
            } catch (Exception e) {
                tx.rollback();
                return false;
            }
        } finally {
            HibernateUtil.closeSession();
        }
        return false;

共有2个答案

陶成化
2023-03-14

只需要访问应用程序中SessionFactory的单个实例。

以下信息来自Hibernate 4.3手册第2.2章上下文会话和第13章事务和并发

“SessionFactory是一个创建成本高昂的线程安全对象,旨在由所有应用程序线程共享。它通常在应用程序启动时从配置实例创建一次。”
“会话是一个廉价的非线程安全对象,应该使用一次,然后丢弃:单个请求、会话或单个工作单元。”

如果没有“工作单元”,只有一堆(捆绑的)查询和更新,只需遵循非托管环境的第一个习惯用法(来自前面提到的第13章)。除非你能证明这会带来性能问题(*),否则不要尝试优化,因为这是万恶之源。

如果有“工作单元”或“每个请求的会话”,可以使用org.hibernate.context.internal替换问题中的HibernateUtil。ThreadLocalSessionContext作为CurrentSessionContext(参见前面提到的第2.2章),遵循非托管环境的第二种习惯用法。

如果使用JTA,请将ThreadLocalSessionContext替换为org.hibernate.context.internal。JTASessionContext,并遵循使用JTA中描述的习惯用法。

请注意讨论“工作单元”的章节:良好的软件架构取决于对“业务事务”和“应用程序事务”对应用程序的含义的良好理解。

(*)性能问题可能由配置问题引起,例如,此问题在Hibernate手册中有相关文档。

周和安
2023-03-14

我会放弃TreadUtil类,它让我想起了Spring 1.0 Hibernate集成风格。如果您计划转到Hibernate 4。

除了应该依赖Hibernate 4引导机制之外,您的代码还存在以下问题:

>

    synchronized(HibernateUtil.class) {
    if (sessionFactory == null) {
        rebuildSessionFactory();
    }
}

我不明白为什么您需要重建它,因为您从未将其设置为null,会话工厂正在初始化静态块。

如果您总是必须在HibernateUtil中包装您的Hibernate代码。openSession()try/finally阻塞时,您将复制大量会话管理逻辑,同时将业务逻辑与事务逻辑混合。这打破了单一责任原则。

如果您仍然不想放弃HibernateUtil,那么您至少可以使用类似于JDBCTemplate的机制,在模板方法中抽象会话/事务管理,同时在可调用文件中提供业务代码,这对您来说可能类似于:

interface SessionCallback<T> {T doInSession(Session session);}

class HibernateUtil {

    public T execute(SessionCallback<T> action) {
        try{
            //open session
            //open transcation
            T result = action.doInSession(sessionFactory.getCurrentSession());
            //commit tx



            return result;
        }
        catch(RuntimeException e) {
            //rollback tx
            throw e;
        }
        finally {
            //close session
        }
    }
}

HibernateUtil.execute(new SessionCallback<Void>() {
    public Void doInSession(Session session) {
        session.createQuery(...);
        return null;
    }
});

final customerID = ...

Customer customer = HibernateUtil.execute(new SessionCallback<Customer>() {
    public Customer doInSession(Session session) {
        return (Customer) session.get(Customer.class, customerID);
        return null;
    }
});

查看您的代码表明您希望JDBC资源本地事务使用每个请求会话访问习惯用法,这意味着您需要ThreadLocalSessionContext:

hibernate.current_session_context_class=thread
hibernate.transaction.factory_class=JDBCTransactionFactory

额外的

您也可以考虑切换到JPA,并将Hibernate属性移到persistence.xml。

 类似资料:
  • 我正在尝试制作一个Minecraft客户端,但我不知道如何获取会话ID来启动游戏。我在google上搜索了一下,但无论如何都找不到从命令行启动Minecraft的答案——用户名和密码作为前缀不起作用。

  • 问题内容: 如何在Hibernate拦截器中获取Hibernate会话? 我正在尝试使用Hibernate通过组织ID透明地强制执行数据访问。我设置了一个全局筛选器,以按组织ID筛选所有查询。现在,在保存/更新之前,我需要使用实体拦截器在所有实体上设置组织ID。 组织ID来自HttpSession 我已经在Hibernate会话中将Organizational Id设置为Filter属性,我想在我

  • 如果我在一个会话中有值,并且我需要获取会话中的所有值,如 如果我将一组复选框值转换为字符串。Im 将.jsp中选择的所有值设置为会话对象。我只需要检索保存在上述代码中的jsp中的选定值。

  • 问题内容: 如何获取烧瓶上的复选框是否已选中我正在使用Flask开发服务器环境使用Flask,Gevent和Web套接字进行项目。我用过。这里 如何获得每个连接的唯一会话ID? 我想将其存储在数据库中,并在客户端断开连接后将其删除。 如何获得活动连接总数 问题答案: 没有会话ID。 Flask中的会话只是Cookie的包装。你保存在上面的内容经过数字签名,并以cookie的形式发送给客户端。当你发

  • Selenium网格显示配置中的最大会话5。当设置节点时,我给出了最大会话=20。当检查线程=22时,也只有5个chrome占用Rest时间在排队中。请找到附件。请帮助解决问题。 节点代码: 网格

  • 我需要向API服务发送一个post请求,该服务需要一个会话id以及post请求字段中的其他参数,以便获得所需的信息。 我正在使用邮递员来测试这个API。 我想知道在使用Postman时,如何在帖子请求中发送“会话ID”? 我知道Postman中的预请求脚本,但我不知道如何在post请求中使用该变量。