如何理解Hibernate中的HibernateSessionFactory类

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何理解Hibernate中的HibernateSessionFactory类相关的知识,希望对你有一定的参考价值。

参考技术A Session接口对于Hibernate 开发人员来说是一个最重要的接口。然而在Hibernate中,实例化的Session是一个轻量级的类,创建和销毁它都不会占用很多资源。这在实际项目 中确实很重要,因为在客户程序中,可能会不断地创建以及销毁Session对象,如果Session的开销太大,会给系统带来不良影响。但值得注意的是 Session对象是非线程安全的,因此在你的设计中,最好是一个线程只创建一个Session对象。

在Hibernate的设计者的头脑中,他们将session看作介于数据连接与事务管理一种中间接口。我们可以将session想象成一个持久对象 的缓冲区,Hibernate能检测到这些持久对象的改变,并及时刷新数据库。我们有时也称Session是一个持久层管理器,因为它包含这一些持久层相 关的操作,诸如存储持久对象至数据库,以及从数据库从获得它们。请注意,Hibernate 的session不同于JSP应用中的HttpSession。当我们使用session这个术语时,我们指的是Hibernate中的session, 而我们以后会将HttpSesion对象称为用户session。

SessionFactory 接口

这里用到了一个设计模式――工厂模式,用户程序从工厂类SessionFactory中取得Session的实例。

令你感到奇怪的是SessionFactory并不是轻量级的!实际上它的设计者的意图是让它能在整个应用中共享。典型地来说,一个项目通常只需要一 个SessionFactory就够了,但是当你的项目要操作多个数据库时,那你必须为每个数据库指定一个SessionFactory。
SessionFactory在Hibernate中实际起到了一个缓冲区的作用,它缓冲了Hibernate自动生成的SQL语句和一些其它的映射数据,还缓冲了一些将来有可能重复利用的数据。

Configuration 接口

Configuration接口的作用是对Hibernate进行配置,以及对它进行启动。在Hibernate的启动过程中,Configuration类的实例首先定位映射文档的位置,读取这些配置,然后创建一个SessionFactory对象。

虽然Configuration接口在整个Hibernate项目中只扮演着一个很小的角色,但它是启动hibernate时你所遇到的每一个对象。

Transaction 接口

Transaction接口是一个可选的API,你可以选择不使用这个接口,取而代之的是Hibernate的设计者自己写的底层事务处理代码。 Transaction接口是对实际事务实现的一个抽象,这些实现包括JDBC的事务、JTA中的UserTransaction、甚至可以是CORBA 事务。之所以这样设计是能让开发者能够使用一个统一事务的操作界面,使得自己的项目可以在不同的环境和容器之间方便地移值。

Query和Criteria接口

Query接口让你方便地对数据库及持久对象进行查询,它可以有两种表达方式:HQL语言或本地数据库的SQL语句。Query经常被用来绑定查询参数、限制查询记录数量,并最终执行查询操作。

Criteria接口与Query接口非常类似,它允许你创建并执行面向对象的标准化查询。

值得注意的是Query接口也是轻量级的,它不能在Session之外使用。

Callback 接口

当一些有用的事件发生时――例如持久对象的载入、存储、删除时,Callback接口会通知Hibernate去接收一个通知消息。一般而言,Callback接口在用户程序中并不是必须的,但你要在你的项目中创建审计日志时,你可能会用到它。

hibernate:如何选择表中的所有行

【中文标题】hibernate:如何选择表中的所有行【英文标题】:hibernate: how to select all rows in a table 【发布时间】:2015-10-13 13:04:27 【问题描述】:

我尝试用 Hibernate 做类似Select * from LogEntry 的事情。 插入工作正常:

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

[...]
protected EntityManager manager;

protected final String tableName = "LogEntry";

public DatabaseImpl(DB_TYPE db) 
    this.db = db;
    if (entityManagerFactory != null && entityManagerFactory.isOpen()) 
        entityManagerFactory.close();
    
    entityManagerFactory = Persistence.createEntityManagerFactory(db.getPersUnit());
    manager = entityManagerFactory.createEntityManager();

public void insert(LogEntry entry) 

    manager.getTransaction().begin();
    manager.persist(entry);
    manager.getTransaction().commit();

但是当我尝试使用这种方法获取插入的值时: 公共 LogEntryList getAll()

    manager.getTransaction().begin();

    Query query = manager.createNativeQuery("SELECT * FROM " + tableName + ";");
    ArrayList<LogEntry> entries = (ArrayList<LogEntry>) query.getResultList();
    manager.getTransaction().commit();

    return new LogEntryList(entries);

我总是得到异常: java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to de.motza.entities.LogEntry

我知道问题在于将查询结果转换为对象,但我找不到任何地方如何正确转换对象,或如何从表中获取多行。

有人有什么建议吗? 如果需要,我可以发布我的 persistence.xml 和更多代码

【问题讨论】:

你用的是哪个版本的hibernate? 试试这个 Query query = manager.createNativeQuery("SELECT * FROM " + tableName + ";", LogEntry.class); List 条目 = query.getResultList(); 休眠 entityManager 4.3.8.Final 请查看下面给出的答案。 【参考方案1】:

如果你使用 Spring HibernateDaoSupport,你可以使用这些方法从数据库中加载实体:

a) 按 ID 的单个实体

@Override
public DeleteProcessNotification getDeleteProcessNotificationById(Long id) 
    return this.getHibernateTemplate().load(DeleteProcessNotification.class, id);

b) 所有实体

@Override
public List<DeleteProcessNotification> getDeleteProcessNotificationsInQueue() 
    return this.getHibernateTemplate().loadAll(DeleteProcessNotification.class);

c) 具有 HQL 查询的实体

@Override
public List<DeleteProcessNotification> getPrioritizedDeleteProcessNotifications() 
    return (List<DeleteProcessNotification>) this.getHibernateTemplate().find(
            "FROM DeleteProcessNotification dpn \n" +
                    "WHERE dpn.priority = 'HIGH'");

HibernateDaoSupport 文档:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/hibernate5/support/HibernateDaoSupport.html

【讨论】:

【参考方案2】:

因为你使用了nativeQuery所以你需要使用setResultTransormer方法来传递结果。

Query query = manager.createNativeQuery("SELECT * FROM " + tableName + ";");
query.setResultTransformer(Transformers.aliasToBean(LogEntry.class))
ArrayList<LogEntry> entries = (ArrayList<LogEntry>) query.getResultList();

【讨论】:

你从哪里得到 Transformers.aliasToBean() 来自?【参考方案3】:
List<String> list = null;

TypedQuery<String> query = sessionfactory.openSession().createQuery("from yourTableName");

list = query.getResultList();

yourTableName 可以是你的@Entity

【讨论】:

【参考方案4】:

你可以使用 session.createCriteria(MyEntity.class).list(); 例如。

参考:Retrieving all rows of a table without HQL?

【讨论】:

SharedSessionContract 类型的方法 createCriteria(Class) 现已弃用。【参考方案5】:

据我所知,getResultList() 为您提供了一个列表...不是通用列表。所以如果你想得到一个通用列表,你必须使用

TypedQuery<Person> 

插入

Query

这是我得到信息的链接。

Cast to something the result of Query.getResultList()?

我对 Hibernate 了解不多。我希望这能帮到您。

【讨论】:

【参考方案6】:

对于初学者,您应该尝试利用 HQL,即 Hibernate 查询语言。在上面给出的示例中,您正在尝试执行本机 SQL 查询。您获得ClassCastException 的原因是本机查询绕过了框架并返回原始Objects 而不是您想要的类型。

尝试将此代码用于您的SELECT *

String hql = "from LogEntry";
Session session = entityManagerFactory.openSession();
Query query = session.createQuery(hql);
List<LogEntry> logEntries = query.list();      // no ClassCastException here

【讨论】:

虽然不完全是用户想要的,但这无疑是有益的信息。这是给我的。谢谢你的回答@Tim Biegeleisen :)【参考方案7】:

“问题”是,您正在发送一个本机查询,该查询将返回一个 Object[] 数组,每个数组都有一个值。您不需要调用原生查询,而是休眠查询,例如......

manager.createQuery("SELECT l FROM LogEntry");

例如,请参阅this answer。

【讨论】:

以上是关于如何理解Hibernate中的HibernateSessionFactory类的主要内容,如果未能解决你的问题,请参考以下文章

与 SQL 相比,Hibernate JPQL 查询非常慢

如何理解Hibernate中的HibernateSessionFactory类

使用 Vaadin Hibernates ThreadLocal<Session>.get() 在第一次调用后返回 null

休眠:分离没有级联到集合

谈谈你对Hibernate的理解

Hibernate