簡體   English   中英

Spring DATA JPA + Hibernate-無法初始化代理-修復后無會話:

[英]Spring DATA JPA + Hibernate - could not initialize proxy - no Session after fix:

大家好 我是Spring Data + JPA的新手。 我需要你的幫助。 這是我關於stackoverflow的第一個問題,對不起,如果我提出的問題不正確。

我開始使用Spring Data + JPA + Hibernate,Spring MVC和Use MySQL實現項目。

我有數據庫方案:

項目數據庫

數據庫方案

應用程序上下文:

<context:property-placeholder location="classpath:util.properties" />
<!--Activates various annotations to be detected in bean classes: Spring's @Required and @Autowired and so on-->
<context:annotation-config/>

<!-- Datasource.  -  MySQL -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="${jdbc.driverClass}"/>
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}" />
</bean>

<!--Do not forget activate @Transactional JPA annotation with <annotation-driven/>-->
<!-- JPA Persistence Context and EntityManager configuration -->
<bean id="entityManagerFactory"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
    <!--packagesToScan - search Entity and mapping them -->
    <property name="packagesToScan" value="by.GetItFree" />
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >
            <property name="generateDdl" value="true" />
            <property name="showSql" value="true" />
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.format_sql">false</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
            <prop key="hibernate.enable_lazy_load_no_trans">true</prop>
        </props>
    </property>
</bean>

<!-- Automatic Transaction Participation-->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<jpa:repositories base-package="by.GetItFree.orm.repository" entity-manager-factory-ref="entityManagerFactory"
                  transaction-manager-ref="transactionManager"/>

MVC配置:

<!--
    mvc:annotation-driven configures Spring MVC annotations
    Support for validating @Controller inputs with @Valid, if a JSR-303 Provider is present on the classpath.
    HttpMessageConverter support for @RequestBody method parameters and @ResponseBody method return values
    from @RequestMapping or @ExceptionHandler methods.
 -->
<mvc:annotation-driven/>

<!-- activate @Transactional JPA annotation -->
<tx:annotation-driven/>

<!-- ViewResolver bean config for mapping strings to jsp views -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!-- Example: a logical view name of 'showMessage' is mapped to '/WEB-INF/jsp/showMessage.jsp' -->
    <property name="order" value="1" />
    <property name="prefix" value="/WEB-INF/view" />
    <property name="suffix" value=".jsp" />
</bean>


<mvc:view-controller path="/about.html" view-name="/about/about"/>
<mvc:view-controller path="/index.html" view-name="/index"/>


<!-- Static Resources Configuration (get access to static sources such as CSS and JavaScript files) -->
<mvc:resources mapping="/resources/**" location="/resources/" />


一些JPA持久性實體:

廣告:

@Entity
public class Advert {
    private int id;
    private String karmaReq;
    private byte[] image;
    private int profileId;
    private String profileUsersUsername;
    private String head;
    private String content;
    private byte ordered;
    private Timestamp date;
    private Profile profile;
    private Collection<Comment> commentsById;

    @Id
    @Column(name = "id", nullable = false)
    public int getId() {
        return id;
    }

public void setId(int id) {
    this.id = id;
}

@Basic
@Column(name = "karmaReq", nullable = true, length = 45)
public String getKarmaReq() {
    return karmaReq;
}

public void setKarmaReq(String karmaReq) {
    this.karmaReq = karmaReq;
}

@Basic
@Column(name = "image", nullable = false)
public byte[] getImage() {
    return image;
}

public void setImage(byte[] image) {
    this.image = image;
}

@Basic
@Column(name = "profile_id", nullable = false)
public int getProfileId() {
    return profileId;
}

public void setProfileId(int profileId) {
    this.profileId = profileId;
}

@Basic
@Column(name = "profile_users_username", nullable = false, length = 45)
public String getProfileUsersUsername() {
    return profileUsersUsername;
}

public void setProfileUsersUsername(String profileUsersUsername) {
    this.profileUsersUsername = profileUsersUsername;
}

@Basic
@Column(name = "head", nullable = true, length = 45)
public String getHead() {
    return head;
}

public void setHead(String head) {
    this.head = head;
}

@Basic
@Column(name = "content", nullable = true, length = 450)
public String getContent() {
    return content;
}

public void setContent(String content) {
    this.content = content;
}

@Basic
@Column(name = "ordered", nullable = false)
public byte getOrdered() {
    return ordered;
}

public void setOrdered(byte ordered) {
    this.ordered = ordered;
}

@Basic
@Column(name = "date", nullable = false)
public Timestamp getDate() {
    return date;
}

public void setDate(Timestamp date) {
    this.date = date;
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Advert advert = (Advert) o;

    if (id != advert.id) return false;
    if (profileId != advert.profileId) return false;
    if (ordered != advert.ordered) return false;
    if (karmaReq != null ? !karmaReq.equals(advert.karmaReq) : advert.karmaReq != null) return false;
    if (!Arrays.equals(image, advert.image)) return false;
    if (profileUsersUsername != null ? !profileUsersUsername.equals(advert.profileUsersUsername) : advert.profileUsersUsername != null)
        return false;
    if (head != null ? !head.equals(advert.head) : advert.head != null) return false;
    if (content != null ? !content.equals(advert.content) : advert.content != null) return false;
    if (date != null ? !date.equals(advert.date) : advert.date != null) return false;

    return true;
}

@Override
public int hashCode() {
    int result = id;
    result = 31 * result + (karmaReq != null ? karmaReq.hashCode() : 0);
    result = 31 * result + Arrays.hashCode(image);
    result = 31 * result + profileId;
    result = 31 * result + (profileUsersUsername != null ? profileUsersUsername.hashCode() : 0);
    result = 31 * result + (head != null ? head.hashCode() : 0);
    result = 31 * result + (content != null ? content.hashCode() : 0);
    result = 31 * result + (int) ordered;
    result = 31 * result + (date != null ? date.hashCode() : 0);
    return result;
}

@ManyToOne
@JoinColumns({@JoinColumn(name = "profile_id", referencedColumnName = "id", nullable = false, insertable = false, updatable = false), @JoinColumn(name = "profile_users_username", referencedColumnName = "users_username", nullable = false, insertable = false, updatable = false)})
public Profile getProfile() {
    return profile;
}

public void setProfile(Profile profile) {
    this.profile = profile;
}

@OneToMany(mappedBy = "advertByAdvertId")
public Collection<Comment> getCommentsById() {
    return commentsById;
}

public void setCommentsById(Collection<Comment> commentsById) {
    this.commentsById = commentsById;
}

@Override
public String toString() {
    return "Advert{" +
            "id=" + id +
            ", karmaReq='" + karmaReq + '\'' +
            ", image=" + Arrays.toString(image) +
            ", profileId=" + profileId +
            ", profileUsersUsername='" + profileUsersUsername + '\'' +
            ", head='" + head + '\'' +
            ", content='" + content + '\'' +
            ", ordered=" + ordered +
            ", date=" + date +
            ", profile=" + profile +
            ", commentsById=" + commentsById +
            '}';
}

}

//我知道,如果我在String()中注釋調用概要文件,那么一切都會正常進行。

輪廓

@Entity
@IdClass(ProfilePK.class)
public class Profile {
    private int id;
    private String usersUsername;
    private Integer karma;
    private String phone;
    private byte[] icon;
    private Collection<Advert> adverts;
    private Collection<Comment> comments;
    private Collection<Message> messages;
    private Users usersByUsersUsername;
@Id
@Column(name = "id", nullable = false)
public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

@Id
@Column(name = "users_username", nullable = false, length = 45)
public String getUsersUsername() {
    return usersUsername;
}

public void setUsersUsername(String usersUsername) {
    this.usersUsername = usersUsername;
}

@Basic
@Column(name = "karma", nullable = true)
public Integer getKarma() {
    return karma;
}

public void setKarma(Integer karma) {
    this.karma = karma;
}

@Basic
@Column(name = "phone", nullable = true, length = 15)
public String getPhone() {
    return phone;
}

public void setPhone(String phone) {
    this.phone = phone;
}

@Basic
@Column(name = "icon", nullable = true)
public byte[] getIcon() {
    return icon;
}

public void setIcon(byte[] icon) {
    this.icon = icon;
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Profile profile = (Profile) o;

    if (id != profile.id) return false;
    if (usersUsername != null ? !usersUsername.equals(profile.usersUsername) : profile.usersUsername != null)
        return false;
    if (karma != null ? !karma.equals(profile.karma) : profile.karma != null) return false;
    if (phone != null ? !phone.equals(profile.phone) : profile.phone != null) return false;
    if (!Arrays.equals(icon, profile.icon)) return false;

    return true;
}

@Override
public int hashCode() {
    int result = id;
    result = 31 * result + (usersUsername != null ? usersUsername.hashCode() : 0);
    result = 31 * result + (karma != null ? karma.hashCode() : 0);
    result = 31 * result + (phone != null ? phone.hashCode() : 0);
    result = 31 * result + Arrays.hashCode(icon);
    return result;
}

@OneToMany(mappedBy = "profile")
public Collection<Advert> getAdverts() {
    return adverts;
}

public void setAdverts(Collection<Advert> adverts) {
    this.adverts = adverts;
}

@OneToMany(mappedBy = "profile")
public Collection<Comment> getComments() {
    return comments;
}

public void setComments(Collection<Comment> comments) {
    this.comments = comments;
}

@OneToMany(mappedBy = "profile")
public Collection<Message> getMessages() {
    return messages;
}

public void setMessages(Collection<Message> messages) {
    this.messages = messages;
}

@ManyToOne
@JoinColumn(name = "users_username", referencedColumnName = "username", nullable = false, insertable = false, updatable = false)
public Users getUsersByUsersUsername() {
    return usersByUsersUsername;
}

public void setUsersByUsersUsername(Users usersByUsersUsername) {
    this.usersByUsersUsername = usersByUsersUsername;
}

@Override
public String toString() {
    return "Profile{" +
            "id=" + id +
            ", usersUsername='" + usersUsername + '\'' +
            ", karma=" + karma +
            ", phone='" + phone + '\'' +
            ", icon=" + Arrays.toString(icon) +
            ", adverts=" + adverts +
            ", comments=" + comments +
            ", messages=" + messages +
            ", usersByUsersUsername=" + usersByUsersUsername +
            '}';
}

}

ORM

廣告

   /**
 * DAO interface responsible for operation with Advertising.
 * <p>
 * Created by Novik Igor on 09.02.2017.
 */
public interface AdvertDAO {

    /**
     * Method returned list of Advert's from the DB.
     *
     * @return list of Advertising's.
     */
    List<Advert> findAll();

    /**
     * Method returned list of Advert from the DB according ID.
     *
     * @param head id of the Advert;
     * @return Advertising according id.
     */
    Advert findByHead(String head);
}

AdvertDAOR存儲庫

/**
 * SpringData AdvertDAO repository.
 *
 * Created by Novik Igor on 10.02.2017.
 */
public interface AdvertDAORepository extends CrudRepository<Advert,Integer> {

    List<Advert> findByHead(String head);

}

Spring Data / JPA服務-AdvertDAOImpl

/**
 * Repository bean that implements JPA DAO Advert interfaces responsible for operation with Advertising from DB.
 * <p>
 * Created by nolik on 10.02.17.
 */

@Service("jpaAdvertDAO")
@Repository
@Transactional
public class AdvertDAOImpl implements AdvertDAO {

    @Autowired
    private AdvertDAORepository advertDAORepository;

    @Override
    public List<Advert> findAll() {

        return Lists.newArrayList(advertDAORepository.findAll());
    }

    @Override
    public Advert findByHead(String head) {

        return (Advert) advertDAORepository.findByHead(head);
    }
}

測試MVC控制器:

    @Controller
public class TestController {

    @Autowired
    AdvertDAO jpaAdvertDAO;
    @Autowired
    CommentDAO jpaCommentDAO;

    @RequestMapping(value = "/testCall", method = RequestMethod.GET)
    public ModelAndView readCookieExample() {

        System.out.println(" Test console");
        return new ModelAndView("/error/errorpage");

    }

    @RequestMapping(value = "/jpaFindAllAdvert", method = RequestMethod.GET)
    public ModelAndView jpaFindAllAdvert() {
        System.out.println("ORMController ormFindAllUsers is called");
        List<Advert> adverts = jpaAdvertDAO.findAll();
        return new ModelAndView("/error/test", "resultObject", adverts);

    }

    @RequestMapping(value = "/jpaFindAllComments", method = RequestMethod.GET)
    public ModelAndView jpaFindAllComments() {
        System.out.println("ORMController FindAllComments is called");
        List<Comment> comments = jpaCommentDAO.findAll();
        return new ModelAndView("/error/test", "resultObject", comments);

    }
}

簡單的JSP,用於顯示調用“ / jpaFindAllAdvert”的結果

 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Test</title> </head> <body> <%--<a href="${adverts}" class="list-group-item">Find All Adverts</a>--%> ${resultObject} </body> </html> 

首先,我面臨下一個例外:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: by.GetItFree.entities.Profile.adverts, could not initialize proxy - no Session
org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:563)
org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:205)
org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:542)
org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:133)
org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:509)
java.lang.String.valueOf(String.java:2994)
java.lang.StringBuilder.append(StringBuilder.java:131)
by.GetItFree.entities.Profile.toString(Profile.java:144)
java.lang.String.valueOf(String.java:2994)
java.lang.StringBuilder.append(StringBuilder.java:131)
by.GetItFree.entities.Advert.toString(Advert.java:174)
java.lang.String.valueOf(String.java:2994)
java.lang.StringBuilder.append(StringBuilder.java:131)
java.util.AbstractCollection.toString(AbstractCollection.java:462)
org.apache.el.lang.ELSupport.coerceToString(ELSupport.java:497)
org.apache.el.lang.ELSupport.coerceToType(ELSupport.java:529)
org.apache.el.ExpressionFactoryImpl.coerceToType(ExpressionFactoryImpl.java:47)
javax.el.ELContext.convertToType(ELContext.java:304)
org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:186)
org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(PageContextImpl.java:944)
org.apache.jsp.WEB_002dINF.view.error.test_jsp._jspService(test_jsp.java:118)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:443)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:385)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:329)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:168)
org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1271)
org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1037)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)

我在Google上搜索到,這是Hibernate對帶有@ManyToONe關系的Join進行Leazy初始化的N + 1 SQL問題的結果。

我使用添加以下內容的方法進行修復:在“ Jpa屬性”中添加<prop key="hibernate.enable_lazy_load_no_trans">true</prop>

在此之后,我面臨:StackOverflow exeption:

java.lang.StackOverflowError
java.util.AbstractCollection.toString(AbstractCollection.java:454)
org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:510)
java.lang.String.valueOf(String.java:2994)
java.lang.StringBuilder.append(StringBuilder.java:131)
by.GetItFree.entities.Profile.toString(Profile.java:144)
java.lang.String.valueOf(String.java:2994)
java.lang.StringBuilder.append(StringBuilder.java:131)
by.GetItFree.entities.Advert.toString(Advert.java:174)
java.lang.String.valueOf(String.java:2994)
java.lang.StringBuilder.append(StringBuilder.java:131)
java.util.AbstractCollection.toString(AbstractCollection.java:462)
org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:510)
java.lang.String.valueOf(String.java:2994)
java.lang.StringBuilder.append(StringBuilder.java:131)
by.GetItFree.entities.Profile.toString(Profile.java:144)
java.lang.String.valueOf(String.java:2994)
java.lang.StringBuilder.append(StringBuilder.java:131)
by.GetItFree.entities.Advert.toString(Advert.java:174)

等等-非常長的清單

在Tocat中,在最后一種情況下登錄-我看到很大的列表JPQL /或HSQL,但我不知道:

  RMController ormFindAllUsers is called
Hibernate: select advert0_.id as id1_1_, advert0_.content as content2_1_, advert0_.date as date3_1_, advert0_.head as head4_1_, advert0_.image as image5_1_, advert0_.karmaReq as karmaReq6_1_, advert0_.ordered as ordered7_1_, advert0_.profile_users_username as profile_9_1_, advert0_.profile_id as profile_8_1_ from Advert advert0_
Hibernate: select profile0_.users_username as users_us1_5_0_, profile0_.id as id2_5_0_, profile0_.icon as icon3_5_0_, profile0_.karma as karma4_5_0_, profile0_.phone as phone5_5_0_, users1_.username as username1_6_1_, users1_.enabled as enabled2_6_1_, users1_.password as password3_6_1_ from Profile profile0_ inner join Users users1_ on profile0_.users_username=users1_.username where profile0_.users_username=? and profile0_.id=?
Hibernate: select adverts0_.profile_users_username as profile_9_1_0_, adverts0_.profile_id as profile_8_1_0_, adverts0_.id as id1_1_0_, adverts0_.id as id1_1_1_, adverts0_.content as content2_1_1_, adverts0_.date as date3_1_1_, adverts0_.head as head4_1_1_, adverts0_.image as image5_1_1_, adverts0_.karmaReq as karmaReq6_1_1_, adverts0_.ordered as ordered7_1_1_, adverts0_.profile_users_username as profile_9_1_1_, adverts0_.profile_id as profile_8_1_1_ from Advert adverts0_ where adverts0_.profile_users_username=? and adverts0_.profile_id=?
Hibernate: select profile0_.users_username as users_us1_5_0_, profile0_.id as id2_5_0_, profile0_.icon as icon3_5_0_, profile0_.karma as karma4_5_0_, profile0_.phone as phone5_5_0_, users1_.username as username1_6_1_, users1_.enabled as enabled2_6_1_, users1_.password as password3_6_1_ from Profile profile0_ inner join Users users1_ on profile0_.users_username=users1_.username where profile0_.users_username=? and profile0_.id=?

我在github上的progectProgectSourceCode

這種行為的原因是什么。 那有什么解決方案? 感謝您的關注和支持。

您遇到此問題的原因是,應在事務邊界內初始化視圖所需的關聯,以避免LazyInitializationException 添加選項以在事務外部加載集合只是一個臨時任務,並不能真正解決代碼的潛在設計缺陷。

如果您的視圖要求您加載Profile及其與之關聯的Advert實體集合,則您的數據訪問權限應專門切換該行為,或者查詢指定您需要初始化該集合。

您可以通過多種方式觸發此集合作為查詢的一部分進行加載。

  • JPQL / HQL在adverts集合上使用JOIN FETCH
  • 使用Criteria API指定聯接提取
  • 使用@FetchProfile按名稱切換特定的提取策略。
  • 使用@NamedEntityGraph

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM