2011-11-03 26 views
7

Chúng tôi có trình kích hoạt chèn trước để nhận giá trị tiếp theo từ chuỗi. Khi đối tượng được tiếp tục với phương thức save(), hibernate nhận giá trị từ chuỗi và thêm nó vào đối tượng. và khi giao dịch được cam kết từ lớp dịch vụ của Spring, giá trị ID lại tăng lên trên cơ sở dữ liệu. làm cách nào để tránh bị NEXTVAL() nếu đối tượng đã có một id ..Sự cố phát hiện với Trình kích hoạt Oracle để tạo id từ một chuỗi

Dưới đây là những gì tôi ma cố gắng làm ..

UserDao

public User saveUser(User user){ 
     session.getCurrentSession.save(user);//line2 
     return user;//line3 
} 

UserService

public void saveUserAndWriteToAudit(User user, UserAudit userAudit){ 
    userDao.saveUser(user);//line1 
    userAudit.setUserId(user.getId);//line4 
    userAudit.saveUserAudit(userAudit);//line5 
} 

Và Lớp người dùng

@Entity 
    public class User{ 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO, generator="a1") 
    @SequenceGenerator(name="a1", sequenceName="usersequence") 
    private Long id; 
    ///////////////// 
} 

Khi con trỏ đến đối tượng người dùng line1 và line2 có null trong thuộc tính id. sau line2, nó có nextval từ chuỗi - cho phép nói 1. trên line4, tôi đã thêm id = 1 vào đối tượng useraudit của người dùng .. khi giao dịch được cam kết sau dòng 5, 2 được chèn vào cột id của người dùng và 1 vào cột userId của UserAudit. Điều này không có mục đích gì đối với tôi: (Làm cách nào để tránh vấn đề này? Cảm ơn!

Trả lời

9

Chỉ cập nhật trình kích hoạt của bạn để chỉ kích hoạt khi không được cấp id.

create or replace 
trigger sa.my_trigger 
before insert on sa.my_table 
for each row 
when (new.id is null) 
begin 
    select sa.my_sequence.nextval 
    into :new.id 
    from dual; 
end; 
+0

cảm ơn matthew .. – RKodakandla

0

Lý tưởng nhất là bạn nên loại bỏ BEFORE INSERT TRIGGER. Nếu không, Hibernate không có cách nào để biết khóa chính, và nó thực sự cần Nếu bạn không quan tâm đến đối tượng sau khi INSERT có thể ổn (cache cấp 2 vẫn là một vấn đề), nhưng nếu bạn cần sử dụng nó ngay lập tức thì đó là một vấn đề thực sự. cố gắng tiếp cận khó chịu này:.

  1. Nói Hibernate mà bạn quản lý các khóa chính bản thân
  2. Tạo đối tượng mới và đặt một giá trị tùy ý vào khóa chính
  3. .
  4. Xóa phiên Hibernate của bạn và chuỗi SELECT.CURRVAL (giả sử chỉ có một INSERT).
  5. Tải đối tượng bằng cách sử dụng giá trị chuỗi hiện tại thu được và không sử dụng trường hợp trên.
+0

@FelixM .. cảm ơn câu trả lời .. nếu chúng tôi sửa đổi trình kích hoạt để kiểm tra: new.id = null hay không, điều đó có hiệu quả không? .. Tôi không thể kiểm tra vì tôi không có đặc quyền db để sửa đổi trình kích hoạt .. Tôi cần phải chắc chắn rằng nó đủ trước khi yêu cầu dba sửa đổi nó – RKodakandla

+0

Nếu bạn thay đổi kích hoạt như mô tả trong các phản ứng khác, bạn có thể nói Hibernate để sử dụng trình tự. – FelixM

5

Giải pháp trên là tuyệt vời, nó đã giúp tôi giải quyết nhiều vấn đề này.

Kẹp duy nhất của tôi là nó mở cửa cho người dùng/mã để chèn bất kỳ giá trị ID nào mà không thực sự hỏi chuỗi.

Tôi đã tìm thấy giải pháp sau cũng hoạt động. Nó cho phép Hibernate tìm thấy ID tối đa và có nó tăng lên mỗi khi một câu lệnh chèn được thực thi. Nhưng khi nó chạm vào cơ sở dữ liệu, các ID được bỏ qua và thay thế bằng một tạo ra bởi các kích hoạt, vì vậy không có uniqueness in a cluster problem:

@Id 
    @GeneratedValue(generator="increment") 
    @GenericGenerator(name="increment", strategy = "increment") 
    private Long id; 

Hạn chế lớn nhất là @GenericGenerator là một chú thích Hibernate, vì vậy bạn mất tính di động JPA. Nó cũng không rõ ràng cho các lập trình viên rằng ID này thực sự được liên kết với một chuỗi trong khi trên thực tế, nó là một trong những giải pháp kết hợp chặt chẽ nhất mà sử dụng một chuỗi.

+0

Cảm ơn Christopher, tôi đã đấu tranh để sử dụng kích hoạt cơ sở dữ liệu để cư trú chính khóa và điều này giải quyết vấn đề. – user75ponic

0
create or replace 
trigger sa.my_trigger 
before insert on sa.my_table 
for each row 
when (new.id is null) 
begin 
    select sa.my_sequence.nextval 
    into :new.id 
    from dual; 
end; 

đây là điều gì đó thực sự sai trong thế giới cơ sở dữ liệu.

Xem xét giải pháp trên, giả sử sa.my_sequence.nextval là 51 và khung ngủ đông của bạn sẽ hoạt động mà không có bất kỳ sự cố nào. Nhưng nếu ai đó thực hiện chèn jdbc trực tiếp với giá trị khóa chính của bạn là 66 ghi đè chuỗi (ví dụ, giá trị hiện tại là 52), trình kích hoạt sẽ chỉ chèn.

Vấn đề thực sự là khi giá trị chuỗi tăng lên 66, điều này sẽ làm tăng ngoại lệ trong trình kích hoạt kết thúc khi đặt lại giá trị chuỗi. Điều này thực sự kết thúc trong cấu trúc xấu của thiết kế lược đồ từ phía cơ sở dữ liệu.

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