হাইবারনেট ব্যতিক্রমটি কীভাবে "অলসভাবে ভূমিকা সংকলনের সূচনা করতে ব্যর্থ হয়েছে" সমাধান করবেন


363

আমার এই সমস্যা আছে:

org.hibernate.LazyInitializationEception: অলসভাবে ভূমিকা সংগ্রহের সূচনা করতে ব্যর্থ: mvc3.model.Topic.comments, কোনও অধিবেশন বা অধিবেশন বন্ধ ছিল না

মডেলটি এখানে:

@Entity
@Table(name = "T_TOPIC")
public class Topic {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;

    @ManyToOne
    @JoinColumn(name="USER_ID")
    private User author;

    @Enumerated(EnumType.STRING)    
    private Tag topicTag;

    private String name;
    private String text;

    @OneToMany(mappedBy = "topic", cascade = CascadeType.ALL)
    private Collection<Comment> comments = new LinkedHashSet<Comment>();

    ...

    public Collection<Comment> getComments() {
           return comments;
    }

}

নিয়ামক, যা মডেলকে নিম্নলিখিতগুলির মতো দেখায়:

@Controller
@RequestMapping(value = "/topic")
public class TopicController {

    @Autowired
    private TopicService service;

    private static final Logger logger = LoggerFactory.getLogger(TopicController.class);


    @RequestMapping(value = "/details/{topicId}", method = RequestMethod.GET)
    public ModelAndView details(@PathVariable(value="topicId") int id)
    {

            Topic topicById = service.findTopicByID(id);
            Collection<Comment> commentList = topicById.getComments();

            Hashtable modelData = new Hashtable();
            modelData.put("topic", topicById);
            modelData.put("commentList", commentList);

            return new ModelAndView("/topic/details", modelData);

     }

}

Jsp- পৃষ্ঠাতে নিম্নলিখিতটি দেখতে পাবেন:

<%@page import="com.epam.mvc3.helpers.Utils"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
      <title>View Topic</title>
</head>
<body>

<ul>
<c:forEach items="${commentList}" var="item">
<jsp:useBean id="item" type="mvc3.model.Comment"/>
<li>${item.getText()}</li>

</c:forEach>
</ul>
</body>
</html>

ব্যতিক্রম উত্থাপিত হয়, যখন jsp দেখুন। সি দিয়ে লাইনে : প্রতিটি লুপ

উত্তর:


214

আপনি যদি জানেন যে আপনি Commentপ্রতিবারের মতো পুনরুদ্ধার করার সময় আপনি সমস্ত দেখতে চান Topicতবে এর জন্য আপনার ফিল্ড ম্যাপিংটি এতে পরিবর্তন করুন comments:

@OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();

সংগ্রহগুলি অলস লোড ডিফল্টরূপে হয়, কটাক্ষপাত করা এই যদি আপনি আরো জানতে চাই।


35
দুঃখিত, তবে আমি অলস বোঝা ব্যবহার করতে চাই। সুতরাং, আমি 'লিঙ্কডহ্যাশসেট' টাইপ টি 'পার্সেন্টিস্টলিস্ট' পরিবর্তন করেছি। ব্যতিক্রম এখনও ঘটে
ইউজিন

242
এটি কার্যকরভাবে হিসাবে ব্যবহার করা যেতে পারে, তবে সমস্যার আসল সমাধান নয়। আমাদের যদি অলসভাবে আনা দরকার?
Dkyc

14
তবে যদি আমরা অলস চান তবে এই সমাধানটি কার্যকর হবে না এবং বেশিরভাগ ক্ষেত্রে আমরা কেবল অলসতা চাই।
প্রশান্ত ঠাকরে 6'15

103
এটি উত্তরের ধরণ যা স্ট্যাক ওভারফ্লোতে সর্বত্র পপ আপ হয়। সংক্ষেপে, সমস্যাটি এবং বিভ্রান্তির সমাধান করে। ভবিষ্যতের পাঠকদের কাছে নিজেই অনুগ্রহ করুন এবং অলস এবং আগ্রহের সাথে কী উত্পন্ন হয়েছে তা শিখুন এবং এর পরিণতিগুলি বুঝতে পারবেন।
সিড

13
@darrengorman আমি যখন জেপিএ শুরু করি তখন আমি ওপির একটির লাইনের চারপাশে একটি প্রশ্ন পোস্ট করি। আপনি যেমনটি দিয়েছেন তেমন প্রতিক্রিয়াও পেয়েছি। শীঘ্রই যথেষ্ট যখন আমি কয়েক হাজার সারি নিয়ে কিছু পরীক্ষা চালিয়েছিলাম, অনুমান করুন কী হয়েছিল? আমি মনে করি এটি বিভ্রান্তিকর কারণ এটি একটি সমস্যার উত্তরের একটি সহজ সরল প্রতিক্রিয়া সরবরাহ করে যা বেশিরভাগ প্রাথমিকভাবে মুখোমুখি হয় এবং খুব শীঘ্রই তারা সাবধান না হলে তাদের পুরো ডাটাবেস মেমরিতে লোড করবে (এবং তারা করবে না, কারণ তারা তা করবে না) এটি সচেতন থাকুন) :)।
সিড

182

আমার অভিজ্ঞতা থেকে, বিখ্যাত LazyInitializationException সমাধান করার জন্য আমার কাছে নীচের পদ্ধতিগুলি রয়েছে:

(1) হাইবারনেট.ইনাইটালাইজ ব্যবহার করুন

Hibernate.initialize(topics.getComments());

(২) যোগদান করুন ফেচ

আপনি আপনার জেপিকিউএল-এ জয়েন্ট ফাইচ সিনট্যাক্সটি স্পষ্টভাবে বাচ্চাদের সংগ্রহ আনার জন্য ব্যবহার করতে পারেন। এটি কিছুটা EAGER আনার মতো।

(3) ওপেনসেশনআইভিউ ফিল্টার ব্যবহার করুন

LazyInitialization ধারণা প্রায়শই ভিউ লেয়ারে ঘটে। যদি আপনি স্প্রিং ফ্রেমওয়ার্ক ব্যবহার করেন তবে আপনি ওপেনসেশনআইভিউ ফিল্টার ব্যবহার করতে পারেন। তবে, আমি আপনাকে এটি করার পরামর্শ দিচ্ছি না। সঠিকভাবে ব্যবহার না করা পারফরম্যান্স সমস্যার দিকে নিয়ে যায় issue


5
(1) আমার পক্ষে নিখুঁতভাবে কাজ করেছে। আমার কেস: হাইবারনেট.ইনাইটালাইজাইজ (রেজিস্ট্রি.টেটভিহিকল ()। গেটওউনার ()। গেটপারসন ()। গেটএড্রেস ());
লিওনেল সানচা দা সিলভা

6
দেখে মনে হচ্ছে যে হাইবারনেট.ইনাইটায়ালাইজটি এন্টি ম্যানেজারের সাথে কাজ করে না
marionmaiden

8
এটি সঠিক উত্তর হওয়া উচিত। উদাহরণস্বরূপ কর্মক্ষেত্রে আমার প্রকল্পে আমরা স্পষ্টতই ইগ্রার আনয়ন ব্যবহার করার কথা না। এটি এই নির্দিষ্ট সিস্টেমে সমস্যা সৃষ্টি করে।
স্টিভ ওয়াটারস

আকর্ষণীয় বলে মনে হচ্ছে তবে অন্য কোনও ক্ষেত্রে প্রয়োগের জন্য ডকুমেন্টেশনের অভাব ... আপনি কীভাবে এই সমাধানটি বাস্তবায়ন করবেন সে সম্পর্কে আরও কিছু লিঙ্ক বা ব্যাখ্যা সরবরাহ করতে পারেন?
পাইপো

58

আমি জানি এটি একটি পুরানো প্রশ্ন তবে আমি সহায়তা করতে চাই। আপনার প্রয়োজনীয় পরিষেবা পদ্ধতিতে আপনি লেনদেনের টীকাটি রাখতে পারেন, এক্ষেত্রে ফাইন্ডটপাইকাইড (আইডি) থাকা উচিত

@Transactional(propagation=Propagation.REQUIRED, readOnly=true, noRollbackFor=Exception.class)

এই টীকাটি সম্পর্কে আরও তথ্য এখানে পাওয়া যাবে

অন্যান্য সমাধান সম্পর্কে:

fetch = FetchType.EAGER 

এটি একটি ভাল অনুশীলন নয়, প্রয়োজনে এটি শুধুমাত্র ব্যবহার করা উচিত।

Hibernate.initialize(topics.getComments());

হাইবারনেট ইনিশিয়ালাইজার আপনার ক্লাসগুলিকে হাইবারনেট প্রযুক্তিতে আবদ্ধ করে। আপনি যদি নমনীয় হওয়ার লক্ষ্য রাখেন তবে যাওয়ার ভাল উপায় নয়।

আশা করি এটা সাহায্য করবে


3
@ ট্রান্সজেকশনাল টিকাটি আমার পক্ষে কাজ করেছে তবে নোট করুন যে প্রচার কমপক্ষে স্প্রিট বুট ১.৪.২ (স্প্রিং ৪.৩) এ ডিফল্ট।
ben3000

4
হ্যাঁ এটি হ'ল, তবে আমি ভেবেছিলাম যে এটি স্পষ্ট করে আপনি প্রকৃতপক্ষে প্রচারের পরিবর্তনটি পরিবর্তন করতে পারবেন
প্রশংসনীয় লপেক্সে

নয় @Transactionalএকটি বসন্ত শুধুমাত্র জিনিস?
ক্যাম্পা

@ ক্যাম্পা হ্যাঁ এটি আপনি যদি এটি ম্যানুয়ালি হ্যান্ডেল করতে চান তবে আপনার ব্যবসায়ের যুক্তিটি সত্তা ম্যানেজারের কাছ থেকে প্রাপ্ত কোনও লেনদেনের মধ্যে রেখে দেওয়া উচিত
sarbuLopex

54

আপনার সমস্যার উত্স:

ডিফল্টরূপে হাইবারনেট অলসভাবে সংগ্রহগুলি (সম্পর্কগুলি) লোড করে যার অর্থ আপনি যখনই নিজের কোডটিতে collection( ক্লাসে এই commentsক্ষেত্রটি Topic) ব্যবহার করেন তখন হাইবারনেট ডাটাবেস থেকে পেয়ে যায়, এখন সমস্যাটি হ'ল আপনি নিজের কন্ট্রোলারে সংগ্রহ পেয়ে যাচ্ছেন (যেখানে জেপিএ সেশন) বন্ধ আছে) .এটি কোডের লাইনটি ব্যতিক্রম ঘটায় (যেখানে আপনি commentsসংগ্রহটি লোড করছেন ):

    Collection<Comment> commentList = topicById.getComments();

আপনি আপনার নিয়ামকটিতে "মন্তব্য" সংগ্রহ (টপিক.জেটকমেন্টস ()) পাচ্ছেন (যেখানে JPA sessionশেষ হয়েছে) এবং এটি ব্যতিক্রম ঘটায়। এছাড়াও যদি আপনি এইভাবে commentsআপনার জেএসপি ফাইলে সংগ্রহটি পেতেন (এটি আপনার নিয়ামকটিতে না যাওয়ার পরিবর্তে):

<c:forEach items="topic.comments" var="item">
//some code
</c:forEach>

আপনার এখনও একই কারণে একই ব্যতিক্রম থাকবে।

সমস্যা সমাধান:

যেহেতু আপনার FetchType.Eagerসত্ত্বা শ্রেণিতে (অধীর আগ্রহে সংগ্রহের) সাথে মাত্র দুটি সংগ্রহ থাকতে পারে এবং যেহেতু অলস লোডটি অধীর আগ্রহে লোডিংয়ের চেয়ে বেশি দক্ষ, তাই আমি মনে করি আপনার সমস্যা সমাধানের এই উপায়টি কেবল FetchTypeআগ্রহী থেকে পরিবর্তনের চেয়ে ভাল :

আপনি যদি সংগ্রহটি অলসভাবে শুরু করতে চান এবং এই কাজটি করতে চান তবে কোডের এই স্নিপেটটি আপনার যুক্ত করা আরও ভাল web.xml:

<filter>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

এই কোডটি যা করে তা হ'ল এটি আপনার দৈর্ঘ্য বাড়িয়ে দেবে JPA sessionবা ডকুমেন্টেশন যেমন বলে, এটি ব্যবহার করা হয় "to allow for lazy loading in web views despite the original transactions already being completed."যাতে এভাবে জেপিএ সেশনটি আরও দীর্ঘ খোলা হবে এবং এর কারণে আপনি অলসভাবে আপনার জেএসপি ফাইল এবং নিয়ন্ত্রণকারী ক্লাসে সংগ্রহগুলি লোড করতে পারবেন ।


7
জেপিএস অধিবেশন কেন বন্ধ? কীভাবে এটি বন্ধ হচ্ছে না? কীভাবে অলস সংগ্রহ করবেন?
Dims

1
দুটি ফেচটাইপের সীমাটি কী সংজ্ঞায়িত করে? প্রতি সত্তা প্রতি বয়স্ক সংগ্রহ?
ক্রিসিনমটাউন

স্প্রিং বুটে, আপনি 'অ্যাপ্লিকেশন.প্রপার্টি'-তে' বসন্ত.জপা.ওপেন-ইন-ভিউ = সত্য 'যুক্ত করতে পারেন
আসকর

28

কারণ হ'ল আপনি যখন অলস লোড ব্যবহার করেন তখন সেশনটি বন্ধ হয়ে যায়।

দুটি সমাধান আছে।

  1. অলস বোঝা ব্যবহার করবেন না।

    সেট lazy=falseXML বা সেটে @OneToMany(fetch = FetchType.EAGER)সালে টীকা।

  2. অলস বোঝা ব্যবহার করুন।

    সেট lazy=trueXML বা সেটে @OneToMany(fetch = FetchType.LAZY)সালে টীকা।

    এবং OpenSessionInViewFilter filterআপনার যোগ করুনweb.xml

বিস্তারিত আমার পোস্ট দেখুন ।


1
... এবং তবুও উভয় সমাধান ভাল নয়। EAGER ব্যবহারের পরামর্শ দিয়ে বিশাল সমস্যা তৈরি করতে পারে। ওপেনসেশনআইভিভিউ ফিল্টার ব্যবহার করা একটি অ্যান্টি-প্যাটার্ন।
রাফেল

27
@Controller
@RequestMapping(value = "/topic")
@Transactional

আমি যুক্ত করে এই সমস্যাটি সমাধান @Transactionalকরি, আমি মনে করি এটি অধিবেশন উন্মুক্ত করতে পারে


কেন এটি একটি বিয়োগ ভোট পেয়েছে? অপারেশনে একটি লেনদেন যুক্ত করা অধিবেশনটির প্রসারিত করে
টিউডর গ্রিগরিউ

1
নিয়ন্ত্রকের @ লেনদেনের বিজ্ঞাপন দেওয়া খারাপ অভ্যাস।
রাফায়েল

@ রাফায়েল কেন এটি একটি খারাপ অভ্যাস?
আমর এলফায়ে

: - @AmrEllafy> এখানে এটা একটা ভালো ব্যাখ্যা stackoverflow.com/a/18498834/1261162
রাফায়েল

22

হাইবারনেট সেশন বন্ধ হওয়ার সাথে সাথে একটি অ্যাট্রিবিউট অ্যাক্সেস করার কারণে সমস্যাটি দেখা দেয়। আপনার নিয়ামকটিতে হাইবারনেট লেনদেন নেই।

সম্ভাব্য সমাধান:

  1. কন্ট্রোলারে নয়, সার্ভিস লেয়ারে (@ ট্রানজেকশনাল সহ) এই সমস্ত যুক্তিটি করুন। এটি করার জন্য সঠিক জায়গা হওয়া উচিত, এটি অ্যাপ্লিকেশনটির যুক্তির অংশ, নিয়ামক নয় (এই ক্ষেত্রে, মডেলটি লোড করার জন্য একটি ইন্টারফেস)। পরিষেবা স্তরের সমস্ত ক্রিয়াকলাপ লেনদেনের হওয়া উচিত। অর্থাত: এই লাইনটি টপিকসেসার্স.ফাইন্ডটপিকবিআইআইডি পদ্ধতিতে সরান:

    সংগ্রহ কমেন্টলিস্ট = টপটিবিআইআইডি.জেটকমেন্টস ();

  2. 'অলস' পরিবর্তে 'উত্সাহী' ব্যবহার করুন । এখন আপনি 'অলস' ব্যবহার করছেন না .. এটি আসল সমাধান নয়, আপনি যদি অলস ব্যবহার করতে চান তবে অস্থায়ী (খুব অস্থায়ী) কাজের মতো কাজ করে।

  3. কন্ট্রোলারে @ লেনদেন ব্যবহার করুন । এটি এখানে ব্যবহার করা উচিত নয়, আপনি উপস্থাপনার সাথে পরিষেবা স্তর মিশ্রণ করছেন, এটি কোনও ভাল নকশা নয়।
  4. ওপেনসেশনআইভিভিউ ফিল্টার ব্যবহার করুন , অনেকগুলি অসুবিধাগুলি জানা গেছে, সম্ভাব্য অস্থিরতা।

সাধারণভাবে, সর্বোত্তম সমাধানটি হ'ল 1।



আপনার উচিত উচিত যে সর্বোত্তম সমাধানটি 1 হ'ল ... সত্যিকার অর্থেই কেবলমাত্র ভাল সমাধান যেহেতু অন্য সমস্ত নিদর্শন বিরোধী!
রাফায়েল

19

কোনও সংগ্রহকে অলস করতে হলে একটি সক্রিয় সেশন হতে হবে। একটি ওয়েব অ্যাপে এটি করার দুটি উপায় রয়েছে। আপনি ওপেন সেশন ইন ভিউ প্যাটার্নটি ব্যবহার করতে পারেন, যেখানে আপনি অনুরোধের শুরুতে সেশনটি খোলার জন্য একটি ইন্টারসেপ্টর ব্যবহার করেন এবং এটি শেষে বন্ধ করুন। ঝুঁকিটি হ'ল আপনার শক্ত ব্যতিক্রম হ্যান্ডলিং করতে হবে বা আপনি আপনার সমস্ত সেশন বেঁধে রাখতে পারেন এবং আপনার অ্যাপ্লিকেশনটি স্তব্ধ হয়ে যেতে পারে।

এটি পরিচালনা করার অন্য উপায়টি হ'ল আপনার নিয়ামকটিতে আপনার প্রয়োজনীয় সমস্ত ডেটা সংগ্রহ করা, আপনার সেশনটি বন্ধ করা এবং তারপরে আপনার মডেলটিতে ডেটা স্টাফ করা। আমি ব্যক্তিগতভাবে এই পদ্ধতির পছন্দ করি, কেননা এটি এমভিসি প্যাটার্নের চেতনার সামান্য কাছাকাছি মনে হয়। এছাড়াও যদি আপনি এইভাবে ডাটাবেস থেকে কোনও ত্রুটি পান তবে আপনি এটি আপনার ভিউ রেন্ডারারে ঘটলে এর চেয়ে অনেক বেশি ভাল পরিচালনা করতে পারেন। এই দৃশ্যে আপনার বন্ধু হ'ল হাইবারনেট.ইনাইটালাইজ (মাই টপিক.জেটকমেন্টস ())। আপনি প্রতিটি অনুরোধের সাথে একটি নতুন লেনদেন তৈরি করছেন যেহেতু, আপনি অধিবেশনটিতে পুনরায় সংযুক্ত করতে হবে। তার জন্য সেশন.লক (মাইটপিক, লকমোড.নোন) ব্যবহার করুন।


15

যেমনটি আমি এই নিবন্ধে ব্যাখ্যা করেছি , হ্যান্ডেল করার সর্বোত্তম উপায় LazyInitializationExceptionহ'ল ক্যোয়ারির সময় এটি এড়ানো, এর মতো:

select t
from Topic t
left join fetch t.comments

আপনার নীচের অ্যান্টি-প্যাটার্নগুলি সবসময় এড়ানো উচিত:

অতএব, নিশ্চিত হয়ে নিন যে আপনার FetchType.LAZYসমিতিগুলি কোয়েরি সময়ে বা দ্বিতীয় সংগ্রহের জন্য @Transactionalব্যবহার করে মূল ক্ষেত্রের মধ্যেই সূচনা হয়েছিল Hibernate.initialize


1
একটি স্প্রিং-উত্পাদিত সংগ্রহস্থলের ফাইবআইআইডি () পদ্ধতি দ্বারা প্রাপ্ত কোনও সত্তায় অলস-সূচনা সম্পন্ন সংগ্রহের সাথে কাজ করার জন্য আপনার কী পরামর্শ আছে? আমি কোয়েরিটি লিখছি না এবং লেনদেনটি আমার কোডের বাইরে।
ক্রিসিনমটাউন

পরীক্ষা করে দেখুন এই নিবন্ধটি অলস সংগ্রহের আরম্ভের সম্পর্কে আরো বিস্তারিত জানার জন্য।
ভ্লাদ মিহালসিয়া

'মূল @ ট্রান্সজেকশনাল স্কোপের অভ্যন্তরে' আপনি কী বোঝাতে চেয়েছেন তা কি আপনি স্পষ্ট করে বলতে পারেন যে খোলা অধিবেশন চলাকালীন আমি এই ত্রুটিটি পেয়েছি বলে মনে হচ্ছে (তবে সঠিকটি নয়?)
মিচিয়েল হায়সমা

ক্ষেত্রের মধ্যে থাকা ও শীর্ষস্থানীয় সর্বাধিক লেনদেনের পরিষেবা পদ্ধতি, যা লেনদেনের প্রবেশদ্বার হিসাবেও পরিচিত। TrassctionInterceptorস্ট্যাক ট্রেসের মধ্যে যাচাই করুন এবং এটিই একটি।
ভ্লাদ মিহলসিয়া

এখন পর্যন্ত অন্যতম সেরা উত্তর ... এটি সঠিক হিসাবে চিহ্নিত করা উচিত। বিটিডাব্লু ... ওএসআইভি ধরে নিয়ে যাওয়া একটি অ্যান্টি-প্যাটার্ন এটি কীভাবে সম্ভব যে স্প্রিং-বুটের সাম্প্রতিক সংস্করণগুলিতে ডিফল্টরূপে সক্ষম করা যায়? ... সম্ভবত খারাপ না?
রাফায়েল

10

আপনি যদি কোনও সত্তা এবং সংগ্রহের সাথে জাভা অবজেক্টের (উদাহরণস্বরূপ দীর্ঘ টাইপ) তালিকার মধ্যে সম্পর্ক স্থাপনের চেষ্টা করছেন তবে এটি এর মতো কিছু চাই:

@ElementCollection(fetch = FetchType.EAGER)
    public List<Long> ids;

1
অনেক ক্ষেত্রে, আপনি সত্যিই এটি করতে চান না। আপনি এখানে অলস লোডিংয়ের সমস্ত সুবিধা আলগা করে
রেখেছেন

EAGER ব্যবহার করা কোনও পেশাদার সমাধান নয়।
রাফেল

9

সর্বোত্তম সমাধানগুলির মধ্যে একটি হ'ল আপনার অ্যাপ্লিকেশন.প্রপার্টি ফাইলগুলিতে নিম্নলিখিতগুলি যুক্ত করা: স্প্রিং.জেপা.পোপারটিস.ইবার্নেট.এনেবল_লাজি_লোড_নো_ট্রান্স = সত্য


1
ওপিকে কী বলতে পারে এটি ঠিক কী করে, কোনও পার্শ্ব প্রতিক্রিয়া, পারফরম্যান্স প্রভাব?
পিএস

3
অলস লোডিংয়ের পিছনে, অ্যাসোসিয়েশন প্রতিটি সময় অলসভাবে লোড করা হওয়ার সময় একটি নতুন অধিবেশনটি কাঁটাচামচ করা হয়, তাই আরও সংযোগ কাঁটাচামচ করা হয় এবং সংযোগ পুলের উপরে কিছুটা চাপ সৃষ্টি করে। আপনার যদি সংযোগের সংখ্যার সীমা থাকে তবে এই সম্পত্তিটি ব্যবহারের জন্য সঠিক হতে পারে না।
শ্রীমত্ত

2
কারও কারও কাছে এটি একটি অ্যান্টি-প্যাটার্ন ভ্লাদমিহালসিয়া.com
উরি লোয়া

7

আমি বুঝতে পারলাম যে ঘোষণা @PersistenceContextযেমন EXTENDEDএই সমস্যা solves:

@PersistenceContext(type = PersistenceContextType.EXTENDED)

1
হাই, এই ধরনের পরিবর্তনগুলি সম্পর্কে সাবধানতা অবলম্বন করুন। ট্রান্সএকশন স্কোপড অধ্যবসায় প্রসঙ্গ তৈরির কাজটি অলস, যা ওপি অভিপ্রায় ছিল। সুতরাং প্রশ্ন আপনি রাষ্ট্রবিহীন হতে চান বা না হয়। এই সেটিংটি সিস্টেমের উদ্দেশ্যের উপর নির্ভরশীল এবং খুব ... উত্সাহের সাথে পরিবর্তন করা উচিত নয়। আপনি আমি বলতে চাচ্ছি তা জানেন. এখানে পড়ুন stackoverflow.com/questions/2547817/...
kiedysktos

বিপজ্জনক। এটি সঠিক উত্তর নয়। আরও অনেক নির্ভুল এবং নিরাপদ উপরে অন্য রয়েছে।
রাফায়েল

5

এটি হ'ল আমি সম্প্রতি যে সমস্যার মুখোমুখি হয়েছি যা ব্যবহার করে সমাধান করেছি

<f:attribute name="collectionType" value="java.util.ArrayList" />

আরো decription বিস্তারিত এখানে এবং এটি হল আমার দিন সংরক্ষণ করা হয়েছে।


5

আপনার তালিকাটি অলস লোডিং, সুতরাং তালিকাটি লোড করা হয়নি। তালিকায় নামার জন্য কল যথেষ্ট নয়। তালিকাটি আরম্ভ করার জন্য হাইবারনেট.ইনাইটালাইজে ব্যবহার করুন। যদি তালিকার কাজ তালিকার উপাদানটিতে চলে এবং প্রত্যেকের জন্য হাইবারনেট.ইনাইটালাইজ কল করুন। আপনার লেনদেনের সুযোগ থেকে ফিরে আসার আগে এটি হওয়া দরকার। তাকান এই পোস্ট।
সন্ধান করা -

Node n = // .. get the node
Hibernate.initialize(n); // initializes 'parent' similar to getParent.
Hibernate.initialize(n.getChildren()); // pass the lazy collection into the session 

4

আমার ক্ষেত্রে সমস্যাটি সমাধান করার জন্য এটি কেবল এই লাইনটি অনুপস্থিত ছিল

<tx:annotation-driven transaction-manager="myTxManager" />

অ্যাপ্লিকেশন-প্রসঙ্গ ফাইলটিতে।

@Transactionalএকটি পদ্ধতি উপর টীকা বিবেচনায় নেয়া হয়নি।

আশা করি উত্তরটি কারও কাজে আসবে


4

কন্ট্রোলারে ট্রানজেকশনাল টিকাটি অনুপস্থিত

@Controller
@RequestMapping("/")
@Transactional
public class UserController {
}

17
আমি যুক্তি দিয়ে বলব যে লেনদেন পরিচালনা সেবার লেয়ারের যেখানে ব্যবসায়িক যুক্তি রয়েছে।
সাবার

লেনদেনের টীকাটি অনুপস্থিত। কন্ট্রোলারের এ জাতীয় মন্তব্য থাকা উচিত নয়। এই টীকাগুলি পরিষেবা স্তরে হওয়া উচিত।
রাফেল

4

হাইবারনেট @Transactionalটীকাটি ব্যবহার করে , যদি আপনি অলস ফ্যাচযুক্ত বৈশিষ্ট্যযুক্ত ডাটাবেস থেকে কোনও বস্তু পেয়ে থাকেন তবে আপনি এই জাতীয় বৈশিষ্ট্যগুলি আনার মাধ্যমে কেবল এটি পেতে পারেন:

@Transactional
public void checkTicketSalePresence(UUID ticketUuid, UUID saleUuid) {
        Optional<Ticket> savedTicketOpt = ticketRepository.findById(ticketUuid);
        savedTicketOpt.ifPresent(ticket -> {
            Optional<Sale> saleOpt = ticket.getSales().stream().filter(sale -> sale.getUuid() == saleUuid).findFirst();
            assertThat(saleOpt).isPresent();
        });
}

এখানে, একটি হাইবারনেট প্রক্সি-পরিচালিত লেনদেনে, কলিংয়ের সত্যতা ticket.getSales()বিক্রয় আনার জন্য আরও একটি ক্যোয়ারী করায় কারণ আপনি এটি স্পষ্টভাবে জিজ্ঞাসা করেছিলেন।


4

দুটি জিনিস আপনার জন্য হওয়া উচিত fetch = FetchType.LAZY

@Transactional

এবং

Hibernate.initialize(topicById.getComments());

2

যারা মানদণ্ডের সাথে কাজ করছেন , আমি তাদের খুঁজে পেয়েছি

criteria.setFetchMode("lazily_fetched_member", FetchMode.EAGER);

আমার যা কিছু প্রয়োজন ছিল তা করেছে।

সংগ্রহের জন্য প্রাথমিক আনয়ন মোডটি পারফরম্যান্স সরবরাহের জন্য ফেচমোড.লাজেতে সেট করা হয়েছে, তবে যখন আমার ডেটার প্রয়োজন হয়, আমি কেবল সেই লাইনটি যুক্ত করি এবং সম্পূর্ণ জনবহুল অবজেক্ট উপভোগ করি।


2

আমার ক্ষেত্রে নিম্নলিখিত কোডগুলি একটি সমস্যা ছিল:

entityManager.detach(topicById);
topicById.getComments() // exception thrown

কারণ এটি ডাটাবেস থেকে পৃথক হয়ে যায় এবং যখন প্রয়োজন হয় তখন হাইবারনেট ক্ষেত্র থেকে আর তালিকাটি পুনরুদ্ধার করে না। সুতরাং আমি বিচ্ছিন্ন করার আগে এটি সূচনা:

Hibernate.initialize(topicById.getComments());
entityManager.detach(topicById);
topicById.getComments() // works like a charm

1

কারণটি হ'ল আপনি পরিষেবার ভিতরে সেশনটি বন্ধ করার পরে আপনার নিয়ামককে কমেন্টলিস্ট পাওয়ার চেষ্টা করছেন।

topicById.getComments();

উপরের মন্তব্যটি কেবলমাত্র লোড করবে যদি আপনার হাইবারনেট সেশনটি সক্রিয় থাকে তবে আমার ধারণা আপনি আপনার পরিষেবা বন্ধ করে দিয়েছিলেন।

সুতরাং, সেশনটি বন্ধ করার আগে আপনাকে কমেন্টলিস্টটি পেতে হবে।


2
হ্যাঁ, এটি সমস্যার বিবৃতি, আপনার একটি উত্তর দেওয়া উচিতAnswer
সার্জ

1

commentsআপনার মডেল শ্রেণীর সংগ্রহটি Topicঅলসভাবে লোড করা হয়েছে, এটি যদি আপনি fetch = FetchType.EAGERনির্দিষ্টভাবে উল্লেখ না করেন তবে এটি ডিফল্ট আচরণ ।

বেশিরভাগ ক্ষেত্রেই সম্ভবত আপনার findTopicByIDপরিষেবা স্টেটহীন হাইবারনেট সেশনটি ব্যবহার করছে। একটি রাষ্ট্রবিহীন সেশনে প্রথম স্তরের ক্যাশে থাকে না, অর্থাৎ দৃ pers়তার প্রসঙ্গ নেই context পরে যখন আপনি পুনরাবৃত্তি করার চেষ্টা করবেন তখন commentsহাইবারনেট একটি ব্যতিক্রম ছুঁড়ে দেবে।

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: mvc3.model.Topic.comments, no session or session was closed

সমাধান হতে পারে:

  1. টীকা commentsসঙ্গেfetch = FetchType.EAGER

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)   
    private Collection<Comment> comments = new LinkedHashSet<Comment>();
  2. আপনি যদি এখনও মন্তব্যগুলি অলসভাবে বোঝাতে চান তবে হাইবারনেটের স্টেটফুল সেশনগুলি ব্যবহার করুন , যাতে আপনি পরে দাবিতে মন্তব্যগুলি পেতে সক্ষম হবেন।


1

আমার ক্ষেত্রে, আমি ম্যাপিং বি / ডাব্লু Aএবং Bপছন্দ ছিল

A হয়েছে

@OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
Set<B> bs;

মধ্যে DAOস্তর, পদ্ধতি সঙ্গে সটীক করা প্রয়োজন @Transactionalযদি আপনি এর সাথে ম্যাপিং সটীক নি পান প্রকার - উৎসুক


1

সেরা সমাধান নয়, তবে যারা LazyInitializationExceptionবিশেষত এতে মুখোমুখি Serializationতাদের সহায়তা করবে। এখানে আপনি অলসভাবে প্রারম্ভিক বৈশিষ্ট্য এবং nullসেগুলির জন্য সেটিংস পরীক্ষা করবেন । তার জন্য নীচের ক্লাসটি তৈরি করুন

public class RepositoryUtil {
    public static final boolean isCollectionInitialized(Collection<?> collection) {
        if (collection instanceof PersistentCollection)
            return ((PersistentCollection) collection).wasInitialized();
        else 
            return true;
    }   
}

আপনার সত্তা শ্রেণীর ভিতরে যা আপনি অলসভাবে প্রারম্ভিক বৈশিষ্ট্যগুলি পেয়ে যাচ্ছেন নীচে দেখানো মত একটি পদ্ধতি যুক্ত করুন। এই পদ্ধতির ভিতরে আপনার সমস্ত অলস লোডিং বৈশিষ্ট্য যুক্ত করুন।

public void checkLazyIntialzation() {
    if (!RepositoryUtil.isCollectionInitialized(yourlazyproperty)) {
        yourlazyproperty= null;
    }

checkLazyIntialzation()আপনি যে জায়গাতে ডেটা লোড করছেন সেখানে এই পদ্ধতিটি কল করুন।

 YourEntity obj= entityManager.find(YourEntity.class,1L);
  obj.checkLazyIntialzation();

0

হাই হাই পোস্টিং বেশ দেরি করে আশা করি এটি অন্যকে সহায়তা করে, এই পোস্টটি হাইবারনেট.ইনাইটালাইজ (অবজেক্ট) এর জন্য @ জিএমকে অগ্রিম ধন্যবাদ

যখন অলস = "সত্য"

Set<myObject> set=null;
hibernateSession.open
set=hibernateSession.getMyObjects();
hibernateSession.close();

এখন যদি আমি সেশন বন্ধ করার পরে 'সেট' অ্যাক্সেস করি তবে এটি ব্যতিক্রম ছুঁড়ে।

আমার সমাধান:

Set<myObject> set=new HashSet<myObject>();
hibernateSession.open
set.addAll(hibernateSession.getMyObjects());
hibernateSession.close();

হাইবারনেট সেশন বন্ধ করার পরেও এখন আমি 'সেট' অ্যাক্সেস করতে পারি।


0

জিনিসটি করার আরেকটি উপায়, আপনি অলস সংগ্রহের চারপাশে মোড়ানোর জন্য লেনদেনের পরীক্ষাটি ব্যবহার করতে পারেন । মত

Collection<Comment> commentList = this.transactionTemplate.execute
(status -> topicById.getComments());

0

সমস্যাটির কারণ এই কোডটি অলস জেপিএ সম্পর্ক অ্যাক্সেস করছে যখন ডাটাবেসের সাথে "সংযোগ" বন্ধ থাকে ( অধ্যবসায় প্রসঙ্গটি হবারনেট / জেপিএর ক্ষেত্রে সঠিক নাম)।

স্প্রিং বুটে এটি সমাধানের একটি সহজ উপায় হ'ল একটি পরিষেবা স্তর সংজ্ঞায়িত করা এবং @Transactionalটীকাদান ব্যবহার করা । কোনও পদ্ধতিতে এই টীকাটি এমন একটি লেনদেন তৈরি করে যা সংগ্রহস্থল স্তরে প্রচার করে এবং পদ্ধতিটি শেষ না হওয়া পর্যন্ত অধ্যবসায়ের প্রসঙ্গটি খোলা রাখে। আপনি যদি লেনদেনের পদ্ধতির অভ্যন্তরে সংগ্রহটি অ্যাক্সেস করেন তবে হাইবারনেট / জেপিএ ডাটাবেস থেকে ডেটা আনবে।

আপনার যদি, আপনি শুধু সঙ্গে টীকা যোগ করার প্রয়োজন @Transactionalপদ্ধতি findTopicByID(id)আপনার TopicServiceএবং যে পদ্ধতিতে সংগ্রহ আনা (উদাহরণস্বরূপ, এর আকার জিজ্ঞাসা করে) ফোর্স:

    @Transactional(readOnly = true)
    public Topic findTopicById(Long id) {
        Topic topic = TopicRepository.findById(id).orElse(null);
        topic.getComments().size();
        return topic;
    }

0

অলস প্রারম্ভিককরণ ব্যতিক্রম থেকে মুক্তি পাওয়ার জন্য আপনি যখন বিচ্ছিন্ন কোনও বস্তু নিয়ে কাজ করেন তখন অলস সংগ্রহের জন্য আপনাকে কল করা উচিত নয়।

আমার মতে, সর্বোত্তম পন্থা হল ডিটিও ব্যবহার করা, এবং সত্তা নয়। এই ক্ষেত্রে আপনি যে ক্ষেত্রগুলি ব্যবহার করতে চান তা স্পষ্টভাবে সেট করতে পারেন। যথারীতি এটি যথেষ্ট। জ্যাকসনের মতো কিছু ObjectMapperবা hashCodeলোমবকের দ্বারা উত্পাদিত এমন কোনও বিষয় আপনার পদ্ধতিগুলিকে স্পষ্টভাবে কল করবে এমন চিন্তা করার দরকার নেই ।

কিছু নির্দিষ্ট ক্ষেত্রে আপনি @EntityGrpaphটীকাটি ব্যবহার করতে পারেন , যা আপনার সত্তায় eagerথাকলেও আপনাকে বোঝা তৈরি করতে দেয় fetchType=lazy


0

এই অলস সূচনা ইস্যুটির একাধিক সমাধান রয়েছে -

1) অ্যাসোসিয়েশন আনার ধরণটি এলএজিইএই থেকে ইগারে পরিবর্তন করুন তবে এটি একটি ভাল অনুশীলন নয় কারণ এটি কার্য সম্পাদনকে হ্রাস করবে।

2) সম্পর্কিত অবজেক্টের উপর ফেচটাইপ.লাজি ব্যবহার করুন এবং আপনার পরিষেবা স্তর পদ্ধতিতে লেনদেনের টীকাগুলিও ব্যবহার করুন যাতে সেই সেশনটি উন্মুক্ত থাকবে এবং আপনি যখন টপিকে বাই বাইডডেট কমেন্টস () কল করবেন তখন শিশু অবজেক্ট (মন্তব্য) লোড হয়ে যাবে।

3) এছাড়াও, দয়া করে নিয়ামক স্তরে সত্তার পরিবর্তে ডিটিও অবজেক্ট ব্যবহার করার চেষ্টা করুন। আপনার ক্ষেত্রে, সেশনটি নিয়ামক স্তরে বন্ধ রয়েছে। পরিষেবা স্তরটিতে সত্তাকে ডিটিওতে রূপান্তর করতে আরও ভাল।


-11

আমি সেটটির পরিবর্তে তালিকাটি ব্যবহার করে সমাধান করেছি:

private List<Categories> children = new ArrayList<Categories>();
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.