Nếu tôi có một mối quan hệ @OneToMany với @Cascade (CascadeType.SAVE_UPDATE) như sauLàm thế nào để kích hoạt chế độ Hibernate Interceptor khi tôi có giao dịch Hibernate được quản lý bởi Spring?
public class One {
private Integer id;
private List<Many> manyList = new ArrayList<Many>();
@Id
@GeneratedValue
public Integer getId() {
return this.id;
}
@OneToMany
@JoinColumn(name="ONE_ID", updateable=false, nullable=false)
@Cascade(CascadeType.SAVE_UPDATE)
public List<Many> getManyList() {
return this.manyList;
}
}
Và Nhiều lớp
public class Many {
private Integer id;
/**
* required no-arg constructor
*/
public Many() {}
public Many(Integer uniqueId) {
this.id = uniqueId
}
/**
* Without @GeneratedValue annotation
* Hibernate will use assigned Strategy
*/
@Id
public Integer getId() {
return this.id;
}
}
Nếu tôi có Kịch bản sau
One one = new One();
/**
* generateUniqueId method will Take care of assigning unique id for each Many instance
*/
one.getManyList().add(new Many(generateUniqueId()));
one.getManyList().add(new Many(generateUniqueId()));
one.getManyList().add(new Many(generateUniqueId()));
one.getManyList().add(new Many(generateUniqueId()));
Và tôi gọi
sessionFactory.getCurrentSession().save(one);
Trước khi đi trên
Theo Transitive persistence tài liệu tham khảo Hibernate, bạn có thể nhìn thấy
Nếu phụ huynh được chuyển cho save(), cập nhật() hoặc saveOrUpdate(), tất cả trẻ em được chuyển đến saveOrUpdate()
ok. Bây giờ Chúng ta hãy xem những gì Java Persistence Với Hibernate cuốn sách Nói về phương pháp saveOrUpdate
Hibernate truy vấn bảng NHIỀU cho id cụ thể và nếu nó được tìm thấy, Hibernate cập nhật hàng. Nếu nó không được tìm thấy, chèn một hàng mới là bắt buộc và thực hiện.
Mà có thể được dịch theo
INSERT INTO ONE (ID) VALUES (?)
/**
* I have four Many instances added To One instance
* So four select-before-saving
*
* I DO NOT NEED select-before-saving
* Because i know i have a Fresh Transient instance
*/
SELECT * FROM MANY WHERE MANY.ID = ?
SELECT * FROM MANY WHERE MANY.ID = ?
SELECT * FROM MANY WHERE MANY.ID = ?
SELECT * FROM MANY WHERE MANY.ID = ?
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?)
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?)
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?)
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?)
Bất kỳ workaround Để tránh select-trước-tiết kiệm ??? Vâng, Bạn có thể
- Thêm một cột @version (Không áp dụng)
- thực hiện phương pháp isTransient cung cấp bởi Hibernate đánh chặn (Tùy chọn tôi có)
Vì vậy, như một cách để tránh chọn trước khi lưu hành vi mặc định khi sử dụng loại tầng này, tôi đã cải thiện mã của mình bằng cách gán một Hibernate Interceptor cho một phiên Hibernate có Giao dịch được quản lý bởi Spring.
Ở đây đi kho của tôi
Trước (Nếu không có bất kỳ Hibernate Interceptor): Nó hoạt động tốt!
@Repository
public class SomeEntityRepository extends AbstractRepository<SomeEntity, Integer> {
@Autowired
private SessionFactory sessionFactory;
@Override
public void add(SomeEntity instance) {
sessionFactory.getCurrentSession().save(instance);
}
}
Sau (Với Hibernate Inteceptor): họ gặp khó khăn (Không có truy vấn SQL được thực hiện - Cả INSERT Cũng CHỌN-TRƯỚC-TIẾT KIỆM)
@Repository
public class SomeEntityRepository extends AbstractRepository<SomeEntity, Integer> {
@Autowired
private SessionFactory sessionFactory;
@Override
public void add(SomeEntity instance) {
sessionFactory.openSession(new EmptyInterceptor() {
/**
* To avoid select-before-saving
*/
@Override
public Boolean isTransient(Object o) {
return true;
}
}).save(instance);
}
}
Câu hỏi của tôi là: Tại sao mùa xuân không kiên trì thực thể của tôi và các mối quan hệ của nó khi sử dụng Hibernate Interceptor và những gì tôi nên làm như workaround để làm việc tốt ???
Như đã nói: * Bạn có thể thêm Bộ chặn vào SessionFactory *. Nó xảy ra cho dù tôi thêm một Interceptor vào SessionFactory, tôi sẽ nhận được một hành vi ** toàn cục **. Tôi chỉ muốn thêm một Interceptor vào cá thể Session được sử dụng bởi phương thức add (SomeEntity instance). Bất kỳ cách giải quyết nào ??? –