2008-09-24 27 views
25

Tôi có một ứng dụng - giống như một tiện ích - nằm trong một góc và cập nhật hai cơ sở dữ liệu khác nhau theo định kỳ.Cách tốt nhất để thực hiện các giao dịch phân tán trên nhiều cơ sở dữ liệu bằng cách sử dụng Spring và Hibernate

Đây là một ứng dụng độc lập nhỏ đã được xây dựng bằng Ngữ cảnh ứng dụng mùa xuân. Ngữ cảnh có hai Nhà máy phiên Hibernate được cấu hình trong nó, lần lượt sử dụng các nguồn dữ liệu của Commons DBCP được cấu hình trong Spring.

Hiện tại không có quản lý giao dịch, nhưng tôi muốn thêm một số. Bản cập nhật cho một cơ sở dữ liệu phụ thuộc vào bản cập nhật thành công cho một cơ sở dữ liệu khác.

Ứng dụng không nằm trong vùng chứa Java EE - nó được khởi động bởi lớp khởi động tĩnh được gọi từ tập lệnh shell. Lớp khởi động khởi tạo ngữ cảnh ứng dụng và sau đó gọi một phương thức trên một trong các bean của nó.

Cách 'tốt nhất' để đặt giao dịch xung quanh cập nhật cơ sở dữ liệu là gì?

Tôi sẽ để lại định nghĩa 'tốt nhất' cho bạn, nhưng tôi nghĩ rằng cần có một số chức năng 'dễ thiết lập', 'dễ định cấu hình', 'rẻ tiền' và 'dễ dàng đóng gói và phân phối lại' . Tự nhiên FOSS sẽ là tốt.

Trả lời

26

Cách tốt nhất để phân phối giao dịch nhiều hơn một cơ sở dữ liệu là: Không.

Một số người sẽ chỉ cho bạn XA nhưng XA (hoặc hai giai đoạn Cam kết) là một lời nói dối (hoặc thị trường).

Hãy tưởng tượng: Sau khi giai đoạn đầu tiên đã nói với người quản lý XA rằng nó có thể gửi cam kết trận chung kết, kết nối mạng với một trong những cơ sở dữ liệu bị lỗi. Giờ thì sao? Hết giờ? Điều đó sẽ khiến cơ sở dữ liệu khác bị hỏng. Rollback? Hai vấn đề: Bạn không thể quay trở lại một cam kết và làm thế nào để bạn biết những gì đã xảy ra với cơ sở dữ liệu thứ hai? Có thể kết nối mạng không thành công sau khi nó đã cam kết thành công dữ liệu và chỉ thông báo "thành công" bị mất?

Cách tốt nhất là sao chép dữ liệu ở một nơi duy nhất. Sử dụng lược đồ cho phép bạn hủy bỏ bản sao và tiếp tục sao chép bất kỳ lúc nào (ví dụ, bỏ qua dữ liệu bạn đã có hoặc đặt hàng chọn theo ID và chỉ yêu cầu bản ghi> MAX (ID) của bản sao của bạn). Bảo vệ điều này bằng một giao dịch. Đây không phải là vấn đề vì bạn chỉ đọc dữ liệu từ nguồn, vì vậy khi giao dịch thất bại vì bất kỳ lý do gì, bạn có thể bỏ qua cơ sở dữ liệu nguồn. Do đó, đây là một giao dịch nguồn đơn thuần cũ.

Sau khi bạn đã sao chép dữ liệu, hãy xử lý dữ liệu cục bộ.

+5

Giao dịch được phân phối phải phản ánh tất cả 4 thuộc tính ACID. Vấn đề của bạn là gì? Kịch bản bạn mô tả không thể xảy ra, vì các nhà quản lý đang giao tiếp với nhau và chỉ cam kết khi tất cả các nút tham gia đã trao đổi "GO". – Falcon

+6

@Falcon: Vậy điều gì sẽ xảy ra nếu mạng bị lỗi giữa PREPARE và COMMIT? Hoặc một trong những máy chủ chết? "không thể xảy ra" không thể xảy ra trong thực tế. –

+2

Không, họ không được hướng dẫn quay lại vì trong trường hợp này, một số nút đã cam kết. Điều gì xảy ra là khi nút bị rơi trở nên có sẵn, điều phối viên giao dịch yêu cầu nó thực hiện lại. Bởi vì nút phản hồi tích cực trong giai đoạn "chuẩn bị", cần phải có khả năng "cam kết", ngay cả khi nó trở lại sau sự cố. –

6

Thiết lập trình quản lý giao dịch trong ngữ cảnh của bạn. Tài liệu mùa xuân có các ví dụ và rất đơn giản. Sau đó, khi bạn muốn thực hiện một giao dịch:

try { 
    TransactionTemplate tt = new TransactionTemplate(txManager); 

    tt.execute(new TransactionCallbackWithoutResult(){ 
    protected void doInTransactionWithoutResult(
      TransactionStatus status) { 
     updateDb1(); 
     updateDb2(); 
    } 
} catch (TransactionException ex) { 
    // handle 
} 

Để biết thêm ví dụ, và các thông tin có lẽ xem xét điều này: XA transactions using Spring

+3

Ví dụ này không thực sự trả lời câu hỏi hoặc thậm chí câu trả lời sai: OP đề cập rằng ông có hai nhà máy phiên Hibernate được cấu hình để yêu cầu hai người quản lý giao dịch riêng biệt. Ví dụ trong câu trả lời chỉ sử dụng một trình quản lý giao dịch không được chỉ định gần hơn. Sử dụng một trình quản lý giao dịch Hibernate duy nhất do đó sẽ không bao giờ khôi phục một trong hai DB về lỗi. Sử dụng ví dụ một 'ChainedTransactionManager' (như được ghi chú bởi @Pani Dhakshnamurthy) có thể giúp đỡ nhưng điều đó không được đề cập trong câu trả lời này. – Chriki

5

Khi bạn nói "hai cơ sở dữ liệu khác nhau", làm bạn có nghĩa là các máy chủ cơ sở dữ liệu khác nhau, hoặc hai lược đồ khác nhau trong cùng một máy chủ DB?

Nếu trước đây, sau đó nếu bạn muốn có đầy đủ transactionality, sau đó bạn cần API giao dịch XA, cung cấp đầy đủ hai giai đoạn cam kết. Nhưng quan trọng hơn, bạn cũng cần một điều phối viên giao dịch/màn hình mà quản lý giao dịch tuyên truyền giữa các hệ thống cơ sở dữ liệu khác nhau. Đây là một phần của JavaEE spec, và một phần khá hiếm hoi của nó ở đó. Bản thân điều phối viên TX là một phần mềm phức tạp. Phần mềm ứng dụng của bạn (thông qua Spring, nếu bạn muốn) nói chuyện với điều phối viên.

Tuy nhiên, nếu bạn chỉ có nghĩa là hai cơ sở dữ liệu trong DB server cùng, sau đó giao dịch vani JDBC nên chỉ làm việc tốt, chỉ cần thực hiện các hoạt động của bạn chống lại tất cả cơ sở dữ liệu trong một giao dịch duy nhất.

3

Trong trường hợp này, bạn sẽ cần một Màn hình giao dịch (máy chủ hỗ trợ giao thức XA) và đảm bảo cơ sở dữ liệu của bạn cũng hỗ trợ XA. Hầu hết (tất cả?) Máy chủ J2EE đi kèm với Giao diện Màn hình được tích hợp. Nếu mã của bạn không chạy trong máy chủ J2EE thì có một loạt các lựa chọn thay thế độc lập - Atomicos, Bitronix, v.v.