2015-04-08 24 views
6

tôi có như sau (giản thể) Hibernate thực thể:giao dịch bế tắc với Hibernate trên Oracle

@Entity(name = "Foo") 
public class Foo { 

    @Id 
    @GeneratedValue 
    public int id; 

    @OneToOne 
    public Bar bar; 
} 

@Entity(name = "Bar") 
public class Bar { 

    @Id 
    @GeneratedValue 
    public int id; 

    @Column 
    public String field; 

    @Version 
    public int version; 

} 

tôi cập nhật các thực thể trong một giao dịch mà trông gần như thế này:

Bar bar = findBar(em); 
Foo foo = findFoo(em); 

bar.field = "updated value"; 

if (<condition>) { 
    em.remove(foo); 
} 

em.detach(bar); 
em.merge(bar); 

Lưu ý rằng em.remove(foo) chỉ được gọi đôi khi, trong khi thanh luôn là u pdated.

Tôi thường xuyên nhận thấy các lỗi ORA-00060: Deadlock detected khi chạy ứng dụng. Kết xuất dường như cho thấy rằng hai phiên bế tắc bị khóa trên em.merge(bar)em.remove(foo), nhưng tôi không hiểu tại sao điều đó lại xảy ra.

Làm thế nào mã bế tắc này có thể? Có cách nào để cơ cấu lại nó tránh bế tắc không?

Dưới đây là một số thông tin thêm từ dấu vết:

Deadlock graph: 
         ---------Blocker(s)-------- ---------Waiter(s)--------- 
Resource Name   process session holds waits process session holds waits 
TX-00040005-000010dd  73 6557  X    81 6498   X 
TX-00010018-000010bd  81 6498  X    73 6557   X 

session 6557: DID 0001-0049-000002F5 session 6498: DID 0001-0051-0000030E 
session 6498: DID 0001-0051-0000030E session 6557: DID 0001-0049-000002F5 

Rows waited on: 
    Session 6557: obj - rowid = 00004797 - AAAEeXAB4AAADH0BBP 
    (dictionary objn - 18331, file - 120, block - 12788, slot - 15) 
    Session 6498: obj - rowid = 00007191 - AAAHGRAB4AAAACBBBo 
    (dictionary objn - 29041, file - 120, block - 129, slot - 40) 

----- Information for the OTHER waiting sessions ----- 
Session 6498: 
program: JDBC Thin Client 
    application name: JDBC Thin Client, hash value=2546894660 
    current SQL: 

delete from Foo where id=:1 

----- Current SQL Statement for this session (sql_id=sfasdgasdgaf) ----- 
update Bar set field=:1, version=:2 where id=:3 and version=:4 
+0

Có lẽ thật sự không thể tái tạo vấn đề của bạn. Vui lòng xem điều này nếu nó có thể giúp bạn dù sao http://lalitkumarb.wordpress.com/2014/02/25/understanding-oracle-deadlock/ –

+0

Bạn có thể ** TRACE ** các phiên hoàn chỉnh không? –

+0

@LalitKumarB Tôi có dấu vết, và từ đó tôi truy tìm lại các cuộc gọi đó để hợp nhất và xóa. Tôi thấy rằng đó là hai phiên bị khóa. Bạn có muốn thêm bất kỳ thông tin nào từ dấu vết không? – Oleksi

Trả lời

2

Nếu tôi hiểu đúng detach bạn nên làm một cái gì đó như thế:

Foo foo = findFoo(em); 
Bar bar = findBar(em); 

if (<condition>) { 
    em.remove(foo); 
    em.detach(bar); //If it is really necessary 
    em.flush(); 
} 

bar = findBar(em); //It will reattach the entity on the persistence context 
bar.field = "updated value"; 

em.merge(bar); 
em.commit(); 
+0

Vì vậy, điều này đã kết thúc giải quyết vấn đề của tôi. Không chắc chắn nếu nó là do chuyển đổi thứ tự của hoạt động, hoặc rõ ràng flush(), tách() cuộc gọi. Bạn có thể mở rộng khi các khóa thực sự được mua và phát hành trong một giao dịch không? – Oleksi

+0

Khi bạn tách một thực thể, nó không thể được lưu giữ nữa (bị khóa). Việc tìm kiếm sẽ tải một thực thể mới của cùng một bản ghi. Cái này không bị tách rời, vì vậy bạn có thể hợp nhất mà không gặp vấn đề gì. – Sertage

5

Nói chung có hai lý do chính cho bế tắc xảy ra trong Oracle

  • cái gọi là SX để SSX khóa leo thang. Điều này là do thiếu chỉ mục trên FK (bảng con). Trong trường hợp này Oracle phải khóa toàn bộ bảng con trước khi xác thực các ràng buộc. See AskTom Artice
  • thứ tự sai các câu lệnh SQL đặt

Trong mọi trường hợp bế tắc là do lỗi ứng dụng. Bạn sẽ cần báo cáo bế tắc (tệp .trc) từ máy chủ cơ sở dữ liệu. Bạn sẽ tìm thấy câu lệnh SQL và các bảng liên quan. Vì bạn sử dụng Hibernate bạn khó có thể dự đoán thứ tự thực hiện câu lệnh SQL, đôi khi nó có thể giúp mở rộng bộ đệm cache của Entity manager, để ngăn chặn các cuộc gọi quá sớm đến flush().

CHỈNH SỬA: OK để bạn có khóa TX (X). Đây là cấp độ hàng, trong khi SSX là cấp độ bảng. Sau đó, đối tượng bế tắc có thể là một hàng trong một bảng hoặc một khóa duy nhất trong một chỉ mục. Tệp theo dõi cũng phải chứa câu lệnh trước cho mỗi phiên và cũng là con trỏ (vị trí thực thi câu lệnh SQL), con trỏ cũng nên chứa các giá trị của các biến liên kết.

Cố gắng thực hiện:

select * from Foo where rowid = 'AAAHGRAB4AAAACBBBo'; 
select * from Bar where rowid = 'AAAEeXAB4AAADH0BBP'; 
  • Bạn có thực sự sử dụng CamelCase cho tên bảng?
  • DDL cho "Foo" và "Bar" là gì?
  • Có bế tắc nào xảy ra khi bạn thả FK giữa Foo và Bar?
  • Khi bạn chỉ gọi em.remove(foo); cũng sẽ thanh con bị xóa?
+0

Tôi đã lấy thông tin này ra khỏi một trc. Tôi đã sử dụng nó để theo dõi nó trở lại giao dịch đó với hai thực thể được đề cập trong câu hỏi. Bạn có đề xuất rằng việc thêm chỉ mục vào tham chiếu thanh trong thực thể foo có thể giải quyết vấn đề này không? – Oleksi

+0

Nếu báo cáo bế tắc của bạn chứa các loại khóa 'SX' và' SSX', thì đó là trường hợp đầu tiên. Sau đó, bạn cần tạo một chỉ mục trên 'FOO.BAR' vì FOO là bảng con của bảng BAR. Và 'FOO.BAR' trỏ vào' BAR.ID'. – ibre5041

+0

Báo cáo theo dõi bế tắc chỉ ra rằng cả hai loại khóa 'SX'. Không phải là 'SSX' – Oleksi

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