যখন getOne এবং FindOne পদ্ধতিগুলি স্প্রিং ডেটা JPA ব্যবহার করুন


154

আমার একটি ব্যবহারের কেস রয়েছে যেখানে এটি নীচে কল করে:

@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public UserControl getUserControlById(Integer id){
    return this.userControlRepository.getOne(id);
}

পালন @Transactionalকরেছেন Propagation.REQUIRES_NEW এবং সংগ্রহস্থল ব্যবহার getOne । আমি যখন অ্যাপটি চালাচ্ছি, আমি নিম্নলিখিত ত্রুটি বার্তাটি পেয়েছি:

Exception in thread "main" org.hibernate.LazyInitializationException: 
could not initialize proxy - no Session
...

কিন্তু যদি আমি পরিবর্তন getOne(id)দ্বারা findOne(id)কাজ জরিমানা।

বিটিডাব্লু , ব্যবহারের ক্ষেত্রে getUserControlById পদ্ধতি কল করার ঠিক আগে , এটি ইতিমধ্যে insertUserControl পদ্ধতি বলেছে

@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public UserControl insertUserControl(UserControl userControl) {
    return this.userControlRepository.save(userControl);
}

উভয় পদ্ধতি হ'ল প্রচার RE REQUIRES_NEW কারণ আমি একটি সাধারণ নিরীক্ষা নিয়ন্ত্রণ করছি।

আমি getOneপদ্ধতিটি ব্যবহার করি কারণ এটি JpaRepository ইন্টারফেসে সংজ্ঞায়িত করা হয় এবং আমার সংগ্রহস্থল ইন্টারফেসটি সেখান থেকে প্রসারিত হয়, আমি অবশ্যই JPA এর সাথে কাজ করছি।

JpaRepository ইন্টারফেস থেকে প্রসারিত CrudRepositoryfindOne(id)পদ্ধতি সংজ্ঞায়িত করা হয় CrudRepository

আমার প্রশ্নগুলি হ'ল:

  1. getOne(id)পদ্ধতিটি কেন ব্যর্থ ?
  2. আমার কখন এই getOne(id)পদ্ধতিটি ব্যবহার করা উচিত ?

আমি অন্যান্য সংগ্রহস্থলগুলির সাথে কাজ করছি এবং সমস্ত getOne(id)পদ্ধতিটি ব্যবহার করি এবং সমস্ত কাজ সূক্ষ্ম হয়, কেবলমাত্র আমি যখন প্রচার প্রচার করি RE REQUIRES_NEW এটি ব্যর্থ হয়।

GetOne এপিআই অনুসারে :

প্রদত্ত শনাক্তকারী সহ সত্তার একটি রেফারেন্স প্রদান করে।

FindOne এপিআই অনুসারে :

একটি আইডি দ্বারা একটি সত্তা পুনরুদ্ধার।

3) আমার কখন এই findOne(id)পদ্ধতিটি ব্যবহার করা উচিত ?

4) কোন পদ্ধতিটি ব্যবহার করার পরামর্শ দেওয়া হচ্ছে?

আগাম ধন্যবাদ.


ডেটা বেসে কোনও অবজেক্টের অস্তিত্ব পরীক্ষা করার জন্য আপনার বিশেষত getOne () ব্যবহার করা উচিত নয়, কারণ getOne এর মাধ্যমে আপনি সর্বদা একটি বস্তু পান! = নাল, যেখানে FindOne নাল সরবরাহ করে।
উয়ে অলনার

উত্তর:


136

টি এল; ডিআর

T findOne(ID id)(পুরানো এপিআই- Optional<T> findById(ID id)তে নাম ) / (নতুন এপিআই-তে নাম) এতে EntityManager.find()কোনও সত্তা আগ্রহী লোডিং সম্পাদন করে ।

T getOne(ID id)এর উপর নির্ভর EntityManager.getReference()করে একটি সত্তা অলস লোডিং সম্পাদন করে । সুতরাং সত্তার কার্যকর লোডিং নিশ্চিত করার জন্য, এটিতে কোনও পদ্ধতির আবেদন করা প্রয়োজন।

findOne()/findById()তুলনায় সত্যিই আরও স্পষ্ট এবং সহজ getOne()
তাই মামলা খুব বেশিরভাগ, পক্ষপাতী findOne()/findById()উপর getOne()


এপিআই পরিবর্তন

কমপক্ষে, 2.0সংস্করণটি থেকে Spring-Data-Jpaপরিবর্তিত findOne()
পূর্বে, এটি CrudRepositoryইন্টারফেসে এটি সংজ্ঞায়িত হয়েছিল :

T findOne(ID primaryKey);

এখন, findOne()আপনি যে একক পদ্ধতিতে সন্ধান করতে পারবেন তা CrudRepositoryহ'ল QueryByExampleExecutorইন্টারফেসে কোনটি সংজ্ঞায়িত হয়েছে :

<S extends T> Optional<S> findOne(Example<S> example);

এটি অবশেষে প্রয়োগ করা হয় SimpleJpaRepository, CrudRepositoryইন্টারফেসের ডিফল্ট প্রয়োগ ।
এই পদ্ধতিটি উদাহরণ অনুসন্ধানের দ্বারা একটি ক্যোয়ারী এবং আপনি এটি প্রতিস্থাপন হিসাবে চান না।

আসলে, একই আচরণের পদ্ধতিটি নতুন এপিআইতে এখনও রয়েছে তবে পদ্ধতির নামটি পরিবর্তিত হয়েছে।
এটা তোলে থেকে নাম দেওয়া হয় findOne()থেকে findById()CrudRepositoryইন্টারফেস:

Optional<T> findById(ID id); 

এখন এটি একটি ফেরত Optional। যা রোধ করা এতটা খারাপ নয় NullPointerException

সুতরাং, আসল পছন্দটি এখন Optional<T> findById(ID id)এবং এর মধ্যে T getOne(ID id)


দুটি স্বতন্ত্র পদ্ধতি যা দুটি স্বতন্ত্র জেপিএ সত্তাজনিত পুনরুদ্ধার পদ্ধতির উপর নির্ভর করে

1) Optional<T> findById(ID id)জাভাডোক বলে যে এটি:

একটি আইডি দ্বারা একটি সত্তা পুনরুদ্ধার।

আমরা বাস্তবায়নের দিকে নজর দেওয়ার সাথে সাথে আমরা দেখতে পাচ্ছি যে এটি EntityManager.find()পুনরুদ্ধার করতে নির্ভর করে :

public Optional<T> findById(ID id) {

    Assert.notNull(id, ID_MUST_NOT_BE_NULL);

    Class<T> domainType = getDomainClass();

    if (metadata == null) {
        return Optional.ofNullable(em.find(domainType, id));
    }

    LockModeType type = metadata.getLockModeType();

    Map<String, Object> hints = getQueryHints().withFetchGraphs(em).asMap();

    return Optional.ofNullable(type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints));
}

এবং এখানে em.find()একটি EntityManagerপদ্ধতি হিসাবে ঘোষণা করা হয়েছে:

public <T> T find(Class<T> entityClass, Object primaryKey,
                  Map<String, Object> properties);

এর জাভাদোক বলেছেন:

নির্দিষ্ট বৈশিষ্ট্য ব্যবহার করে প্রাথমিক কী দ্বারা সন্ধান করুন

সুতরাং, বোঝা সত্তা পুনরুদ্ধার প্রত্যাশিত বলে মনে হচ্ছে।

২) T getOne(ID id)জাভাদোকের বক্তব্য (জোর আমার)

প্রদত্ত শনাক্তকারী সহ সত্তার একটি রেফারেন্স প্রদান করে।

আসলে, রেফারেন্স পরিভাষাটি সত্যই বোর্ড এবং জেপিএ এপিআই কোনও getOne()পদ্ধতি নির্দিষ্ট করে না ।
সুতরাং স্প্রিং র‌্যাপার কী করে তা বোঝার জন্য সর্বোত্তম কাজটি বাস্তবায়নের দিকে নজর দিচ্ছে:

@Override
public T getOne(ID id) {
    Assert.notNull(id, ID_MUST_NOT_BE_NULL);
    return em.getReference(getDomainClass(), id);
}

এখানে em.getReference()একটি EntityManagerপদ্ধতি হিসাবে ঘোষণা করা হয়েছে:

public <T> T getReference(Class<T> entityClass,
                              Object primaryKey);

এবং ভাগ্যক্রমে, EntityManagerজাভাদোকটি তার উদ্দেশ্যকে আরও ভালভাবে সংজ্ঞায়িত করেছে (জোর দেওয়া আমার):

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

সুতরাং, অনুরোধ করা getOne()একটি অলস আনীত সত্তা ফিরিয়ে দিতে পারে।
এখানে, অলস আনয়ন সত্তার সাথে সম্পর্কিত নয় বরং সত্তার সাথে সম্পর্কিত।

এর অর্থ হ'ল আমরা যদি প্রার্থনা করি getOne()এবং তারপরে দৃistence়তা প্রসঙ্গটি বন্ধ হয়ে যায়, সত্তাটি কখনই লোড করা যায় না এবং ফলস্বরূপ ফলাফলটি অনির্দেশ্য।
উদাহরণস্বরূপ যদি প্রক্সি অবজেক্টটি সিরিয়ালযুক্ত হয়, আপনি nullসিরিয়ালাইজড ফলাফল হিসাবে একটি রেফারেন্স পেতে পারেন বা যদি কোনও পদ্ধতি প্রক্সি অবজেক্টে ডাকা হয় তবে একটি ব্যতিক্রম যেমন LazyInitializationExceptionনিক্ষেপ করা হয়।
সুতরাং এই ধরণের পরিস্থিতিতে, ডাটাবেসে উপস্থিত নেই এমন একটি দস্তাবেজ হ্যান্ডেল EntityNotFoundExceptionকরতে ব্যবহার getOne()করার মূল কারণ হ'ল সত্তা উপস্থিত না থাকলে ত্রুটি পরিস্থিতি কখনই সম্পাদন করা যায় না।

যে কোনও ক্ষেত্রে, এটির লোড নিশ্চিত করতে আপনাকে সেশনটি খোলা থাকাকালীন সত্তাকে ম্যানিপুলেট করতে হবে। সত্তার কোনও পদ্ধতিতে অনুরোধ করে আপনি এটি করতে পারেন।
বা এর findById(ID id)পরিবর্তে আরও ভাল বিকল্প ব্যবহার ।


এত অস্পষ্ট এপিআই কেন?

শেষ করতে, স্প্রিং-ডেটা-জেপিএ বিকাশকারীদের জন্য দুটি প্রশ্ন:

  • কেন একটি পরিষ্কার ডকুমেন্টেশন নেই getOne()? সত্তা অলস লোডিং আসলে কোনও বিশদ নয়।

  • কেন আপনার getOne()মোড়কের সাথে পরিচয় করিয়ে দেওয়া দরকার EM.getReference()?
    কেন কেবল আবৃত পদ্ধতি বিদ্ধ না: getReference()? খুব getOne() সহজ প্রসেসিংয়ের সময় এই ইএম পদ্ধতিটি খুব নির্দিষ্ট ।


3
আমি বিভ্রান্ত হয়ে পড়েছিলাম কেন getOne () এন্টিটি নটফাউন্ডএক্সসেপশন ছুড়ছে না, তবে আপনার "এন্টিটি নটফাউন্ডএক্সসেপশন নিক্ষেপ করা হয় যখন ইনস্ট্যান্স স্টেটটি প্রথম অ্যাক্সেস করা হয়" আমাকে ধারণাটি ব্যাখ্যা করে। ধন্যবাদ
TheCoder

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

124

মূল পার্থক্য getOneহ'ল অলস বোঝা এবংfindOne না is

নিম্নলিখিত উদাহরণ বিবেচনা করুন:

public static String NON_EXISTING_ID = -1;
...
MyEntity getEnt = myEntityRepository.getOne(NON_EXISTING_ID);
MyEntity findEnt = myEntityRepository.findOne(NON_EXISTING_ID);

if(findEnt != null) {
     findEnt.getText(); // findEnt is null - this code is not executed
}

if(getEnt != null) {
     getEnt.getText(); // Throws exception - no data found, BUT getEnt is not null!!!
}

1
অলস বোঝা বোঝানোর অর্থ কি এটি কেবল তখনই লোড হবে যখন সত্তাটি ব্যবহার করা হবে? সুতরাং আমি আশা করি গেট ইন্ট নাল হবে এবং দ্বিতীয়টির ভিতরে কোডটি কার্যকর করা হবে না যদি আপনি দয়া করে ব্যাখ্যা করতে পারেন। ধন্যবাদ!
ডগ

যদি কোনও কমপ্লিটেবল ফিউচার <> ওয়েব পরিষেবায় আবৃত থাকে তবে আমি খুঁজে পেয়েছি যে এটি অলস বাস্তবায়নের কারণে আপনি FindOne () বনাম getOne () ব্যবহার করতে চান।
ফ্রাট

76

1. কেন getOne (আইডি) পদ্ধতি ব্যর্থ হয়?

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

২. কখন আমার getOne (আইডি) পদ্ধতি ব্যবহার করা উচিত?

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

আপনি তাকান তাহলে JavaDoc জন্য getOne(ID)অধীনে দেখুন এছাড়াও :

See Also:
EntityManager.getReference(Class, Object)

দেখে মনে হচ্ছে যে এই পদ্ধতিটি কেবল জেপিএ সত্তা পরিচালকগুলির বাস্তবায়নের জন্য প্রতিনিধি।

যাইহোক, ডকস জন্যfindOne(ID) এই উল্লেখ না।

ক্লুটি সংগ্রহস্থলের নামেও রয়েছে। JpaRepositoryজেপিএ সুনির্দিষ্ট এবং অতএব প্রয়োজনে সত্তা পরিচালকের কাছে কলগুলি অর্পণ করতে পারে। CrudRepositoryব্যবহৃত অধ্যবসায় প্রযুক্তির অজ্ঞেয়বাদী। এখানে দেখুন । এটি জেপিএ, নিও 4 জ এর মতো একাধিক অধ্যবসায় প্রযুক্তির জন্য চিহ্নিতকারী ইন্টারফেস হিসাবে ব্যবহৃত হয়েছে ইত্যাদির

সুতরাং আপনার ব্যবহারের ক্ষেত্রে দুটি পদ্ধতির ক্ষেত্রে আসলেই 'পার্থক্য' নেই, এটি কেবলমাত্র findOne(ID)আরও বিশেষজ্ঞের চেয়ে জেনেরিক getOne(ID)। আপনি যেটি ব্যবহার করেন তা আপনার এবং আপনার প্রকল্পের উপর নির্ভর করে তবে আমি ব্যক্তিগতভাবে findOne(ID)এটিকে আটকে রাখব কারণ এটি আপনার কোডটিকে কম প্রয়োগকরণ নির্দিষ্ট করে তোলে এবং ভবিষ্যতে খুব বেশি রিফ্যাক্টরিং ছাড়াই মোংগোডিবি ইত্যাদির দিকে যাওয়ার দরজা খুলে দেয় :)


ধন্যবাদ ডোনভান, আপনার উত্তরটি বুঝতে পেরেছেন।
ম্যানুয়েল জর্ডান

20
আমি এখানে এটি বলা খুব বিভ্রান্তিমূলক বলে মনে there's not really a 'difference' in the two methodsহয়, কারণ সত্তা কীভাবে পুনরুদ্ধার করা হয় এবং পদ্ধতিটি ফিরে আসার জন্য আপনার কী প্রত্যাশা করা উচিত তার মধ্যে সত্যই বড় পার্থক্য রয়েছে। @ ডেভিডএক্সএক্সএক্সএক্স এর আরও নীচের উত্তর এটি খুব ভালভাবে তুলে ধরে এবং আমি মনে করি যে স্প্রিং ডেটা জেপিএ ব্যবহার করে তাদের প্রত্যেককে এটি সম্পর্কে সচেতন হওয়া উচিত। অন্যথায়, এটি বেশ কিছুটা মাথা ব্যথার কারণ হতে পারে।
ফ্রিডবার্গ

16

getOneপদ্ধতি আয় ডিবি থেকে মাত্র রেফারেন্স (অলস লোড হচ্ছে)। সুতরাং মূলত আপনি লেনদেনের বাইরে Transactionalরয়েছেন ( পরিষেবা শ্রেণিতে আপনাকে যে ঘোষণা করা হয়েছিল তা বিবেচনা করা হয় না) এবং ত্রুটি ঘটে।


আমরা নতুন ট্রানজেকশনের সুযোগে থাকায় সত্তাটি অ্যান্টিটিম্যানেজ.জেট রেফারেন্স (শ্রেণি, অবজেক্ট) "কিছুই" দেয় না বলে মনে হচ্ছে।
ম্যানুয়েল জর্ডান

2

আমি উপরের উত্তরগুলি থেকে সত্যিই খুব কঠিন খুঁজে পেয়েছি। ডিবাগিং দৃষ্টিকোণ থেকে আমি প্রায় 8 ঘন্টা ব্যয় করেছি নির্বাক ভুলটি জানার জন্য।

আমার কাছে বসন্ত + হাইবারনেট + ডোজার + মাইএসকিএল প্রকল্প পরীক্ষা করা হচ্ছে। স্পষ্ট করা.

আমার ব্যবহারকারীর সত্ত্বা, বুক সত্তা। আপনি ম্যাপিংয়ের গণনা করুন।

একাধিক বই ওয়ান ব্যবহারকারীর সাথে বাঁধা ছিল। তবে ইউজার সার্ভিসআইএমপিতে আমি এটি getOne (ইউজারআইডি) দ্বারা সন্ধান করার চেষ্টা করছিলাম;

public UserDTO getById(int userId) throws Exception {

    final User user = userDao.getOne(userId);

    if (user == null) {
        throw new ServiceException("User not found", HttpStatus.NOT_FOUND);
    }
    userDto = mapEntityToDto.transformBO(user, UserDTO.class);

    return userDto;
}

বাকি ফলাফল

{
"collection": {
    "version": "1.0",
    "data": {
        "id": 1,
        "name": "TEST_ME",
        "bookList": null
    },
    "error": null,
    "statusCode": 200
},
"booleanStatus": null

}

উপরের কোডটি যে বইগুলি ব্যবহারকারীর দ্বারা পড়া হয় তা আনেনি।

বুকলিস্টটি getOne (ID) এর কারণে সর্বদা শূন্য ছিল। FindOne (ID) এ পরিবর্তন করার পরে। ফলাফল হলো

{
"collection": {
    "version": "1.0",
    "data": {
        "id": 0,
        "name": "Annama",
        "bookList": [
            {
                "id": 2,
                "book_no": "The karma of searching",
            }
        ]
    },
    "error": null,
    "statusCode": 200
},
"booleanStatus": null

}


-1

বসন্ত.জপা.ওপেন-ইন-ভিউটি সত্য হলেও, গেটওনে নিয়ে আমার কোনও সমস্যা হয়নি তবে এটি মিথ্যা হিসাবে সেট করার পরে, আমি LazyInitializationException পেয়েছি। তারপরে FindById প্রতিস্থাপন করে সমস্যার সমাধান করা হয়েছিল।
যদিও getOne পদ্ধতিটি প্রতিস্থাপন না করেই আরও একটি সমাধান রয়েছে এবং এটি @ ট্রানজেকশনাল পদ্ধতিতে রাখা হয় যা কলটি কল করে repository.getOne (আইডি)। এইভাবে লেনদেনের অস্তিত্ব থাকবে এবং আপনার পদ্ধতিতে সেশন বন্ধ হবে না এবং সত্তা ব্যবহার করার সময় কোনও LazyInitializationException হবে না।


-2

JpaRespository.getOne (id) কেন কাজ করে না এবং ত্রুটি ছুঁড়ে দেয় তা বুঝতে আমার একইরকম সমস্যা হয়েছিল।

আমি গিয়ে JpaRespository.findById (আইডি) এ পরিবর্তিত হয়েছি যার জন্য আপনাকে একটি alচ্ছিক ফিরে আসতে হবে।

এটি সম্ভবত স্ট্যাকওভারফ্লোতে আমার প্রথম মন্তব্য।


দুর্ভাগ্যক্রমে, এটি প্রশ্নের উত্তর সরবরাহ করে না এবং বিদ্যমান উত্তরগুলির উন্নতি করে না।
জেএসটিএল

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