[英]Spring JPA - org.hibernate.LazyInitializationException: could not initialize proxy - no Session
[英]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上的progect : ProgectSourceCode
這種行為的原因是什么。 那有什么解決方案? 感謝您的關注和支持。
您遇到此問題的原因是,應在事務邊界內初始化視圖所需的關聯,以避免LazyInitializationException
。 添加選項以在事務外部加載集合只是一個臨時任務,並不能真正解決代碼的潛在設計缺陷。
如果您的視圖要求您加載Profile
及其與之關聯的Advert
實體集合,則您的數據訪問權限應專門切換該行為,或者查詢指定您需要初始化該集合。
您可以通過多種方式觸發此集合作為查詢的一部分進行加載。
adverts
集合上使用JOIN FETCH
。 @FetchProfile
按名稱切換特定的提取策略。 @NamedEntityGraph
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.