2009-06-11 34 views
8

Chúng tôi có một ứng dụng luồng công việc Java sử dụng cơ sở dữ liệu Oracle để theo dõi các bước và tương tác của nó với các dịch vụ khác. Trong một luồng công việc chạy một số chèn/cập nhật/lựa chọn được thực hiện và đôi khi lựa chọn sẽ không trả về dữ liệu cập nhật, mặc dù chèn/cập nhật cam kết chạy trước khi nó hoàn tất thành công. Sau khi các luồng công việc bị lỗi (do dữ liệu xấu), nếu chúng ta quay trở lại và kiểm tra cơ sở dữ liệu thông qua ứng dụng của bên thứ 3, dữ liệu mới/cập nhật sẽ hiển thị. Dường như có sự chậm trễ giữa khi các cam kết của chúng ta trải qua và khi chúng được hiển thị. Điều này xảy ra trong khoảng 2% của tất cả các dòng chảy công việc và nó tăng lên trong quá trình sử dụng cơ sở dữ liệu nặng.Độ trễ của Oracle giữa cam kết và chọn

Nhóm hỗ trợ cơ sở dữ liệu của chúng tôi đề xuất thay đổi tham số max-commit-propagation-delay thành 0, mặc định là 700. Đây dường như là giải pháp khả thi nhưng cuối cùng không khắc phục được sự cố của chúng tôi.

Ứng dụng chạy trên WebSphere và cơ sở dữ liệu Oracle được cấu hình dưới dạng nguồn dữ liệu JDBC. Chúng tôi đang sử dụng Oracle 10.1g. Ứng dụng được viết bằng Java 1.5.

Mọi trợ giúp sẽ được đánh giá cao.

chỉnh sửa: mẫu mã

DataSource ds; // spring configured 

String sql = "INSERT INTO " + currentTable + " (" + stepId + ',' + stepEntryId + ", " + stepStepId + ", " + stepActionId + ", " + stepOwner + ", " + stepStartDate + ", " + stepDueDate + ", " + stepFinishDate + ", " + stepStatus + ", " + stepCaller + ") VALUES (?, ?, ?, null, ?, ?, ?, null, ?, null)"; 

Connection conn = ds.getConnection(); 
PreparedStatement stmt = conn.prepareStatement(sql); 
// set values 
stmt.executeUpdate(); 
// close connections 

// later on in the code... 
Connection conn = ds.getConnection(); 
PreparedStatement stmt = null; 
ResultSet rset = null; 

String sql = "SELECT " + stepId + ", " + stepStepId + ", " + stepActionId + ", " + stepOwner + ", " + stepStartDate + ", " + stepDueDate + ", " + stepFinishDate + ", " + stepStatus + ", " + stepCaller + " FROM " + currentTable + " WHERE " + stepEntryId + " = ?"; 
stmt = conn.prepareStatement(sql); 

stmt.setLong(1, entryId); 

rset = stmt.executeQuery(); 
//close connections 
+0

Từ [Tài liệu Oracle] (http://download.oracle.com/docs/cd/B14117_01/server.101/b10755/initparams115.htm), có vẻ như tham số 'max_commit_propagation_delay' chỉ áp dụng cho thiết lập RAC. Bạn đang kết nối với một cá thể RAC? –

+0

Dữ liệu có được cam kết như một phần của giao dịch không? Hoặc đọc? –

Trả lời

1

đang sử dụng sử dụng một ORM? nó có thể được lựa chọn từ bộ nhớ cache và không tạo thành db sau khi thay đổi.

+0

Chúng tôi không sử dụng ORM, các bảng và câu lệnh sql thực sự là cơ bản và chỉ được sử dụng để lưu trữ lượng thông tin theo dõi nhỏ. – Andrew

+0

đăng đoạn mã nếu có thể ... –

+1

nếu đề xuất @Steve Broberg không hoạt động, bạn có thể thử sử dụng cùng một kết nối –

6

Theo mặc định, hành vi bạn mô tả là không thể - các thay đổi được thực hiện trong giao dịch đã cam kết sẽ có sẵn ngay lập tức cho tất cả các phiên. Tuy nhiên, có những ngoại lệ:

  1. Bạn có sử dụng bất kỳ tùy chọn WRITE nào trong lệnh COMMIT không? Nếu không, hãy xác nhận giá trị của tham số khởi tạo COMMIT_WRITE của bạn. Nếu một trong hai hoặc bằng cách sử dụng "WRITE BATCH" hoặc đặc biệt là "WRITE BATCH NOWAIT", bạn có thể tự mở cho mình các vấn đề tương tranh. "WRITE BATCH NOWAIT" thường được sử dụng trong trường hợp tốc độ ghi các giao dịch của bạn có tầm quan trọng lớn hơn các vấn đề đồng thời có thể xảy ra. Nếu tham số khởi tạo của bạn đang sử dụng biến thể "WRITE", bạn có thể ghi đè lên biến thể trên cơ sở giao dịch bằng cách chỉ định mệnh đề IMMEDIATE trong các cam kết của bạn (see COMMIT)

  2. Giao dịch đó đang cố đọc dữ liệu gọi SET TRANSACTION trước giao dịch khác cam kết? Sử dụng SET GIAO DỊCH để xác định serialization CẤP READ ONLY hoặc SERIALIZABLE sẽ dẫn đến việc giao dịch thấy không có thay đổi nào xảy ra từ buổi cam kết khác đã xảy ra sau khi gọi của SET GIAO DỊCH (see SET TRANSACTION)

chỉnh sửa: Tôi thấy rằng bạn đang sử dụng một lớp DataSource. Tôi không quen thuộc với lớp này - tôi cho rằng đó là một tài nguyên chia sẻ kết nối. Tôi nhận ra rằng thiết kế ứng dụng hiện tại của bạn có thể không dễ sử dụng cùng một đối tượng kết nối trong suốt luồng công việc của bạn (các bước có thể được thiết kế để hoạt động độc lập và bạn không xây dựng cơ sở để truyền đối tượng kết nối từ một bước đến tiếp theo), nhưng bạn nên xác minh rằng các đối tượng kết nối được trả về đối tượng DataSource là "sạch", đặc biệt là đối với các giao dịch mở. Có thể bạn không gọi SET TRANSACTION trong mã của bạn, nhưng một người tiêu dùng khác của DataSource có thể làm như vậy và trả lại kết nối về nguồn dữ liệu với phiên vẫn ở chế độ SERIALIZABLE hoặc READ ONLY. Khi chia sẻ kết nối, điều bắt buộc là tất cả các kết nối được cuộn lại trước khi giao cho người tiêu dùng mới.

Nếu bạn không kiểm soát hoặc hiển thị hành vi của lớp DataSource, bạn có thể thử thực hiện ROLLBACK trên kết nối mới được mua để đảm bảo nó không có giao dịch kéo dài đã được thiết lập.

+0

+1 !!! Tôi thậm chí không được coi là COMMIT có thể khác với IMIT NGAY LẬP TỨC hoặc mức cô lập giao dịch không phải là READ COMMITTED. – spencer7593

+0

Xin lỗi vì sự chậm trễ trong việc liên lạc lại với bạn. Tôi không nghĩ rằng tôi đang sử dụng bất kỳ tùy chọn viết cho cam kết. Tôi chỉ sử dụng bất kỳ lớp kết nối java mặc định, điều tương tự cũng xảy ra đối với cài đặt cách ly giao dịch. Dưới đây là một số liên kết tài liệu cho các lớp java tôi đang sử dụng: http://java.sun.com/j2se/1.5.0/docs/api/javax/sql/DataSource.html http: //java.sun .com/j2se/1.5.0/docs/api/java/sql/Connection.html http://java.sun.com/j2se/1.5.0/docs/guide/jdbc/getstart/connection.html – Andrew

4

Nếu nhóm DBA cố sửa đổi thông số max_commit_propagation_delay, có thể bạn đang kết nối với một cá thể RAC (i-e: một số máy chủ riêng biệt truy cập vào một cơ sở dữ liệu).

Trong trường hợp đó, khi bạn đóng và mở lại kết nối trong mã java của mình, có khả năng bạn sẽ được máy chủ khác trả lời. Tham số trễ có nghĩa là có một khung thời gian nhỏ khi hai phiên bản sẽ không ở chính xác cùng một thời điểm. Câu trả lời bạn nhận được là phù hợp với một điểm trong thời gian nhưng có thể không phải là mới nhất.

Theo đề xuất của KM, giải pháp đơn giản nhất là giữ kết nối được mở sau khi cam kết. Ngoài ra, bạn cũng có thể thêm một sự chậm trễ sau khi đóng kết nối nếu nó là thực tế (nếu đây là một công việc hàng loạt và thời gian đáp ứng là không quan trọng ví dụ).

0

Điều này nghe giống như vấn đề với RAC, với các kết nối đến hai trường hợp khác nhau và SCN không đồng bộ.

Giải pháp thay thế, xem xét không đóng kết nối cơ sở dữ liệu và nhận kết nối mới, nhưng tái sử dụng cùng một kết nối.

Nếu không thể thực hiện được, sau đó thêm thử lại truy vấn tìm cách truy xuất hàng được chèn. Nếu hàng không được trả lại, sau đó ngủ một chút và thử lại truy vấn. Đặt điều đó vào vòng lặp, sau một số lần thử lại được chỉ định, bạn có thể thất bại.

[ADDENDUM]

Trong câu trả lời của mình, Steve Broberg (+1!) Đưa ra những ý tưởng thú vị. Tôi đã không xem xét:

  • các COMMIT có thể là bất cứ điều gì khác hơn là IMMEDIATE WAIT
  • mức cô lập giao dịch có thể là bất cứ điều gì khác hơn là ĐỌC CAM KẾT

tôi đã xem xét khả năng truy vấn hồi tưởng, và đã bác bỏ điều đó mà không đề cập đến nó, vì không có lý do rõ ràng nào OP sẽ sử dụng truy vấn flashback và không có bằng chứng về điều đó trong đoạn mã.)

[/ ADDENDUM]

0

Cách giải quyết có thể là sử dụng giao dịch JTA. Nó giúp kết nối của bạn mở "đằng sau cảnh" qua nhiều kết nối jdbc mở/đóng. Có thể nó sẽ giữ kết nối của bạn trên cùng một máy chủ và tránh sự cố đồng bộ hóa này '.

UserTransaction transaction = (UserTransaction)new InitialContext().lookup("java:comp/UserTransaction"); 
transaction.begin(); 
// doing multiple open/close cxs 
transaction.commit(); 
0

Đoạn mã không thực sự bao gồm cam kết.

Nếu bạn đang giả định/dựa vào kết nối gần thực hiện cam kết, nó có thể không đồng bộ (tức là java có thể báo cáo kết nối là đóng khi nó yêu cầu Oracle đóng kết nối, có nghĩa là nó có thể là trước cam kết được hoàn thành bởi Oracle).

+0

http : //java.sun.com/j2se/1.5.0/docs/api/java/sql/Connection.html Theo mặc định, đối tượng Connection đang ở chế độ tự động cam kết, có nghĩa là nó sẽ tự động thực hiện các thay đổi sau khi thực hiện từng tuyên bố. – Andrew

+0

Yuck. Nhưng điều tương tự cũng có thể áp dụng, vì bạn không có quyền kiểm soát cách thức/khi cam kết đang được thực hiện. Bên cạnh đó, có một hình phạt hiệu suất (và có thể hậu quả toàn vẹn dữ liệu) trong cam kết không cần thiết. Tắt nó đi, cam kết một cách rõ ràng và xem vấn đề có biến mất hay không. –

0

Tôi không thấy cam kết trong mã của bạn.Chúng là những tuyên bố quan trọng nhất trong một ứng dụng như vậy vì vậy tôi muốn chúng được viết một cách rõ ràng mọi lúc, không dựa vào việc đóng() hay như vậy.

Bạn cũng có thể đặt autocommit thành true theo mặc định trên (các) kết nối của bạn sẽ giải thích chính xác hành vi (nó cam kết sau mỗi lần chèn/cập nhật).

Bạn có thể kiểm tra, rằng bạn đã cam kết chính xác nơi bạn muốn, ví dụ: ở cuối giao dịch và không phải trước đây?

Nếu có cam kết khi bạn đi qua một phần, thì bạn có điều kiện đua giữa các chủ đề của bạn cũng sẽ giải thích tại sao có nhiều vấn đề hơn khi tải lớn hơn.

+0

Tôi có tự động cam kết được đặt thành true mặc dù tôi không chắc chắn cách giải thích hành vi mà tôi đang thấy. Tôi thực hiện một chèn và executeUpdate() mà tự động cam kết, sau đó thực hiện một lựa chọn và hàng chèn vào đó không được tìm thấy. Tôi không thấy một điều kiện chủng tộc có thể xảy ra ở đây như thế nào, xem xét rằng executeUpdate() sẽ không trở lại cho đến khi nó được cam kết. – Andrew

0

"mặc dù chèn/cập nhật cam kết chạy trước khi hoàn thành thành công".

Điều này gợi ý với tôi rằng bạn đang ban hành một cam kết(), và sau đó dự kiến ​​sẽ đọc chính xác cùng một dữ liệu một lần nữa (đó là đọc lặp lại).

Điều này cho thấy rằng bạn không nên cam kết. Miễn là bạn muốn chắc chắn rằng KHÔNG CÓ NHIỆM VỤ KHÁC có thể sửa đổi BẤT K of dữ liệu mà bạn mong muốn EXPECT để duy trì ổn định, bạn không thể đủ khả năng để giải phóng khóa (đó là những gì cam kết).

Lưu ý rằng trong khi bạn giữ khóa trên một số tài nguyên, các chủ đề khác sẽ được xếp chồng lên "đang chờ tài nguyên đó khả dụng". Khả năng của ngăn xếp đó là không trống vào thời điểm bạn nhả khóa, cao hơn khi tải hệ thống chung cao hơn. Và những gì DBMS của bạn sẽ kết thúc khi bạn (cuối cùng) đưa ra "cam kết", là kết luận rằng, "hey, wow, anh chàng này cuối cùng đã được thực hiện với tài nguyên này, vì vậy bây giờ tôi có thể đi về để cho tất cả những người chờ đợi khác thử và làm điều của họ với nó (và không có gì để ngăn chặn "điều của họ" từ một bản cập nhật!) ".

Có thể có vấn đề liên quan đến sự cô lập ảnh chụp của Oracle mà tôi đang xem. Xin lỗi nếu có.

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