একই ক্লাসের মধ্যে পদ্ধতি অনুসারে স্প্রিং @ ট্রানজেকশন পদ্ধতি কল, কাজ করে না?


109

আমি স্প্রিং লেনদেনে নতুন আমি সত্যিই অদ্ভুত কিছু খুঁজে পেয়েছি, সম্ভবত আমি এটি সঠিকভাবে বুঝতে পেরেছি।

আমি পদ্ধতি স্তরের আশেপাশে একটি লেনদেন পেতে চাই এবং একই ক্লাসের মধ্যে আমার কলার পদ্ধতি রয়েছে এবং এটি মনে হয় এটি এটি পছন্দ করে না, এটি পৃথক শ্রেণীর কাছ থেকে ডাকতে হবে। কীভাবে সম্ভব তা আমি বুঝতে পারছি না।

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

কোডটি এখানে:

public class UserService {

    @Transactional
    public boolean addUser(String userName, String password) {
        try {
            // call DAO layer and adds to database.
        } catch (Throwable e) {
            TransactionAspectSupport.currentTransactionStatus()
                    .setRollbackOnly();

        }
    }

    public boolean addUsers(List<User> users) {
        for (User user : users) {
            addUser(user.getUserName, user.getPassword);
        }
    } 
}

কটাক্ষপাত TransactionTemplate: পদ্ধতির stackoverflow.com/a/52989925/355438
Lu55

স্ব-অনুরোধ কেন কাজ করে না সে সম্পর্কে 8.6 প্রক্সি করার প্রক্রিয়া দেখুন
জেসন ল

উত্তর:


99

এটি স্প্রিং এওপি (ডায়নামিক অবজেক্টস এবং সিজিবিব ) এর একটি সীমাবদ্ধতা ।

আপনি যদি লেনদেনগুলি পরিচালনা করতে স্প্রিংটি AspectJ ব্যবহার করতে কনফিগার করেন তবে আপনার কোডটি কার্যকর হবে।

আপনার কোডটি রিফ্যাক্টর করা সহজ এবং সম্ভবত সর্বোত্তম বিকল্প। উদাহরণস্বরূপ এমন এক শ্রেণি যা ব্যবহারকারীদের পরিচালনা করে এবং প্রতিটি ব্যবহারকারীকে প্রক্রিয়া করে। তারপরে স্প্রিং এওপি-র সাথে ডিফল্ট লেনদেন কাজ করবে।


AspectJ এর সাথে লেনদেন পরিচালনা করার জন্য কনফিগারেশন টিপস

লেনদেনের জন্য স্প্রিংকে AspectJ ব্যবহার করতে সক্ষম করতে, আপনাকে অবশ্যই মোডটি AspectJ এ সেট করতে হবে:

<tx:annotation-driven mode="aspectj"/>

যদি আপনি 3.0.০ এর চেয়ে পুরানো সংস্করণ সহ স্প্রিং ব্যবহার করেন তবে আপনাকে এটি অবশ্যই আপনার বসন্তের কনফিগারেশনে যুক্ত করতে হবে:

<bean class="org.springframework.transaction.aspectj
        .AnnotationTransactionAspect" factory-method="aspectOf">
    <property name="transactionManager" ref="transactionManager" />
</bean>

তথ্যের জন্য আপনাকে ধন্যবাদ. আমি আপাতত কোডটি রিফ্যাক্ট করেছিলাম তবে আপনি দয়া করে আমাকে এসপেক্টজে ব্যবহার করে একটি উদাহরণ পাঠাতে পারেন বা আমাকে কিছু সহায়ক লিঙ্ক সরবরাহ করতে পারেন। আগাম ধন্যবাদ. মাইক।
মাইক

আমার উত্তরে লেনদেন নির্দিষ্ট AspectJ কনফিগারেশন যুক্ত করা হয়েছে। আমি আসা করি এটা সাহায্য করবে.
এসপেন

10
এটা ভালো! বিটিডব্লু: আপনি যদি আমার প্রশ্নকে আমাকে কিছু বিষয় বলার জন্য সেরা উত্তর হিসাবে চিহ্নিত করতে পারেন তবে এটি চমৎকার হবে। (সবুজ চেকমার্ক)
এস্পেন

2
স্প্রিং বুট কনফিগারেশন: @EnableTransactionManagement (মোড = অ্যাডভাইস মোড.এএসপিইসিটিজে)
ভিনিজোনস

64

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

<bean id="userService" class="your.package.UserService">
  <property name="self" ref="userService" />
    ...
</bean>

public class UserService {
    private UserService self;

    public void setSelf(UserService self) {
        this.self = self;
    }

    @Transactional
    public boolean addUser(String userName, String password) {
        try {
        // call DAO layer and adds to database.
        } catch (Throwable e) {
            TransactionAspectSupport.currentTransactionStatus()
                .setRollbackOnly();

        }
    }

    public boolean addUsers(List<User> users) {
        for (User user : users) {
            self.addUser(user.getUserName, user.getPassword);
        }
    } 
}

3
আপনি যদি এই রুটে যেতে বেছে নেন (এটি ভাল নকশা কিনা অন্য কোনও বিষয়) এবং কনস্ট্রাক্টর ইনজেকশন ব্যবহার না করেন তবে নিশ্চিত হন যে আপনি এই প্রশ্নটিও
যিশুরুন

UserServiceসিঙ্গলটনের সুযোগ থাকলে কী হবে ? যদি একই জিনিস হয়?
ইয়ান খোন্স্কি

26

স্প্রিং 4 এর সাথে স্ব-স্বাবলম্বিত হওয়া সম্ভব

@Service
@Transactional
public class UserServiceImpl implements UserService{
    @Autowired
    private  UserRepository repository;

    @Autowired
    private UserService userService;

    @Override
    public void update(int id){
       repository.findOne(id).setName("ddd");
    }

    @Override
    public void save(Users user) {
        repository.save(user);
        userService.update(1);
    }
}

2
সর্বোত্তম উত্তর !! Thx
mjassani

2
আমি ভুল হলে আমাকে সংশোধন করুন তবে এ জাতীয় ধরণটি আসলেই ত্রুটি-প্রবণ, যদিও এটি কার্যকর হয় works এটি আরও স্প্রিং ক্ষমতার শোকেসের মতো, তাই না? "এই বিন কল" আচরণের সাথে পরিচিত না এমন কেউ দুর্ঘটনাক্রমে স্ব-স্বায়িত শিমটি সরিয়ে ফেলতে পারেন (পদ্ধতিগুলি "এটি via" সর্বোপরি উপলব্ধ)) যা প্রথম নজরে সনাক্তকরণ করা শক্তির কারণ হতে পারে। এটি সন্ধানের আগে এটি উন্নত পরিবেশেও তৈরি করতে পারে)।
পিডাব্রো

2
@ পিডাব্রো আপনি ঠিক বলেছেন, এটি একটি বিশাল বিরোধী নিদর্শন এবং এটি প্রথম স্থানে স্পষ্ট নয়। তাই পারলে আপনার এড়ানো উচিত। যদি আপনাকে একই শ্রেণির পদ্ধতি ব্যবহার করতে হয় তবে আরও শক্তিশালী এওপি লাইব্রেরি যেমন অ্যাসপেক্টজে
আলমাস আব্দ্রজাক

21

জাভা 8 থেকে শুরু করে আরও একটি সম্ভাবনা রয়েছে, যা আমি নীচে প্রদত্ত কারণগুলির জন্য পছন্দ করি:

@Service
public class UserService {

    @Autowired
    private TransactionHandler transactionHandler;

    public boolean addUsers(List<User> users) {
        for (User user : users) {
            transactionHandler.runInTransaction(() -> addUser(user.getUsername, user.getPassword));
        }
    }

    private boolean addUser(String username, String password) {
        // TODO
    }
}

@Service
public class TransactionHandler {

    @Transactional(propagation = Propagation.REQUIRED)
    public <T> T runInTransaction(Supplier<T> supplier) {
        return supplier.get();
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public <T> T runInNewTransaction(Supplier<T> supplier) {
        return supplier.get();
    }
}

এই পদ্ধতির নিম্নলিখিত সুবিধা রয়েছে:

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

২) একই লেনদেনকে বিভিন্ন লেনদেনের প্রচারের মধ্যে ডেকে আনা যেতে পারে এবং উপযুক্তটি চয়ন করা কলারের উপর নির্ভর করে। এই 2 লাইন তুলনা করুন:

transactionHandler.runInTransaction(() -> userService.addUser(user.getUserName, user.getPassword));
transactionHandler.runInNewTransaction(() -> userService.addUser(user.getUserName, user.getPassword));

3) এটি সুস্পষ্ট, এইভাবে আরও পাঠযোগ্য।


এটা অসাধারণ! এটি স্প্রিং তার টীকাগুলির সাথে পরিচয় করিয়ে দেয় এমন সমস্ত সমস্যাগুলি এড়িয়ে চলে otherwise এটা ভালবাসা!
ফ্রাঙ্ক হপকিন্স

যদি আমি TransactionHandlerএকটি সাবক্লাস হিসাবে প্রসারিত করি , এবং সাবক্লাসটি TransactionHandlerসুপার ক্লাসে এই দুটি পদ্ধতিতে কল করে , আমি এখনও কি @Transactionalইচ্ছা মতো সুবিধা পেতে সক্ষম হব ?
tom_mai78101

6

এটি স্ব-অনুরোধের জন্য আমার সমাধান :

public class SBMWSBL {
    private SBMWSBL self;

    @Autowired
    private ApplicationContext applicationContext;

    @PostConstruct
    public void postContruct(){
        self = applicationContext.getBean(SBMWSBL.class);
    }

    // ...
}

0

আপনি একই বর্গের মধ্যে বিয়ানফ্যাক্টরীটিকে স্বায়িত করতে পারেন এবং একটি করতে পারেন

getBean(YourClazz.class)

এটি স্বয়ংক্রিয়ভাবে আপনার ক্লাসকে প্রক্সিফাই করবে এবং আপনার @ ট্রান্সজেকশনাল বা অন্যান্য অ্যাওপ টিকাটি অ্যাকাউন্টে নেবে।


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

0

সমস্যাটি কীভাবে বসন্তের লোড ক্লাস এবং প্রক্সি সম্পর্কিত is এটি কাজ করবে না, ততক্ষণ আপনি নিজের অভ্যন্তরীণ পদ্ধতি / লেনদেন অন্য ক্লাসে লিখেন বা অন্য শ্রেণিতে যান এবং তারপরে আবার আপনার ক্লাসে এসে তারপরে অভ্যন্তরীণ নেস্টেড ট্রান্সকেশন পদ্ধতি লিখবেন।

সংক্ষিপ্তসার হিসাবে, বসন্তের প্রক্সিগুলি যে পরিস্থিতিতে আপনি মুখোমুখি হচ্ছেন সেই দৃশ্যের মঞ্জুরি দেয় না। আপনাকে অন্য শ্রেণিতে ২ য় লেনদেনের পদ্ধতি লিখতে হবে


0

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

@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class PersonDao {

    private final PersonDao _personDao;

    @Autowired
    public PersonDao(PersonDao personDao) {
        _personDao = personDao;
    }

    @Transactional
    public void addUser(String username, String password) {
        // call database layer
    }

    public void addUsers(List<User> users) {
        for (User user : users) {
            _personDao.addUser(user.getUserName, user.getPassword);
        }
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.