2017-09-14 32 views
5

Tôi đang cố gắng phân tích tình huống mà tôi có hai lớp học. Một lớp là ProcessImpl là điểm bắt đầu và gọi nội bộ các giao dịch con khác. Tôi không biết điều gì đang xảy ra. ProcessImpl đang nhập một số nội dung và ghi dữ liệu liên quan vào cơ sở dữ liệu.Giao dịch mùa xuân làm chậm quá trình hoàn thành

Specs

mùa xuân-orm phiên bản: 3.2.18.RELEASE.

Phiên bản JDK: 1.8.

Db: H2 (trên bất kỳ hiệu suất giống db nào được ghi lại).

Issue

Nếu tôi loại bỏ @Transactional từ ProcessImpl.processStage() quá trình này mất ~ 50 giây Nếu tôi giữ @Transactional từ ProcessImpl.processStage() quá trình này mất ~ 15 phút. Không biết tại sao điều này xảy ra. Tôi đã cố gắng giải quyết vấn đề này từ lâu nhưng không may mắn. Vui lòng xem mã bên dưới.

Yêu cầu: Toàn bộ processStage() hoàn tất hoặc hoàn nguyên, ngay cả khi một trong các giao dịch của trẻ không thành công.

Fyi: Tôi cũng nhận được nhiều thông báo như: "Tham gia vào giao dịch hiện tại". Đã cố gắng vượt qua điều này bằng cách thêm propagation=Propagation.NESTED vào processStage() nhưng không hoạt động.

ProcessImpl Class.

public class ProcessImpl { 

    /*This is the big transaction that calls other transactional stuff from MyServiceImpl 
    * This is starting point you can say for the process... 
    * 
    * If we remove @Transactional from here the process is lightning fast 
    * With transactional : 15minutes 
    * Without transactional : 50 seconds 
    * */ 
    @Transactional 
    public void processStage(){ 
     MyServiceImpl mp = new MyServiceImpl(); 
     //do some stuff 
     mp.doWork1(); 

     //do more work 
     mp.doWork2(); 

    } 

} 

MyServiceImpl Lớp

class MyServiceImpl{ 

    @Transactional 
    public void doWork1(){ 
     Object o = doChildWork(); 
     // and more stuff 
     //calls other class services and dao layers 
    } 

    @Transactional 
    public void doWork2(){ 
     //some stuff 
     doChildWork2(); 
     doChildWork(); 
     //more work 
    } 

    @Transactional 
    public Object doChildWork(){ 
     return new Object(); //hypothetical, I am returning list and other collection stuff 
    } 

    @Transactional 
    public Object doChildWork2(){ 
     return new Object(); //hypothetical, I am returning list and other collection stuff 
    } 

} 

Ngoài ra, ở đây tôi sẽ có được sự tự vấn đề gọi, mà không nên trong giao dịch?

+0

Cố gắng thêm 'readonly' cho '@ Transactional' – StanislavL

+0

Tôi đang làm rất nhiều chèn trong quá trình này cùng với các hoạt động chọn khác, vì vậy, sẽ chỉ đọc cho processStage vẫn có giá trị? – swapyonubuntu

+0

Không, sau đó chỉ đọc không phải là một lựa chọn cho trường hợp của bạn – StanislavL

Trả lời

3

Thật khó có thể đoán những gì đang xảy ra chính xác trong mã của bạn, tuy nhiên điều này là những vấn đề có thể:

Lock trên mức DB. Điều này có thể xảy ra khi bạn cập nhật cùng một đối tượng DB trong phạm vi doWork1()doWork2(). Vì cả hai phương pháp được thực hiện trong một giao dịch, các cập nhật được thực hiện bên trong doWork1() sẽ không được cam kết cho đến khi doWork2() hoàn tất. Cả hai phương pháp có thể cố gắng khóa cùng một đối tượng DB và đợi nó. Về mặt kỹ thuật, nó có thể là bất kỳ đối tượng DB nào: hàng trong bảng, chỉ mục, toàn bộ bảng, v.v.

Phân tích mã của bạn và cố gắng tìm những gì có thể bị khóa.Bạn cũng có thể xem nhật ký giao dịch DB trong khi phương thức đang chạy. Tất cả các DB phổ biến đều cung cấp chức năng giúp tìm các địa điểm có vấn đề.

Làm chậm trong khi làm mới ngữ cảnh Hibernate. Trong trường hợp bạn cập nhật quá nhiều đối tượng ORM engine (cho phép nói Hibernate) phải chìm chúng và giữ chúng trong bộ nhớ. Hibernate theo nghĩa đen phải có tất cả các trạng thái cũ và tất cả các trạng thái mới của các đối tượng được cập nhật. Đôi khi nó thực hiện điều này khá không tối ưu.

Bạn có thể biểu thị điều này bằng cách sử dụng gỡ lỗi. Cố gắng tìm địa điểm chậm nhất và kiểm tra chính xác những gì đang được gọi ở đó. Tôi có thể đoán rằng nó chậm lại khi cập nhật hibernate trạng thái của bộ nhớ cache.

Một vấn đề khác. Tôi thấy rằng bạn tạo MyServiceImpl sử dụng hàm tạo trong thời gian processStage(). Tôi khuyên bạn nên thay thế mã này bằng cách tự động chạy mùa xuân. Trước hết, cách bạn đang sử dụng nó không phải là cách nó được thiết kế để sử dụng, nhưng về mặt lý thuyết cũng có thể ảnh hưởng đến việc thực thi.

Tôi sẽ gặp vấn đề về tự gọi, điều này không được khuyến nghị trong Giao dịch?

Không, nó sẽ hoạt động tốt khi bỏ qua tất cả chú thích. Cuộc gọi của doChildWork()doChildWork2() bên trong doWork2() sẽ được coi là cuộc gọi java chuẩn (mùa xuân không thể thêm bất kỳ "phép thuật" nào cho họ miễn là bạn đang gọi trực tiếp).

0

Bất kỳ câu trả lời nào ở đây sẽ thực sự chỉ là (phỏng đoán rất tốt) phỏng đoán. Trong tình huống như thế này, điều tốt nhất cần làm là nắm giữ một trình lược tả Java và làm một sơ đồ chi tiết về mức cpu để tìm ra chính xác những gì đang diễn ra.

Tôi đề xuất YourKit xuất sắc là thương mại nhưng bạn có thể dùng thử miễn phí.

https://www.yourkit.com/docs/java/help/performance_bottlenecks.jsp

+0

đã làm điều đó và tôi rất chắc chắn @Transactional đang dẫn đến kết quả hiệu suất rất kém ... – swapyonubuntu

Các vấn đề liên quan