6

Tôi có một lớp truy cập dữ liệu chạy như một phần của ứng dụng java độc lập. Nó hiện đang làm việc có nghĩa là một người quản lý giao dịch được định nghĩa nhưng tôi muốn cấu trúc lại lớp để giảm phạm vi giao dịch nhưng nếu tôi nhận được org.hibernate.HibernateException: Không có phiên Hibernate nào bị ràng buộc vào luồng và cấu hình không cho phép tạo một giao dịch phi giao dịch tại đây ngụ ý rằng việc di chuyển @Transactional bằng cách nào đó đã ngăn không cho nó được nhận dạng.Làm cách nào để bạn tái cấu trúc phương thức @Transactional để tách các phần không giao dịch

Phiên bản gốc của tôi có các phương pháp được cấu trúc lại là riêng tư nhưng tôi đã tìm thấy đề xuất thay đổi điều đó thành công khai như trong một số trường hợp, chú thích sẽ không được chọn.

public class DoStuff { 
    @Transactional 
    public void originalMethod() { 
     // do database stuff 
     ... 

     // do non-database stuff that is time consuming 
     ... 
    } 
} 

Những gì tôi muốn làm là cấu trúc lại như sau

public class DoStuff { 
    public void originalMethod() { 
     doDatabaseStuff() 

     doNonDatabaseStuff() 
    } 

    @Transactional 
    public void doDatabaseStuff() { 
     ... 
    } 

    public void doNonDatabaseStuff() { 
     ... 
    } 
} 
+0

Người quản lý giao dịch của bạn ở đâu? Bạn có thể thêm chi tiết hơn không? – Chris

+0

DoStuff lớp của bạn có triển khai bất kỳ giao diện nào không? –

+0

Không có giao diện và trình quản lý giao dịch được định nghĩa là nó hoạt động đối với lớp gốc. –

Trả lời

6

Edit:

Bạn cần phải hiểu how Spring proxying works để hiểu tại sao refactoring của bạn không hoạt động.

Cuộc gọi phương thức trên tham chiếu đối tượng sẽ là cuộc gọi trên proxy và như vậy proxy sẽ có thể ủy quyền cho tất cả các máy đánh chặn (lời khuyên) có liên quan đến cuộc gọi phương thức cụ thể đó. Tuy nhiên, một khi cuộc gọi cuối cùng đã đạt được đối tượng đích, bất kỳ phương thức nào gọi nó có thể tự tạo ra, sẽ được gọi ra khỏi tham chiếu này, và không phải là proxy. Điều này có ý nghĩa quan trọng. Nó có nghĩa là tự gọi sẽ không dẫn đến lời khuyên kết hợp với một lời gọi phương thức nhận được một cơ hội để thực thi.

@Transactional sử dụng Spring AOP, Spring sử dụng proxy. Điều này có nghĩa là khi bạn gọi phương thức @Transactional từ một lớp khác, Spring sẽ sử dụng proxy, vì vậy lời khuyên giao dịch sẽ được áp dụng. Tuy nhiên, nếu bạn gọi phương thức từ cùng một lớp, mùa xuân sẽ sử dụng tham chiếu "này" thay vì proxy, do đó lời khuyên giao dịch sẽ không được áp dụng.

gốc trả lời:

Đây là những gì làm việc cho tôi trong kịch bản tương tự.

public class DoStuff implement ApplicationContextAware {  
private ApplicationContext CONTEXT; 
public void setApplicationContext(ApplicationContext context) throws BeansException { 
    CONTEXT = context; 
} 

    public void originalMethod() {   
     getSpringProxy().doDatabaseStuff()    
     doNonDatabaseStuff()  
    } 

    private DoStuff getSpringProxy() { 
     return context.getBean(this.getClass());  
    } 
    @Transactional  
    public void doDatabaseStuff() {   
     ...  
    }   

    public void doNonDatabaseStuff() {   
     ...  
    } 
} 

Giải thích:

  1. Làm cho lớp ApplicationContextAware, vì vậy nó có một tham chiếu đến bối cảnh
  2. Khi bạn cần gọi một phương thức giao dịch, lấy proxy mùa xuân thực tế từ bối cảnh
  3. Sử dụng proxy này để gọi phương thức của bạn để @Transactional thực sự được áp dụng.
+0

Lớp gốc đã nhận ra @Transactional và hoạt động chính xác. Nó chỉ dừng hoạt động sau khi tái cấu trúc. –

+0

@Michael Rutherfurd xem chỉnh sửa của tôi – gresdiplitude

+0

Điều này có vẻ là vấn đề của tôi. Cảm ơn –

0

Cách tiếp cận của bạn có vẻ như chỉ hoạt động tốt, tôi cho rằng sự cố có liên quan đến Proxy mùa xuân.

Lý do tôi hỏi về giao diện có liên quan đến phương pháp mặc định mà theo đó Spring áp dụng hành vi giao dịch - proxy động JDK.

Nếu định nghĩa thực tế của lớp học của bạn là:

public class DoStuff implements Doable { 
    public void originalMethod() { 

    } 
} 

public interface Doable { 
    public void originalMethod(); 
} 

Nếu đây thực sự là cơ cấu, khi bạn chuyển sang mùa xuân cấu trúc mới không có khả năng để proxy phương pháp mới doDatabaseStuff.

lựa chọn của bạn để sửa lỗi này:

  • Thêm phương pháp mới để giao diện của bạn để đảm bảo rằng mùa xuân có thể ủy quyền cho họ
  • Move để sử dụng proxy cglib dựa (những không dựa trên giao diện)
+0

Không có lớp nào là POJO, không có giao diện nào được triển khai ở tất cả –

+0

Ồ tốt. Vẫn. Đó là tất cả sự thật :) –

+0

Tôi đã không đồng ý với tôi (chỉ nói rằng nó không áp dụng trong trường hợp này :-) –

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