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

使用Spring Roo项目并获得org.hibernate.lazyInitializationException:无法初始化代理-没有会话

康锦
2023-03-14

所涉及的项目:

  • memdrill-data
  • 数据-使用

memdrill-data是一个Spring Roo管理的项目。这里没有web组件。我只是:

persistence setup --provider HIBERNATE --database HYPERSONIC_PERSISTENT
@RooJavaBean
@RooToString
@RooEntity
public class Item {

    @NotNull
    @Column(unique = true)
    @Size(min = 1, max = 200)
    private String itemId;

    @NotNull
    @Lob
    @OneToOne(cascade = javax.persistence.CascadeType.ALL, fetch = FetchType.LAZY)
    private LobString content;
}

@RooJavaBean
@RooEntity
public class LobString {

    @Lob
    @Basic(fetch=FetchType.LAZY)
    private String data;

    public LobString() {
        super();
    }

    public LobString(String data) {
        this.data = data;
    }
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd         http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

<context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>

<context:spring-configured/>

<context:component-scan base-package="com.memdrill.data">
    <context:exclude-filter expression=".*_Roo_.*" type="regex"/>
    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
    <property name="driverClassName" value="${database.driverClassName}"/>
    <property name="url" value="${database.url}"/>
    <property name="username" value="${database.username}"/>
    <property name="password" value="${database.password}"/>
    <property name="testOnBorrow" value="true"/>
    <property name="testOnReturn" value="true"/>
    <property name="testWhileIdle" value="true"/>
    <property name="timeBetweenEvictionRunsMillis" value="1800000"/>
    <property name="numTestsPerEvictionRun" value="3"/>
    <property name="minEvictableIdleTimeMillis" value="1800000"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
    <property name="persistenceUnitName" value="persistenceUnit"/>
    <property name="dataSource" ref="dataSource"/>
</bean>
public static void main(String[] args) {
    ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
            "classpath*:META-INF/spring/applicationContext*.xml");

    Item item = new Item();
    item.setItemId("abc123");
    item.setContent(new LobString("this is the content of the item"));

    item.persist();

    System.out.println("persist - OK");

    List<Item> items = Item.findAllItems();

    Item i = items.get(0);
    System.out.println("i.getId() = " + i.getId());
    System.out.println("i.getItemId() = " + i.getItemId());
    System.out.println("i.getContent() = " + i.getContent());
    System.out.println("i.getContent().getId() = " + i.getContent().getId());
    System.out.println("i.getContent().getData() = " + i.getContent().getData());

    appContext.close();
}
public static List<Item> Item.findAllItems() {
    return entityManager().createQuery("SELECT o FROM Item o", Item.class).getResultList();
}

这是我得到的:

persist - OK
i.getId() = 1
i.getItemId() = abc123
2014-07-05 13:23:30,732 [main] ERROR org.hibernate.LazyInitializationException - could not initialize proxy - no Session
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
    at com.memdrill.data.util.LobString_$$_javassist_0.toString(LobString_$$_javassist_0.java)
    at java.lang.String.valueOf(String.java:2826)
    at java.lang.StringBuilder.append(StringBuilder.java:115)
    at com.memdrill.prototypes.datause.Main.main(Main.java:34)

因此,当我试图访问懒惰加载的数据以填充LobString POJO时,没有会话在进行,会话崩溃。

我最接近(在我的代码中,即,不是我所依赖的库中)放入LobString访问代码(例如,item.getContent().getId())的方法是插入findAllItems(),或者创建一个类似于这样的新方法来说明这一点:

html" target="_blank">public static List<Item> findAllItemsWithRefs() {
    List<Item> items = entityManager().createQuery("SELECT o FROM Item o", Item.class).getResultList();
    for(Item item : items) {
        System.out.println("item.getContent().getId() = " + item.getContent().getId());
    }
    return items;
}

正如其他SO文章所建议的那样,我尝试将@Transactional置于该方法之上,但仍然得到了LazyInitializationException。但即使这真的有效...为什么我需要启动一个事务来从数据库中读取数据?事务难道不是为了在编写时保持数据完整性吗?

在我看来,解决这个问题的一个方法是以某种方式指定一个不同于“从项目o中选择o”的查询...一个还获取LobString数据的...但这似乎不太正确,即使它能在这种特殊情况下飞行。

当我访问它还没有加载的数据时,我希望Hibernate开始一个新的会话...但很明显,它并不像我期望的那样起作用。

顺便说一句,如果我将以下log4j.propeties添加到类路径:

log4j.rootLogger=error, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

# Print the date in ISO 8601 format
log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p %c - %m%n

log4j.logger.org.hibernate.SQL=DEBUG
log4j.logger.org.hibernate.type=TRACE

我得到:

persist - OK
2014-07-05 16:17:35,707 [main] DEBUG org.hibernate.SQL - select item0_.id as id1_, item0_.content as content1_, item0_.item_id as item2_1_, item0_.version as version1_ from item item0_
2014-07-05 16:17:35,711 [main] TRACE org.hibernate.type.descriptor.sql.BasicExtractor - found [1] as column [id1_]
2014-07-05 16:17:35,713 [main] TRACE org.hibernate.type.descriptor.sql.BasicExtractor - found [1] as column [content1_]
2014-07-05 16:17:35,713 [main] TRACE org.hibernate.type.descriptor.sql.BasicExtractor - found [abc123] as column [item2_1_]
2014-07-05 16:17:35,713 [main] TRACE org.hibernate.type.descriptor.sql.BasicExtractor - found [0] as column [version1_]
i.getId() = 1
i.getItemId() = abc123
2014-07-05 16:17:35,717 [main] ERROR org.hibernate.LazyInitializationException - could not initialize proxy - no Session

因此,正如“Found 1 as column[content1_]”一行所示,我至少在包含LobString数据的表中有行的外键······但是如果没有获得LazyInitializationException,我就无法访问该id。如果我能找到它,也许我可以通过身份证找到龙虾串...但是i.getContent()和i.getContent().getID()给出了例外情况。外键应该与LobString表的主键id匹配,即i.getContent().getID()。但是似乎没有办法从i...如日志所示,实际上是从数据库中提取的。

        // Invoke method on actual Query object.
        try {
            Object retVal = method.invoke(this.target, args);
            return (retVal == this.target ? proxy : retVal);
        }
        catch (InvocationTargetException ex) {
            throw ex.getTargetException();
        }
        finally {
            if (method.getName().equals("getResultList") || method.getName().equals("getSingleResult") ||
                    method.getName().equals("executeUpdate")) {
                EntityManagerFactoryUtils.closeEntityManager(this.em);
            }
        }

首先,如果使用“GetResultList”,则EntityManager将被关闭。我假设EntityManager是一个JPA结构,它映射到Hibernate的会话,但不详细说明。

二...如果我在调试时钻得足够深,我可以看到什么应该懒洋洋地加载数据“这是项目的内容”...所以我实际上把数据加载到内存里了...1)因为它是懒惰的,所以不应该2)即使它在那里,我也不能访问它,因为我得到了LazyInitializationException。

在调试时,我可以看到数据加载在以下两个地方:

懒惰加载的数据到此为止...我到底做错了什么?

我似乎也懒洋洋地加载了LobString的规范。但如果是这样的话,而我确实记忆中有这些内容...为什么我不能访问它?

编辑3:

    EntityManager em = Item.entityManager();
    List<Item> items = em.createQuery("SELECT o FROM Item o JOIN FETCH o.content", Item.class).getResultList();
2014-07-06 21:44:56,862 [main] INFO  org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean - Building JPA container EntityManagerFactory for persistence unit 'persistenceUnit'
in LobString default constructor
in LobString (String data) constructor
2014-07-06 21:44:57,891 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Creating new transaction with name [com.memdrill.data.entity.Item.persist]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2014-07-06 21:44:57,944 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@779d9c0d] for JPA transaction
2014-07-06 21:44:57,948 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Not exposing JPA transaction [org.hibernate.ejb.EntityManagerImpl@779d9c0d] as JDBC transaction because JpaDialect [org.springframework.orm.jpa.DefaultJpaDialect@d7e60a1] does not support JDBC Connection retrieval
2014-07-06 21:44:57,999 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Initiating transaction commit
2014-07-06 21:44:58,000 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@779d9c0d]
2014-07-06 21:44:58,002 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@779d9c0d] after transaction
2014-07-06 21:44:58,002 [main] DEBUG org.springframework.orm.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
persist - OK - in Main of memdrill-data not data-use
2014-07-06 21:44:58,008 [main] DEBUG org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler - Creating new EntityManager for shared EntityManager invocation
in LobString default constructor
2014-07-06 21:44:58,133 [main] DEBUG org.springframework.orm.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
i.getId() = 1
i.getItemId() = abc123
i.getContent() = com.memdrill.data.util.LobString@6fe30af
i.getContent().getId() = 1
i.getContent().getData() = this is the content of the item
2014-07-06 21:44:58,134 [main] INFO  org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'persistenceUnit'

这几乎是我想要的。我只想要龙虾串的ID。这个想法是,这将是一个REST调用,我只想返回项“基本”数据和LobString的ID,它们可以用于单独的请求。

知道什么样的JPQL查询可以实现这一点吗?(如有任何有助于理解幕后发生的事情的评论,将不胜感激)-谢谢

共有1个答案

汤博
2023-03-14

要解决这个问题,可以在非静态方法上使用@transactional注释。

示例:

@RooJavaBean
@RooToString
@RooEntity
public class Item {

    @NotNull
    @Column(unique = true)
    @Size(min = 1, max = 200)
    private String itemId;

    @NotNull
    @Lob
    @OneToOne(cascade = javax.persistence.CascadeType.ALL, fetch = FetchType.LAZY)
    private LobString content;

    @Transactional(readOnly=true)
    LobString loadContent(){
       getContent().getId();
       return getContent();
    }
}

然后,使用LoadContent()方法获取LobString

 类似资料:
  • 问题内容: 我有2台物理服务器,我的Web应用程序命中该服务器由负载均衡器管理。我总是得到- org.hibernate.LazyInitializationException:无法初始化代理-没有会话 当其中一台服务器受到攻击而另一台服务器运行平稳而没有任何问题时。我有一个由应用程序启用和管理的本地托管缓存存储。仅当尝试从一个表访问一个特定的列时,才会发生此异常。不管选择哪个服务器,其余的操作都

  • 问题内容: 我试图从数据库中的对象进行简单加载,但出现错误“无法初始化代理-没有会话”,知道吗?谢谢 问题答案: 尝试添加到validate方法: 发生的事情是,因为没有注释,所以没有与该方法关联的会话,并且每个查询都将在其自己的会话中运行,该会话随后将立即关闭。 该方法始终返回一个代理,与之不同(请参阅此处,了解load与get之间的差异)。 因此,返回了代理,但是由于缺少代理,因此立即关闭了创

  • 我试图从DB中的一个对象做一个简单的加载,但是我得到的错误是“Could not initialize proxy-no session”,有什么想法吗?谢谢

  • 我正在尝试使用Primeface JSF Spring Boot做一个示例User CRUD页面。在页面上,我有一个启用LazyLoding的表。我的User对象没有1对N或N对1字段,都是原始字段,在到达时不需要数据库访问或初始化。(所以FetchType.EAGER不会有帮助) 当试图在弹出窗口上显示用户列表中的用户时,出现以下异常: 为什么 JSF 组件尝试从数据库中更新对象以获取 1 比

  • 问题内容: 对数据库有以下查询: 在获取employee.address.street,employee.address.houseNumber或employee.address.city时,它将失败,但以下情况除外: 员工映射: 地址映射: 对于其他类(办公室,公司等),这​​是绝对正常的。如果注释,则在jsp应用程序中加载地址字段的行将正常工作。怎么了?顺便说一下,尽管有异常,它仍显示有关js

  • 抱歉,如果我的帖子是重复的,但我不能从另一个主题解决我的问题,所以我创建了这个主题。希望有人帮助我。我用的是Hibernate,JSF和Glassfish。 这是我的完整代码 CusterBean(请求范围) 顾客道 xhtml 我得到这个错误: SEVERE:javax.el.ELException: /admin/customer_list.xhtml@68,106 value="#{cust