হাইবারনেটে বিযুক্ত জিনিসগুলিকে পুনরায় সংযুক্ত করার উপযুক্ত উপায় কী?


186

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

এখনই, আমি দুটি কাজের একটি করতে পারি।

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

  2. getHibernateTemplate().merge( obj ) হাইবারনেট সেশনে কোনও বস্তুর উপস্থিতি থাকলে এবং কেবল এটিই কাজ করে। যদি আমি এটি ব্যবহার করি তবে পরে একটি সেশনে আমার অবজেক্টটি থাকার দরকার হলে ব্যতিক্রমগুলি ছুঁড়ে দেওয়া হয়।

এই দুটি পরিস্থিতি দেওয়া, আমি কীভাবে জেনারেলভাবে বস্তুর সাথে সেশনগুলি সংযুক্ত করতে পারি? এই সমস্যার সমাধানের প্রবাহ নিয়ন্ত্রণ করতে আমি ব্যতিক্রমগুলি ব্যবহার করতে চাই না, কারণ আরও একটি মার্জিত সমাধান থাকতে হবে ...

উত্তর:


181

সুতরাং দেখে মনে হচ্ছে জেপিএতে কোনও বাসি বিচ্ছিন্ন সত্তাকে পুনরায় সংযুক্ত করার কোনও উপায় নেই।

merge() বাসি রাজ্যটিকে ডিবিতে ধাক্কা দেবে, এবং কোনও মধ্যবর্তী আপডেটগুলি ওভাররাইট করবে।

refresh() কোনও বিচ্ছিন্ন সত্তাকে ডাকা যাবে না।

lock() কোনও বিচ্ছিন্ন সত্তার কাছে ডাকা যাবে না, এমনকি যদি তাও হতে পারে এবং এটি সত্তাকে পুনরায় সংযুক্ত করে, 'লকমোড.নোন' যুক্তি দিয়ে কল করে যে আপনি লক করছেন, কিন্তু লক করছেন না, এটি এপিআই নকশার সর্বাধিক বিপরীতমুখী অংশ আমি কখনও দেখেছি।

সুতরাং আপনি আটকে আছেন। একটি detach()পদ্ধতি আছে, কিন্তু না attach()বা reattach()। অবজেক্ট লাইফাইসাইকেলের একটি সুস্পষ্ট পদক্ষেপ আপনার কাছে উপলভ্য নয়।

জেপিএ সম্পর্কিত অনুরূপ প্রশ্নের সংখ্যার বিচার করে মনে হয় যে জেপিএ সুসংগত মডেল থাকার দাবি করেও, এটি অবশ্যই বেশিরভাগ প্রোগ্রামারদের মানসিক মডেলের সাথে মেলে না, যারা বেশ কয়েক ঘন্টা নষ্ট করার অভিশাপ দেওয়া হয়েছিল কীভাবে পাওয়ার তা বোঝার চেষ্টা করে জেপিএ সহজ জিনিসগুলি করতে এবং তাদের সমস্ত অ্যাপ্লিকেশন জুড়ে ক্যাশে পরিচালনা কোড দিয়ে শেষ করে।

এটি করার একমাত্র উপায় হ'ল এটি হল আপনার বাসি বিচ্ছিন্ন সত্তাটিকে বাতিল করা এবং একই আইডি দিয়ে অনুসন্ধান অনুসন্ধান করুন, যা এল 2 বা ডিবিতে আঘাত করবে।

MIK


1
আমি ভাবছি যদি জেপিএ স্পেকটি refresh()বিচ্ছিন্ন সত্তাগুলি অনুমতি দেয় না এমন কোনও কারণ আছে কি ? ২.০ অনুমানের মধ্যে দিয়ে আমি কোনও ন্যায়সঙ্গত দেখতে পাচ্ছি না; এটি অনুমোদিত নয়।
FGreg

11
এটি অবশ্যই সঠিক নয়। জেপিডাব্লুএইচ থেকে: *Reattaching a modified detached instance* A detached instance may be reattached to a new Session (and managed by this new persistence context) by calling update() on the detached object. In our experience, it may be easier for you to understand the following code if you rename the update() method in your mind to reattach()—however, there is a good reason it’s called updating.আরও 9.3.2 বিভাগে পাওয়া যাবে
5:57 এ cwash

অবিচ্ছিন্ন অবজেক্টগুলি দুর্দান্ত কাজ করে, ফ্লাশ () সময়ে প্রাথমিক লোড এবং মান (গুলি) এর মধ্যে ব-দ্বীপের উপর ভিত্তি করে ময়লা পতাকা সেট করা হয়। বিযুক্ত জিনিসগুলির প্রয়োজন, এবং বর্তমানে এই কার্যকারিতাটি নেই। হাইবারনেট করার উপায় হ'ল বিচ্ছিন্ন বস্তুর জন্য অতিরিক্ত হ্যাশ / আইডি যুক্ত করা। এবং অবিচ্ছিন্ন অবজেক্টের জন্য যেমন করুন তারা বিচ্ছিন্ন বস্তুর শেষ অবস্থার স্ন্যাপশট রাখুন। সুতরাং তারা বিদ্যমান বিদ্যমান কোডটি উপকার করতে পারে এবং এটিকে বিযুক্ত বস্তুর জন্য কাজ করতে পারে। @ মিখাইলফ্র্যাঙ্কো হিসাবে এইভাবে উল্লেখ করা হয়েছে যে আমরা "বাসি রাজ্যটিকে ডিবিতে ঠেকাবো না, এবং কোনও হস্তক্ষেপমূলক আপডেটগুলি ওভাররাইট করব না"
টম

2
হাইবারনেট জাভাদোকের (তবে জেপিএ নয়) মতে, lock(LockMode.NONE)আসলে একটি ক্ষণস্থায়ী বস্তুতে ডেকে আনা যেতে পারে, এবং এটি সত্তায় সত্তাকে পুনরায় সংযুক্ত করে। দেখুন stackoverflow.com/a/3683370/14379
seanf

লক আমার পক্ষে কাজ করেনি: java.lang.IllegalArgumentException: org.hibernate.internal.SessionImpl.lock (SessionImpl.java:3491) এ অরগ্যান্ট প্রসঙ্গে নয় সত্তা org.hibernate.intern.SessionImpl.lock (SessionImpl। java: 3482) com.github.vok.framework.DisableTransactionControlEMDelegate.lock (DB.kt)
মার্টিন

32

এই সমস্ত উত্তর একটি গুরুত্বপূর্ণ পার্থক্য মিস। আপডেট () ব্যবহার করে (পুনরায়) আপনার অবজেক্ট গ্রাফটি একটি সেশনে সংযুক্ত করতে ব্যবহৃত হয়। আপনি যে জিনিসগুলি এটি পাস করেন সেগুলি হ'ল পরিচালনা করা হয়।

মার্জ () আসলে কোনও (পুনরায়) সংযুক্তি API নয়। বিজ্ঞপ্তি মার্জ () একটি ফেরতের মান আছে? কারণ এটি আপনাকে পরিচালিত গ্রাফটি ফিরিয়ে দেয়, এটি আপনি যে গ্রাফটি দিয়েছিলেন তা নাও হতে পারে। মার্জ () একটি জেপিএ এপিআই এবং এর আচরণটি জেপিএ স্পেক দ্বারা পরিচালিত হয়। আপনি যে বস্তুটি মার্জ করতে () প্রবেশ করতে পেরেছেন তা যদি ইতিমধ্যে পরিচালিত হয় (ইতিমধ্যে সেশনের সাথে জড়িত) তবে হাইবারনেট এই গ্রাফটির সাথে কাজ করে; যে বস্তুটি পাস হয়েছে তা হ'ল মার্জ () থেকে ফিরে আসা একই জিনিস। যাইহোক, আপনি যে বস্তুকে মার্জ () এ পাস করেছেন তা যদি আলাদা করা হয় তবে হাইবারনেট একটি নতুন অবজেক্ট গ্রাফ তৈরি করে যা পরিচালিত হয় এবং এটি আপনার বিচ্ছিন্ন গ্রাফ থেকে রাষ্ট্রটিকে নতুন পরিচালিত গ্রাফটিতে অনুলিপি করে। আবার, এগুলি সমস্তই জেপিএ স্পেক দ্বারা নিয়ন্ত্রিত এবং পরিচালিত।

"এই সত্তাটি পরিচালনা করা হয়েছে কিনা তা নিশ্চিত করুন বা এটি পরিচালনা করুন" এর জেনেরিক কৌশলটির শর্তাবলী, আপনি যদি না-এখনও প্রবেশ না করা ডেটার জন্য অ্যাকাউন্ট করতে চান তবে এটি নির্ভর করে। ধরে নিচ্ছি যে, কিছু ব্যবহার করুন

if ( session.contains( myEntity ) ) {
    // nothing to do... myEntity is already associated with the session
}
else {
    session.saveOrUpdate( myEntity );
}

লক্ষ্য করুন যে আমি আপডেট () পরিবর্তে সেভআরআপডেট () ব্যবহার করেছি। আপনি যদি এখানে-না-প্রবেশকৃত ডেটা হ্যান্ডেল করতে না চান তবে পরিবর্তে আপডেট () ব্যবহার করুন ...


3
এই প্রশ্নের সঠিক উত্তর- মামলা বন্ধ!
5:48 এ cwash

2
Session.contains(Object)রেফারেন্স দ্বারা চেক। সেশনে ইতিমধ্যে যদি অন্য সত্ত্বা একই সারির প্রতিনিধিত্ব করে এবং আপনি একটি বিচ্ছিন্ন উদাহরণটি পাস করেন তবে আপনি ব্যতিক্রম পাবেন।
djmj

Session.contains(Object)রেফারেন্স অনুসারে চেক হিসাবে , সেশনে একই সারিটির প্রতিনিধিত্বকারী অন্য কোনও সত্তা থাকলে, এটি মিথ্যা প্রত্যাবর্তন করবে এবং এটি আপডেট করবে।
এক্সেলওয়াস

19

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

কূটনৈতিক উত্তর: এটি হাইবারনেট ডক্সে বর্ণিত হয়েছে । আপনার যদি আরও স্পষ্টকরণের প্রয়োজন হয় তবে হাইবারনেটের সাথে জাভা পার্সিস্টির সেকশন 9.3.2 দেখুন "বিচ্ছিন্নভাবে অবজেক্টস অব ওয়ার্কিং" নামে পরিচিত। আপনি হাইবারনেটের সাথে সিআরইউডি ছাড়া আরও কিছু করছেন যদি আপনি এই বইটি পেতে দৃ get ়ভাবে পরামর্শ দিই ।


5
Seamframework.org থেকে : "রেড হ্যাট দ্বারা সিয়াম 3 এর সক্রিয় বিকাশ বন্ধ হয়ে গেছে" " সিমের এই ডক্সের এই অংশ" লিঙ্কটিও মারা গেছে।
ব্যাডবিশপ

14

আপনি যদি নিশ্চিত হন যে আপনার সত্তাটি সংশোধিত হয়নি (বা আপনি যদি কোনও সংশোধনী নষ্ট হয়ে যান) তবে আপনি এটি লক সহ সেশনে পুনরায় সংযুক্ত করতে পারেন।

session.lock(entity, LockMode.NONE);

এটি কিছুই লক করবে না, তবে এটি সেশন ক্যাশে থেকে সত্তাটি পাবে বা (সেখানে না পাওয়া গেলে) এটি ডিবি থেকে পড়বে।

আপনি যখন কোনও "পুরানো" (উদাহরণস্বরূপ এইচটিটিপিএসশন থেকে) সত্ত্বা থেকে সম্পর্ক নেভিগেশন করছেন তখন LazyInitException রোধ করতে এটি খুব কার্যকর। আপনি প্রথমে সত্তাকে "পুনরায় সংযুক্ত" করেন।

গেট ব্যবহার করাও কার্যকর হতে পারে, যখন আপনি উত্তরাধিকারকে ম্যাপ করা হয়ে থাকে (যা ইতিমধ্যে getId () এ ব্যতিক্রম করবে।

entity = session.get(entity.getClass(), entity.getId());

2
আমি সেশনটির সাথে একটি সত্তাকে পুনরায় সংযুক্ত করতে চাই। দুর্ভাগ্যক্রমে, Session.lock(entity, LockMode.NONE)ব্যতিক্রম ব্যতীত ব্যর্থতা: অবিচ্ছিন্ন ক্ষণস্থায়ী সংগ্রহকে পুনরায় যোগাযোগ করতে পারেনি। কীভাবে এটি কাটিয়ে উঠতে পারে?
dma_k

1
আসলে আমি পুরোপুরি ঠিক ছিলাম না। লক () ব্যবহার করা আপনার সত্তাকে পুনরায় সংযুক্ত করে, তবে এটির সাথে আবদ্ধ অন্যান্য সত্ত্বা নয়। সুতরাং যদি আপনি সত্তা.গেটঅথেরনেটিটি ()। GetYetAnotherEntity () করেন তবে আপনার কাছে একটি LazyInit ব্যতিক্রম থাকতে পারে। আমি এটি অতিক্রম করতে জানি একমাত্র উপায় হ'ল অনুসন্ধান ব্যবহার করা। সত্তা = em.find (সত্তা.সেটক্লাস (), সত্তা.টিআইডিআইডি ();
জন রিজো

কোনও Session.find()এপিআই পদ্ধতি নেই। সম্ভবত আপনি বলতে চাইছেন Session.load(Object object, Serializable id)
dma_k

11

যেহেতু এটি একটি খুব সাধারণ প্রশ্ন, আমি এই নিবন্ধটি লিখেছি , যার ভিত্তিতে এই উত্তরটি ভিত্তিক।

সত্তা রাজ্য

জেপিএ নিম্নলিখিত সংস্থাগুলির সংজ্ঞা দেয়:

নতুন (ক্ষণস্থায়ী)

একটি সদ্য নির্মিত বস্তু যা হাইবারনেট Session(ওরফে Persistence Context) এর সাথে কখনও যুক্ত হয় নি এবং কোনও ডাটাবেস টেবিল সারিতে ম্যাপ করা হয়নি তা নতুন (ক্ষণস্থায়ী) অবস্থায় বিবেচিত হয়।

অবিচল থাকার জন্য আমাদের হয় স্পষ্টভাবে EntityManager#persistপদ্ধতিটি কল করতে হবে বা ট্রানজিটিভ অধ্যবসায়ের প্রক্রিয়াটি ব্যবহার করতে হবে।

অবিরাম (পরিচালিত)

একটি অবিচলিত সত্তা একটি ডাটাবেস টেবিল সারিটির সাথে যুক্ত হয়েছে এবং এটি বর্তমানে চলমান দৃistence়প্রতিনিধি দ্বারা পরিচালিত হচ্ছে। এই জাতীয় সত্তায় যে কোনও পরিবর্তন করা হয়েছে তা সনাক্ত করে ডেটাবেজে প্রচার করা হচ্ছে (সেশন ফ্লাশ-সময় চলাকালীন)।

হাইবারনেট সহ, আমাদের আর ইনসার্ট / আপডেট / বিবৃতি মুছে ফেলতে হবে না। হাইবারনেট একটি লেনদেনমূলক রাইট-ব্যাক ওয়ার্কিং স্টাইলকে নিয়োগ করে এবং পরিবর্তনগুলি খুব শেষ দায়ী মুহুর্তে, বর্তমান Sessionফ্লাশ-সময়ের সময়ে সিঙ্ক্রোনাইজ করা হয় ।

বিচ্ছিন্ন

একবার চলমান দৃistence়প্রত্যক্ষ প্রসঙ্গটি বন্ধ হয়ে গেলে পূর্ববর্তী সমস্ত পরিচালিত সত্তা বিচ্ছিন্ন হয়ে যায়। ধারাবাহিক পরিবর্তনগুলি আর ট্র্যাক করা হবে না এবং কোনও স্বয়ংক্রিয় ডাটাবেস সিঙ্ক্রোনাইজেশন ঘটবে না।

সত্তার রাষ্ট্রের রূপান্তর

আপনি EntityManagerইন্টারফেস দ্বারা সংজ্ঞায়িত বিভিন্ন পদ্ধতি ব্যবহার করে সত্তার স্থিতি পরিবর্তন করতে পারেন ।

জেপিএ সত্তা রাষ্ট্রের রূপান্তরগুলি আরও ভালভাবে বুঝতে, নিম্নলিখিত চিত্রটি বিবেচনা করুন:

জেপিএ সত্তা রাষ্ট্রের রূপান্তর

জেপিএ ব্যবহার করার সময়, কোনও সক্রিয়কে পৃথক পৃথক সত্তাকে পুনঃস্থাপন EntityManagerকরতে, আপনি মার্জ অপারেশনটি ব্যবহার করতে পারেন ।

নেটিভ হাইবারনেট এপিআই ব্যবহার mergeকরার সময়, নীচের চিত্র দ্বারা প্রদর্শিত হিসাবে আপনি আপডেট পদ্ধতিগুলি ব্যবহার করে একটি সক্রিয় হাইবারনেট সেশনে একটি বিচ্ছিন্ন সত্তাকে পুনরায় সংযুক্ত করতে পারেন:

হাইবারনেট সত্তা রাষ্ট্রের রূপান্তর

একটি বিচ্ছিন্ন সত্তা মার্জ করা

মার্জটি বিচ্ছিন্ন সত্তা রাষ্ট্রের (উত্স) একটি পরিচালিত সত্তা উদাহরণ (গন্তব্য) অনুলিপি করতে চলেছে।

বিবেচনা করুন আমরা নিম্নলিখিত Bookসত্তাকে অবিচলিত করেছি, এবং EntityManagerসত্তাটি বন্ধ হয়ে যাওয়ার জন্য ব্যবহার করা হয়েছিল বলে এখন সত্তাটি আলাদা করা হয়েছে :

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

সত্তাটি বিচ্ছিন্ন অবস্থায় থাকা অবস্থায়, আমরা এটিকে নিম্নরূপে সংশোধন করি:

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

এখন, আমরা ডাটাবেসে পরিবর্তনগুলি প্রচার করতে চাই, সুতরাং আমরা mergeপদ্ধতিটি কল করতে পারি :

doInJPA(entityManager -> {
    Book book = entityManager.merge(_book);

    LOGGER.info("Merging the Book entity");

    assertFalse(book == _book);
});

এবং হাইবারনেট নিম্নলিখিত এসকিউএল স্টেটমেন্টগুলি কার্যকর করতে চলেছে:

SELECT
    b.id,
    b.author AS author2_0_,
    b.isbn AS isbn3_0_,
    b.title AS title4_0_
FROM
    book b
WHERE
    b.id = 1

-- Merging the Book entity

UPDATE
    book
SET
    author = 'Vlad Mihalcea',
    isbn = '978-9730228236',
    title = 'High-Performance Java Persistence, 2nd edition'
WHERE
    id = 1

যদি মার্জিং সত্তাটির বর্তমানের কোনও সমতুল্য না থাকে EntityManagerতবে ডাটাবেস থেকে একটি নতুন সত্তার স্ন্যাপশট নেওয়া হবে।

একবার কোনও ম্যানেজড সত্তা থাকলে, জেপিএ বিচ্ছিন্ন সত্তার অবস্থার অনুলিপিটি বর্তমানে পরিচালিত একটিতে অনুলিপি করে এবং দৃ the ়তা প্রসঙ্গেflush , যদি কোনও নোংরা চেকিংয়ের ব্যবস্থাটি খুঁজে পায় যে পরিচালিত সত্তাটি পরিবর্তিত হয়েছে।

সুতরাং, ব্যবহার করার সময় merge, বিচ্ছিন্ন অবজেক্ট উদাহরণটি মার্জ ক্রিয়াকলাপের পরেও বিচ্ছিন্ন থাকা অবিরত থাকবে।

একটি বিচ্ছিন্ন সত্তা আবার পাঠাচ্ছে

হাইবারনেট, তবে জেপিএ updateপদ্ধতিটির মাধ্যমে পুনঃনির্দেশকে সমর্থন করে না ।

একটি হাইবারনেট Sessionএকটি প্রদত্ত ডাটাবেস সারিটির জন্য কেবল একটি সত্তা অবজেক্টকে যুক্ত করতে পারে। কারণ পার্সিস্টন কনটেক্সট একটি ইন-মেমরি ক্যাশে (প্রথম স্তরের ক্যাশে) হিসাবে কাজ করে এবং কেবলমাত্র একটি মান (সত্তা) প্রদত্ত কী (সত্তার ধরণ এবং ডাটাবেস শনাক্তকারী) এর সাথে সম্পর্কিত।

বর্তমান হাইবারনেটের সাথে ইতিমধ্যে অন্য কোনও জেভিএম অবজেক্ট (একই ডেটাবেস সারিটির সাথে মিলছে) না থাকলে কেবলমাত্র সত্তা পুনরায় সংযুক্ত করা যায় Session

বিবেচনা করে আমরা Bookসত্তাকে অবিচল রেখেছি এবং সত্তাটি যখন Bookবিচ্ছিন্ন অবস্থায় ছিল তখন আমরা এটিকে সংশোধন করেছি :

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

আমরা বিচ্ছিন্নভাবে সত্তাকে এভাবে পুনরায় সংযুক্ত করতে পারি:

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);

    session.update(_book);

    LOGGER.info("Updating the Book entity");
});

এবং হাইবারনেট নিম্নলিখিত এসকিউএল বিবৃতি কার্যকর করবে:

-- Updating the Book entity

UPDATE
    book
SET
    author = 'Vlad Mihalcea',
    isbn = '978-9730228236',
    title = 'High-Performance Java Persistence, 2nd edition'
WHERE
    id = 1

updateপদ্ধতি করতে হবে একটি হাইবারনেট করতে ।unwrapEntityManagerSession

বিপরীতে merge, সরবরাহিত বিচ্ছিন্ন সত্তাটি বর্তমান দৃ Pers়তা প্রসঙ্গে পুনরায় যোগাযোগ করতে চলেছে এবং সত্তাটি পরিবর্তন করেছে কিনা তা ফ্লাশ চলাকালীন একটি আপডেটের সময়সূচী রয়েছে।

এটি প্রতিরোধ করতে, আপনি @SelectBeforeUpdateহাইবারনেট টীকাগুলি ব্যবহার করতে পারেন যা এমন একটি নির্বাচনী বিবৃতি ট্রিগার করবে যা লোড হওয়া অবস্থায় আনবে যা পরে নোংরা চেকিং প্রক্রিয়া দ্বারা ব্যবহৃত হয়।

@Entity(name = "Book")
@Table(name = "book")
@SelectBeforeUpdate
public class Book {

    //Code omitted for brevity
}

ননউইনিকউজেক্টএক্সসেপশন থেকে সাবধান থাকুন

একটি সমস্যা যা ঘটতে পারে updateতা হ'ল যদি দৃistence়তা প্রসঙ্গে ইতিমধ্যে একই আইডির সাথে সত্তার রেফারেন্স থাকে এবং নিম্নলিখিত উদাহরণের মতো একই ধরণের:

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(book);

    return book;
});

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

try {
    doInJPA(entityManager -> {
        Book book = entityManager.find(
            Book.class,
            _book.getId()
        );

        Session session = entityManager.unwrap(Session.class);
        session.saveOrUpdate(_book);
    });
} catch (NonUniqueObjectException e) {
    LOGGER.error(
        "The Persistence Context cannot hold " +
        "two representations of the same entity",
        e
    );
}

এখন, উপরোক্ত পরীক্ষার কেসটি কার্যকর করার সময়, হাইবারনেট একটি নিক্ষেপ করতে চলেছে NonUniqueObjectExceptionকারণ দ্বিতীয়টিতে EntityManagerইতিমধ্যে Bookএকই শনাক্তকারীর সাথে একটি সত্তা রয়েছে যা আমরা পাস করেছি updateএবং পার্সিস্টি কনটেক্সট একই সত্তার দুটি উপস্থাপনা রাখতে পারে না।

org.hibernate.NonUniqueObjectException:
    A different object with the same identifier value was already associated with the session : [com.vladmihalcea.book.hpjp.hibernate.pc.Book#1]
    at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:651)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:284)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:227)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:92)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
    at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:682)
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:674)

উপসংহার

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

updateযেমন অতিরিক্ত SELECT স্টেটমেন্ট দ্বারা উত্পন্ন প্রতিরোধ করতে পারি ব্যাচ আপডেট জন্য ভাল mergeঅপারেশন, অতএব ব্যাচ আপডেট সঞ্চালনের সময় কমে যায়।


চমৎকার উত্তর. আমি @SelectBeforeUpdateযদিও টীকাটি নিয়ে ভাবছিলাম । নির্বাচন কখন ট্রিগার হয়? কল করার সময় update, ঠিক ফ্লাশ করার আগে বা এটি আসলেই কিছু যায় আসে না (হাইবারনেট ফ্লাশ করার আগে একটি কলটিতে সমস্ত টীকাযুক্ত সত্তা এনেছিল তা কি ব্যাপার)?
অ্যান্ড্রোনিকাস

@SelectBeforeUpdateঅধ্যবসায় কনটেক্সট সময় নির্বাচন আরম্ভ করে flushঅপারেশন। পরীক্ষা করে দেখুন পদ্ধতি আরো বিস্তারিত জানার জন্য। getDatabaseSnapshotDefaultFlushEntityEventListener
ভ্লাদ মিহালসিয়া

10

আমি জাভাডকের কাছে ফিরে গিয়ে org.hibernate.Sessionনিম্নলিখিতগুলি খুঁজে পেয়েছি:

ক্ষণস্থায়ী দৃষ্টান্তগুলি কল করে save(), persist()বা দ্বারা স্থির করা যেতে পারে saveOrUpdate()। ক্রমাগত উদাহরণগুলি কল করে ক্ষণস্থায়ী হতে পারে delete()। কোনও get()বা load()পদ্ধতি দ্বারা প্রত্যাবর্তিত কোনও উদাহরণ অবিচল। বিচ্ছিন্ন দৃষ্টান্ত কল করে ক্রমাগত করা যেতে পারে update(), saveOrUpdate(), lock()বা replicate()। একটি ক্ষণস্থায়ী বা বিচ্ছিন্ন উদাহরণের অবস্থা কল করেও একটি নতুন ধ্রুবক উদাহরণ হিসাবে স্থির করা যেতে পারে merge()

সুতরাং update(), saveOrUpdate(), lock(), replicate()এবং merge()প্রার্থী অপশন আছে।

update(): একই শনাক্তকারীর সাথে যদি অবিচ্ছিন্ন উদাহরণ থাকে তবে একটি ব্যতিক্রম ছুঁড়ে ফেলবে।

saveOrUpdate(): হয় সংরক্ষণ করুন বা আপডেট করুন

lock(): অবচয়

replicate(): বর্তমান সনাক্তকারী মানটি পুনরায় ব্যবহার করে প্রদত্ত বিচ্ছিন্ন উদাহরণের স্থিতি রাখুন।

merge(): একই শনাক্তকারীর সাথে একটি অবিচ্ছিন্ন বস্তু ফেরত দেয়। প্রদত্ত উদাহরণটি অধিবেশনটির সাথে যুক্ত হয় না।

সুতরাং, তাত্ক্ষণিকভাবে lock()ব্যবহার করা উচিত নয় এবং কার্যকরী প্রয়োজনের ভিত্তিতে তাদের মধ্যে এক বা একাধিকটি বেছে নেওয়া যেতে পারে।


7

এনহাইবারনেটের সাথে সি # তে আমি এটি করেছিলাম, তবে জাভাতে এটি একইভাবে কাজ করা উচিত:

public virtual void Attach()
{
    if (!HibernateSessionManager.Instance.GetSession().Contains(this))
    {
        ISession session = HibernateSessionManager.Instance.GetSession();
        using (ITransaction t = session.BeginTransaction())
        {
            session.Lock(this, NHibernate.LockMode.None);
            t.Commit();
        }
    }
}

ফার্স্ট লকটি প্রতিটি জিনিসে কল করা হয়েছিল কারণ কনটেনগুলি সর্বদা মিথ্যা ছিল। সমস্যাটি হ'ল এনহাইবারনেট ডাটাবেস আইডি এবং টাইপ দ্বারা বস্তুর তুলনা করে। সমন্বিত equalsপদ্ধতিটি ব্যবহার করে , যা ওভাররাইট না হলে রেফারেন্সের সাথে তুলনা করে। এই equalsপদ্ধতিটি দিয়ে এটি কোনও ব্যতিক্রম ছাড়াই কাজ করে:

public override bool Equals(object obj)
{
    if (this == obj) { 
        return true;
    } 
    if (GetType() != obj.GetType()) {
        return false;
    }
    if (Id != ((BaseObject)obj).Id)
    {
        return false;
    }
    return true;
}

4

Session.contains(Object obj) রেফারেন্সটি পরীক্ষা করে এবং একটি পৃথক উদাহরণ সনাক্ত করতে পারে না যা একই সারিটি উপস্থাপন করে এবং এর সাথে ইতিমধ্যে সংযুক্ত রয়েছে।

সনাক্তকারী সম্পত্তি সহ সত্তাগুলির জন্য আমার জেনেরিক সমাধান।

public static void update(final Session session, final Object entity)
{
    // if the given instance is in session, nothing to do
    if (session.contains(entity))
        return;

    // check if there is already a different attached instance representing the same row
    final ClassMetadata classMetadata = session.getSessionFactory().getClassMetadata(entity.getClass());
    final Serializable identifier = classMetadata.getIdentifier(entity, (SessionImplementor) session);

    final Object sessionEntity = session.load(entity.getClass(), identifier);
    // override changes, last call to update wins
    if (sessionEntity != null)
        session.evict(sessionEntity);
    session.update(entity);
}

এটি আমার পছন্দ নেট অ্যান্টিটি ফ্রেমওয়ার্কের কয়েকটি দিকগুলির মধ্যে একটি, পরিবর্তিত সত্তা এবং তাদের বৈশিষ্ট্য সম্পর্কিত বিভিন্ন সংযুক্ত বিকল্পগুলি options


3

আমি দৃ the়তা স্টোর থেকে এমন একটি বস্তুর "রিফ্রেশ" করার সমাধান নিয়ে এসেছি যা ইতিমধ্যে অধিবেশনটিতে সংযুক্ত অন্যান্য বস্তুর জন্য অ্যাকাউন্ট করবে:

public void refreshDetached(T entity, Long id)
{
    // Check for any OTHER instances already attached to the session since
    // refresh will not work if there are any.
    T attached = (T) session.load(getPersistentClass(), id);
    if (attached != entity)
    {
        session.evict(attached);
        session.lock(entity, LockMode.NONE);
    }
    session.refresh(entity);
}

2

দুঃখিত, মন্তব্য যোগ করতে পারে না বলে মনে হচ্ছে (এখনও?)

হাইবারনেট 3.5.0-ফাইনাল ব্যবহার করে

যেখানে Session#lockপদ্ধতি এই অবচিত, javadoc নেই ব্যবহার করার সুপারিশ Session#buildLockRequest(LockOptions)#lock(entity)এবং যদি আপনি নিশ্চিত করুন যে আপনার সমিতির আছে তা নিশ্চিত করুন cascade=lock, অলস লোড হচ্ছে একটি বিষয় পারেন নয়।

সুতরাং, আমার সংযুক্তি পদ্ধতিটি দেখতে কিছুটা ভালো লাগে

MyEntity attach(MyEntity entity) {
    if(getSession().contains(entity)) return entity;
    getSession().buildLockRequest(LockOptions.NONE).lock(entity);
    return entity;

প্রাথমিক পরীক্ষাগুলি পরামর্শ দেয় যে এটি একটি ট্রিট কাজ করে।


2

সম্ভবত এটি Eclipselink এ কিছুটা আলাদা আচরণ করে। বাসি ডেটা না পেয়ে বিযুক্ত জিনিসগুলিকে পুনরায় সংযুক্ত করতে, আমি সাধারণত:

Object obj = em.find(obj.getClass(), id);

এবং alচ্ছিক হিসাবে দ্বিতীয় পদক্ষেপ (ক্যাশেগুলি অবৈধ করতে):

em.refresh(obj)


1

মূল পোস্টে দুটি পদ্ধতি রয়েছে update(obj)এবং merge(obj)সেগুলি কাজের কথা উল্লেখ করা হয়েছে তবে বিপরীত পরিস্থিতিতে। এটি যদি সত্যিই সত্য হয় তবে প্রথমে অধিবেশনটিতে বস্তুটি ইতিমধ্যে রয়েছে কিনা তা পরীক্ষা করে কেন নয়, এবং update(obj)যদি তা হয় তবে তা কল করুন, অন্যথায় কল করুন merge(obj)

অধিবেশন অস্তিত্ব জন্য পরীক্ষা হয় session.contains(obj)। অতএব, আমি মনে করি নিম্নলিখিত সিউডো-কোড কাজ করবে:

if (session.contains(obj))
{
    session.update(obj);
}
else 
{
    session.merge(obj);
}

2
() চেকগুলি রেফারেন্সের সাথে তুলনা করে তবে হাইবারনেট ফাংশনগুলি ডাটাবেস আইডি দ্বারা কাজ করে। আপনার কোডে কখনই সেশন ডাবল ডাকা হবে না।
ভেরেনা হানস্মমিড

1

এই অবজেক্টটি আবার সংযুক্ত করতে, আপনাকে অবশ্যই মার্জ () ব্যবহার করতে হবে;

এই মেথোডটি প্যারামিটারে স্বীকৃতি দেয় আপনার সত্তা বিচ্ছিন্ন এবং কোনও সত্তা ফিরিয়ে আনা হবে এবং ডেটাবেস থেকে পুনরায় লোড করা হবে।

Example :
    Lot objAttach = em.merge(oldObjDetached);
    objAttach.setEtat(...);
    em.persist(objAttach);

0

প্রথমে মার্জ কল () (ক্রমাগত উদাহরণ আপডেট করার জন্য), তারপরে লক করুন (লকডমড.নোন) (বর্তমান উদাহরণ সংযুক্ত করতে, মার্জ () দ্বারা ফিরে আসা ব্যক্তিটি কিছু ব্যবহারের ক্ষেত্রে কাজ করছে বলে মনে হচ্ছে না।


0

সম্পত্তি hibernate.allow_refresh_detached_entityআমার জন্য কৌতুক করেছে। তবে এটি একটি সাধারণ নিয়ম, সুতরাং আপনি যদি কিছু ক্ষেত্রে এটি করতে চান তবে এটি খুব উপযুক্ত নয়। আমি আসা করি এটা সাহায্য করবে.

হাইবারনেট 5.4.9 এ পরীক্ষিত

SessionFactoryOptionsBuilder



আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.