gpt4 book ai didi

java - Spring DATA JPA + Hibernate - 无法初始化代理 - 修复 : 后没有 session

转载 作者:行者123 更新时间:2023-12-01 08:52:46 25 4
gpt4 key购买 nike

大家好。我是 Spring Data + JPA 的新手。我需要你的帮助。这是我在 stackoverflow 上的第一个问题,如果我的问题不正确,很抱歉。

我开始使用Spring Data + JPA + Hibernate、Spring MVC、使用MySQL来实现项目。

我有数据库方案:

DB of project

DB scheme

application context:

<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 Config:

<!--
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/" />

<小时/>

Some of JPA Persistence Entites:

Advert:

@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() 中,一切都会正常。

Profile

@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

AdvertDAO

   /**
* 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);
}

AdvertDAORepository

/**
* 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);
}
}

Test MVC Controller:

    @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);

}
}

Simple JSP for showing result of calling "/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)

我谷歌了一下,这是 Hibernate 与 @ManyToONe 关系连接的 Leazy 初始化的 N+1 SQL 问题的结果。

我使用添加的方法来修复: <prop key="hibernate.enable_lazy_load_no_trans">true</prop> 到“Jpa 属性”

在此之后我遇到了:StackOverflow 异常:

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 Log 的最后一个案例中 - 我看到了大列表 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上的项目:ProgectSourceCode

这种行为的原因是什么?解决办法是什么?感谢您的关注和支持。

最佳答案

您遇到此问题的原因是您的 View 所需的关联应在事务边界内初始化,以避免 LazyInitializationException。添加在事务之外加载集合的选项只是一个创可贴,并不能真正解决代码的底层设计缺陷。

如果您的 View 要求您加载 Profile 及其关联的 Advert 实体集合,那么您的数据访问应该专门切换该行为,或者查询指定您需要初始化该集合。

有多种方法可以触发此集合作为查询的一部分加载。

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

关于java - Spring DATA JPA + Hibernate - 无法初始化代理 - 修复 : 后没有 session ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42283849/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com