2012-06-30 42 views
11

Có giải pháp đơn giản nào để lưu dữ liệu vào cơ sở dữ liệu bằng JPA trong một chuỗi mới không?Gọi phương thức @Transactional từ một luồng khác (Runnable)

Ứng dụng web dựa trên Spring của tôi cho phép người dùng quản lý các tác vụ đã lên lịch. Trong thời gian chạy, anh ta có thể tạo và bắt đầu các phiên bản mới của các tác vụ được xác định trước. Tôi đang sử dụng TaskScheduler của mùa xuân và mọi thứ hoạt động tốt.

Nhưng tôi cần lưu kết quả boolean của mọi tác vụ được kích hoạt vào cơ sở dữ liệu. Tôi có thể làm cái này như thế nào?

EDIT: Tôi phải khái quát hóa câu hỏi của mình: Tôi cần phải gọi một phương thức trên lớp @Service từ nhiệm vụ. Vì kết quả nhiệm vụ phải được "xử lý" trước khi lưu vào cơ sở dữ liệu.

CHỈNH SỬA 2: Phiên bản đơn giản của mã có vấn đề của tôi xuất hiện tại đây. Khi saveTaskResult() được gọi từ scheduler, thông báo được in ra nhưng không có gì được lưu vào db. Nhưng bất cứ khi nào tôi gọi saveTaskResult() từ bộ điều khiển, bản ghi được lưu chính xác vào cơ sở dữ liệu.

@Service 
public class DemoService { 

    @Autowired 
    private TaskResultDao taskResultDao; 

    @Autowired 
    private TaskScheduler scheduler; 

    public void scheduleNewTask() { 
     scheduler.scheduleWithFixedDelay(new Runnable() { 

      public void run() { 
       // do some action here 
       saveTaskResult(new TaskResult("result")); 
      } 

     }, 1000L); 
    } 

    @Transactional 
    public void saveTaskResult(TaskResult result) { 
     System.out.println("saving task result"); 
     taskResultDao.persist(result); 
    } 

} 
+0

Chính xác thì vấn đề là gì? Bạn bắt đầu một chủ đề, bạn gọi các dịch vụ Spring của bạn chính xác như bạn đã làm nếu bạn chưa bắt đầu một luồng, và mọi thứ sẽ ổn. –

+0

Vấn đề là phương pháp kinh doanh mục tiêu là @Transactional. Khi tôi gọi phương thức này trong run(), dữ liệu không được duy trì. (Tôi đã cập nhật tiêu đề câu hỏi) –

+0

Trình chặn liên lạc giao dịch không quan tâm nếu chuỗi gọi phương thức là một chuỗi được tạo bởi thùng chứa servlet của bạn hoặc một chuỗi do bạn tạo. Nó sẽ hoạt động. Cho chúng tôi xem một số mã. –

Trả lời

14

Sự cố với mã của bạn là bạn mong đợi một giao dịch được bắt đầu khi bạn gọi saveTaskResult(). Điều này sẽ không xảy ra vì Spring sử dụng AOP để bắt đầu và dừng giao dịch.

Nếu bạn nhận được một thể hiện của một Bean bean giao dịch từ nhà máy đậu, hoặc thông qua tiêm phụ thuộc, những gì bạn nhận được trên thực tế là một proxy xung quanh bean. Proxy này bắt đầu một giao dịch trước khi gọi phương thức thực tế và cam kết hoặc hoàn nguyên giao dịch khi phương thức đã hoàn tất.

Trong trường hợp này, bạn gọi phương thức cục bộ của bean mà không phải thực hiện proxy giao dịch. Đặt phương thức saveTaskResult() (được chú thích bằng @Transactional) vào một bean Spring khác. Tiêm bean Spring khác này vào DemoService và gọi bean Spring khác từ DemoService, và mọi thứ sẽ ổn.

+0

Tuyệt vời, nó hoạt động. Đây chính xác là những gì tôi cần biết. Cảm ơn rất nhiều –

+0

Cảm ơn một triệu. giải pháp này hoạt động với CompletableFuture như quyến rũ. –

2

Giao dịch được lưu giữ tại địa phương lưu trữ luồng.
Nếu phương pháp khác của bạn đang chạy một chuỗi có chú thích @Transactional.
Giá trị mặc định được đặt là REQUIRED và điều này có nghĩa là nếu bạn chạy một phương thức được chú thích với @Transacitonal từ một chuỗi khác, bạn sẽ có giao dịch mới (vì không có giao dịch nào được lưu giữ trong chuỗi lưu trữ cục bộ của chuỗi này).

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