লেনদেনটি কেবল রোলব্যাক হিসাবে চিহ্নিত হয়েছে: আমি কীভাবে কারণটি খুঁজে পাব


95

আমার @ লেনদেন পদ্ধতিতে লেনদেন করার বিষয়ে আমার সমস্যা হচ্ছে:

methodA() {
    methodB()
}

@Transactional
methodB() {
    ...
    em.persist();
    ...
    em.flush();
    log("OK");
}

যখন আমি মেথডিএ () থেকে মেথডিবিকে () কল করি, তখন পদ্ধতিটি সফলভাবে পাস হয় এবং আমি আমার লগগুলিতে "ওকে" দেখতে পাচ্ছি। তবে আমি পাই

Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
    at methodA()...
  1. মেথডিবির প্রসঙ্গে ব্যতিক্রম পুরোপুরি অনুপস্থিত - যা আমি ঠিক মনে করি?
  2. পদ্ধতিবি () এর মধ্যে কিছু লেনদেনকে কেবল রোলব্যাক হিসাবে চিহ্নিত করেছে? আমি এটি কীভাবে খুঁজে পেতে পারি? উদাহরণস্বরূপ কোনও getCurrentTransaction().isRollbackOnly()?কিছুর চেক করার কোনও উপায় আছে - এর মতো আমি পদ্ধতিটি থেকে পদক্ষেপ নিতে পারি এবং কারণটি খুঁজে পেতে পারি।



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

উত্তর:


101

আপনি যখন নিজের পদ্ধতিটিকে চিহ্নিত করেন @Transactional, আপনার পদ্ধতির অভ্যন্তরে কোনও ব্যতিক্রম ঘটলে আশেপাশের টিএক্সটিকে কেবল রোল-ব্যাক হিসাবে চিহ্নিত করা হবে (এমনকি আপনি সেগুলি ধরলেও)। আপনি @Transactionalটীকাগুলির অন্যান্য বৈশিষ্ট্যগুলি এ জাতীয় ঘূর্ণন রোধ করতে ব্যবহার করতে পারেন :

@Transactional(rollbackFor=MyException.class, noRollbackFor=MyException2.class)

6
ঠিক আছে, আমি ব্যবহার করার চেষ্টা করেছি noRollbackFor=Exception.class, তবে মনে হয় এটির কোনও প্রভাব নেই - এটি উত্তরাধিকারসূত্রে প্রাপ্ত ব্যতিক্রমগুলির জন্য কাজ করে?
ভোজটচ

6
হ্যাঁ এটা করে. আপনার নিজের উত্তরটির দিকে তাকানো, এটি সঠিক (আপনি methodCআপনার প্রথম পোস্টে সরবরাহ করেন নি )। উভয় methodBএবং methodCএকই টিএক্স ব্যবহার করুন এবং সর্বদা সর্বাধিক নির্দিষ্ট @Transactionalটীকা ব্যবহার করা হয়, সুতরাং যখন methodCব্যতিক্রম ছুঁড়ে ফেলা হয় তখন চারপাশের টিএক্সকে কেবল রোলব্যাক-হিসাবে চিহ্নিত করা হবে। এটি প্রতিরোধ করতে আপনি বিভিন্ন প্রচার প্রচারকারীও ব্যবহার করতে পারেন।
ইয়ান ভি

4
@ ললোট্রন @ ইয়ান আমি নিশ্চিত করতে পারি যে এটি সত্যিই কেবল পঠনযোগ্য লেনদেনে প্রযোজ্য। আমার পদ্ধতিটি EmptyResultDataAccessExceptionকেবল পঠনযোগ্য লেনদেনে একটি ব্যতিক্রম ছুঁড়েছিল এবং আমি একই ত্রুটি পেয়েছি। @Transactional(readOnly = true, noRollbackFor = EmptyResultDataAccessException.class)সমস্যাটি স্থির করতে আমার টীকা পরিবর্তন করা ।
cbmeeks

4
এই উত্তরটি ভুল। স্প্রিং শুধুমাত্র ব্যতিক্রম যে মধ্য দিয়ে পাস বিষয়ে জানেন @Transactionalপ্রক্সি মোড়কের, অর্থাত্ uncaught । পুরো গল্পের জন্য ভোজচকের অন্যান্য উত্তর দেখুন। নেস্টেড @Transactionalপদ্ধতি থাকতে পারে যা কেবলমাত্র আপনার লেনদেনের রোলব্যাক চিহ্নিত করতে পারে ।
ইয়ারোস্লাভ স্টাভিনিচি

4
noRollbackForশুধুমাত্র যদি কাজglobalRollbackOnParticipationFailure=false
amir110

69

আমি অবশেষে সমস্যাটি বুঝতে পেরেছি:

methodA() {
    methodB()
}

@Transactional(noRollbackFor = Exception.class)
methodB() {
    ...
    try {
        methodC()
    } catch (...) {...}
    log("OK");
}

@Transactional
methodC() {
    throw new ...();
}

যা ঘটে তা হ'ল যদিও methodBএর যথাযথ টিকা আছে, তা methodCনেই। ব্যতিক্রম নিক্ষেপ করা হলে, দ্বিতীয়টি @Transactionalযেভাবেই হোক রোলব্যাক হিসাবে প্রথম লেনদেনটিকে চিহ্নিত করে।


4
লেনদেনের স্থিতি থ্রেড স্থানীয় ভেরিয়েবলে সংরক্ষণ করা হয় the ব্যতিক্রমের আর কোনও দমন সহায়তা করবে না কারণ চূড়ান্ত প্রতিশ্রুতি যখন ঘটে তখন আপনি ত্রুটিটি পেয়ে যাবেন
বাঁচে

@ ভোজটচ কোনওভাবেই হাইপোথিটিক্যালি যদি মেথডিসি থাকে propagation=requires_newতবে মেথডিবি রোলব্যাক করবে না?
deFreitas

4
methodCঅবশ্যই বিভিন্ন স্প্রিং শিম / পরিষেবাতে বা কোনওভাবে স্প্রিং প্রক্সি দিয়ে অ্যাক্সেস করা উচিত। অন্যথায় বসন্তে আপনার ব্যতিক্রম সম্পর্কে জানার কোনও সম্ভাবনা থাকবে না। @Transactionalটিকা রচনায় যাওয়া ব্যতিক্রম কেবলমাত্র লেনদেনকে কেবল রোলব্যাক হিসাবে চিহ্নিত করতে পারে।
ইয়ারোস্লাভ স্টাভিনিচি

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

43

পুনরায় কোড বা পুনর্নির্মাণের প্রয়োজন ছাড়াই দ্রুত কারণ কারণটি আনতে একটি ব্রেকপয়েন্ট সেট করুন

org.hibernate.ejb.TransactionImpl.setRollbackOnly() // Hibernate < 4.3, or
org.hibernate.jpa.internal.TransactionImpl() // as of Hibernate 4.3

এবং স্ট্যাকের উপরে চলে যান, সাধারণত কিছু ইন্টারসেপ্টারের কাছে। সেখানে আপনি কিছু ক্যাচ ব্লক থেকে কারণ ব্যতিক্রম পড়তে পারেন।


6
হাইবারনেট ৪.৩.১১ এ, এটি হ'লorg.hibernate.jpa.internal.TransactionImpl
উইম দেবলাউয়ে

খুব সুন্দর বন্ধু!
রাফায়েল আন্দ্রেড

ধন্যবাদ! হাইবারনেটের (5.4.17) নতুন সংস্করণে ক্লাসটি রয়েছে org.hibernate.engine.transaction.internal.TransactionImplএবং পদ্ধতিটিও setRollbackOnly
পিটার ক্যাটালিন

11

আমি আমার অ্যাপ্লিকেশন চালানোর সময় এই ব্যতিক্রম নিয়ে সংগ্রাম করেছি।

শেষ পর্যন্ত সমস্যাটি স্কেল কোয়েরিতে ছিল । মানে যে জিজ্ঞাসাটি ভুল।

আপনার জিজ্ঞাসা যাচাই করুন। এটি আমার পরামর্শ


4
পরিষ্কার করার জন্য: যদি আপনার ১.০০ স্কল সিনট্যাক্সে একটি ত্রুটি থাকে ২. ব্যতিক্রমটি রোলব্যাকের জন্য সেটআপ হয় ৩. কেবলমাত্র লেনদেনের ফলে আপনি এই ত্রুটিটি পেয়ে যাবেন কারণ স্কুয়েল সিনট্যাক্স একটি ব্যতিক্রম ঘটায় যা রোলব্যাককে ট্রিগার করে যা ব্যর্থ হয় কারণ আপনি " কেবলমাত্র "মোড"
ডেভ

7

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

লেনদেনটি রোলব্যাকের জন্য চিহ্নিত হয়েছে কিনা তা জানতে আপনি প্রসঙ্গটি ব্যবহার করতে পারেন।

@Resource
private SessionContext context;

context.getRollbackOnly();

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

কি SessionContextবসন্তে একটি প্রমিত বর্গ? এটি আমার কাছে মনে হয় এটি বরং EJB3 এবং এটি আমার স্প্রিং অ্যাপ্লিকেশনটিতে নেই।
ভোজটচ

4
আমার খারাপ আমি স্প্রিং সম্পর্কে যে ঘটনা মিস। যাইহোক, TransactionAspectSupport.currentTransactionStatus().isRollbackOnly()উপলভ্য কিছু থাকতে হবে ।
মেরিন

3

সমাধানগুলির সাথে একটি ভাল ব্যাখ্যা পাওয়া গেছে: https://vcfvct.wordpress.com/2016/12/15/spring-nested-transactional-rolback-only/

1) নিসড়িত পদ্ধতি থেকে @ ট্রান্স্যাসিয়োনাল সরান যদি এর জন্য সত্যিকার অর্থে লেনদেন নিয়ন্ত্রণের প্রয়োজন না হয়। এমনকি এটির ব্যতিক্রম রয়েছে, এটি কেবল বুদবুদ হয়ে যায় এবং লেনদেনের স্টাফগুলিকে প্রভাবিত করে না।

বা:

২) যদি নেস্টেড পদ্ধতিতে লেনদেন নিয়ন্ত্রণের প্রয়োজন হয়, তবে প্রচারের নীতির জন্য এটিকে REQUIRE_NEW হিসাবে তৈরি করুন এমনকি যদি ব্যতিক্রম ছোঁড়ে এবং কেবল রোলব্যাক হিসাবে চিহ্নিত করা হয়, তবে কলার প্রভাবিত হবে না।


1

আপনার Bean.xml এ লেনদেনের ব্যবস্থাপনার অক্ষম করুন

<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

এই লাইনগুলি মন্তব্য করুন, এবং আপনি ব্যতিক্রমটি রোলব্যাকের কারণ দেখবেন;)


0

প্রোডাক্ট রিপোসিটরিতে নীচের কোডটি প্রয়োগ করুন

@Query("update Product set prodName=:name where prodId=:id ") @Transactional @Modifying int updateMyData(@Param("name")String name, @Param("id") Integer id);

জুনিট পরীক্ষায় কোডের নীচে প্রয়োগ করুন

@Test
public void updateData()
{
  int i=productRepository.updateMyData("Iphone",102);

  System.out.println("successfully updated ... ");
  assertTrue(i!=0);

}

এটি আমার কোডের জন্য ভাল কাজ করছে

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