Sự khác biệt giữa session.Merge và session.SaveOrUpdate là gì?


86

Tôi nhận thấy đôi khi với các đối tượng cha / con hoặc các mối quan hệ nhiều-nhiều, tôi cần gọi SaveOrUpdatehoặc Merge. Thông thường, khi tôi cần gọi SaveOrUpdate, ngoại lệ tôi nhận được khi gọi Mergeliên quan đến các đối tượng tạm thời không được lưu trước.

Vui lòng giải thích sự khác biệt giữa hai.

Câu trả lời:


157

Đây là từ phần 10.7. Tự động phát hiện trạng thái của Tài liệu Tham khảo Hibernate:

saveOrUpdate () thực hiện như sau:

  • nếu đối tượng đã tồn tại trong phiên này, không làm gì cả
  • nếu một đối tượng khác được liên kết với phiên có cùng số nhận dạng, hãy ném một ngoại lệ
  • nếu đối tượng không có thuộc tính định danh, hãy lưu () nó
  • nếu mã định danh của đối tượng có giá trị được gán cho một đối tượng mới được khởi tạo, hãy lưu () nó
  • nếu đối tượng được tạo phiên bản (bởi <version> hoặc <timestamp>) và giá trị thuộc tính phiên bản là cùng một giá trị được gán cho một đối tượng mới được khởi tạo, hãy lưu () nó
  • nếu không thì cập nhật () đối tượng

và merge () rất khác:

  • nếu có một phiên bản liên tục với cùng một số nhận dạng hiện được liên kết với phiên, hãy sao chép trạng thái của đối tượng đã cho vào phiên bản liên tục
  • nếu không có phiên bản liên tục nào hiện được liên kết với phiên, hãy thử tải nó từ cơ sở dữ liệu hoặc tạo một phiên bản liên tục mới
  • trường hợp liên tục được trả lại
  • phiên bản đã cho không được liên kết với phiên, nó vẫn tách rời

Bạn nên sử dụng Merge () nếu bạn đang cố gắng cập nhật các đối tượng tại một thời điểm được tách ra khỏi phiên, đặc biệt nếu có thể có các trường hợp liên tục của các đối tượng đó hiện được liên kết với phiên. Nếu không, việc sử dụng SaveOrUpdate () trong trường hợp đó sẽ dẫn đến một ngoại lệ.


câu trả lời hay ... Tôi tự hỏi - nếu tôi sử dụng hợp nhất trên một thực thể mới thì có lý do nào để sử dụng lưu chữ sau không hoặc tôi có thể cho rằng hợp nhất đã tạo ra thực thể mới trong DB chắc chắn? (và nếu đó là một thực thể tách rời, khi hợp nhất các thay đổi có tự động bị bỏ qua đối với DB không?)
Dani

5
Bạn có chắc về điều này? Nhìn vào nguồn NHiberante SaveOrUpdateCopy kích hoạt sự kiện Hợp nhất với các tham số giống như hàm Hợp nhất. Tôi nghĩ rằng họ là giống hệt nhau, hàm SaveOrUpdateCopy là cái gì đó đã tồn tại trong hibernate / nhibernate từ 1.0 chức năng Merge là mới và được bổ sung vào để ngủ đông để phù hợp với một tiêu chuẩn java mới (tôi nghĩ)
Torkel

5
@Torkel - SaveOrUpdateCopykhông giống với SaveOrUpdate. Tôi không chắc liệu người hỏi muốn so sánh Mergecái trước hay cái sau. SaveOrUpdateCopylà một phương pháp hiện đã lỗi thời đã thực hiện hợp nhất trong NHibernate trước khi Mergeđược nhập.
codekaizen

thật tốt khi biết ... SaveOrUpdate vẫn được sử dụng nhiều trong các bài hướng dẫn.
anael

9

Theo tôi hiểu, merge()sẽ lấy một đối tượng có thể không được liên kết với phiên hiện tại và sao chép trạng thái của nó (giá trị thuộc tính, v.v.) sang một đối tượng được liên kết với phiên hiện tại (có cùng giá trị / định danh PK, của khóa học).

saveOrUpdate()sẽ gọi Lưu hoặc Cập nhật trên phiên của bạn, dựa trên giá trị nhận dạng của một đối tượng nhất định.


4

SaveOrUpdateCopy()hiện không được dùng nữa kể từ NHibernate 3.1. Merge()nên được sử dụng thay thế.


9
SaveOrUpdateCopyđược đánh dấu Obsolete, không phải SaveOrUpdate. Có vẻ như có rất nhiều sự nhầm lẫn giữa hai phương pháp khác nhau trong câu hỏi này và các câu trả lời tiếp theo.
codekaizen

2
** Update()**

: - nếu bạn chắc chắn rằng phiên không chứa một phiên bản đã tồn tại lâu dài với cùng một số nhận dạng thì hãy sử dụng cập nhật để lưu dữ liệu ở chế độ ngủ đông

** Merge()**

: -nếu bạn muốn lưu các sửa đổi của mình bất kỳ lúc nào mà không biết về trạng thái của phiên thì hãy sử dụng merge () ở chế độ ngủ đông.


1

Tôi tìm thấy liên kết này đã hoạt động khá tốt khi giải thích loại ngoại lệ này:

Những gì làm việc cho tôi là như sau:

  1. Trong tệp ánh xạ Myclass.hbm.xml, hãy đặt cascade="merge"
  2. SaveOrUpdate đối tượng con / phụ thuộc đầu tiên trước khi gán nó cho đối tượng cha.
  3. SaveOrUpdate đối tượng cha.

Tuy nhiên, giải pháp này có những hạn chế. tức là bạn phải lo cứu con / đối tượng phụ thuộc của bạn thay vì để ngủ đông làm việc đó cho bạn.

Nếu có ai có giải pháp tốt hơn, tôi muốn xem.


-2
@Entity
@Table(name="emp")
public class Employee implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="emp_id")
    private int id;
    @Column(name="emp_name")
    private String name;
    @Column(name="salary")
    private int Salary;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSalary() {
        return Salary;
    }

    public void setSalary(int salary) {
        this.Salary = salary;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

public enum HibernateUtil {
    INSTANCE;
    HibernateUtil(){
        buildSessionFactory();
    }
    private SessionFactory sessionFactory=null;

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    private  void buildSessionFactory() {
        Configuration configuration = new Configuration();

        configuration.addAnnotatedClass (TestRefresh_Merge.Employee.class);
        configuration.setProperty("connection.driver_class","com.mysql.jdbc.Driver");
        configuration.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/hibernate");                                
        configuration.setProperty("hibernate.connection.username", "root");     
        configuration.setProperty("hibernate.connection.password", "root");
        configuration.setProperty("dialect", "org.hibernate.dialect.MySQLDialect");
        configuration.setProperty("hibernate.hbm2ddl.auto", "update");
        configuration.setProperty("hibernate.show_sql", "true");
        configuration.setProperty(" hibernate.connection.pool_size", "10");
        /* configuration.setProperty(" hibernate.cache.use_second_level_cache", "true");
         configuration.setProperty(" hibernate.cache.use_query_cache", "true");
         configuration.setProperty(" cache.provider_class", "org.hibernate.cache.EhCacheProvider");
         configuration.setProperty("hibernate.cache.region.factory_class" ,"org.hibernate.cache.ehcache.EhCacheRegionFactory");
        */
        // configuration
        StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
           sessionFactory = configuration.buildSessionFactory(builder.build());
           setSessionFactory(sessionFactory);
    }

    public  static SessionFactory getSessionFactoryInstance(){
        return INSTANCE.getSessionFactory();
    }
} 


public class Main {
    public static void main(String[] args) {
        HibernateUtil util=HibernateUtil.INSTANCE;
        SessionFactory factory=util.getSessionFactory();
        //save(factory); 
        retrieve(factory);
    }

     private static void retrieve(SessionFactory factory) {
        Session sessionOne=factory.openSession();

        Employee employee=(Employee)sessionOne.get(Employee.class, 5);

        sessionOne.close(); // detached Entity

        employee.setName("Deepak1");

        Session sessionTwo=factory.openSession();

        Employee employee1=(Employee)sessionTwo.get(Employee.class, 5);
        sessionTwo.beginTransaction();
        sessionTwo.saveOrUpdate(employee); // it will throw exception

        //sessionTwo.merge(employee); // it will work

        sessionTwo.getTransaction().commit();

        sessionTwo.close();

    }

    private static void save(SessionFactory factory) {
        Session sessionOne=factory.openSession();
        Employee emp=new Employee();
        emp.setName("Abhi");
        emp.setSalary(10000);
        sessionOne.beginTransaction();
        try{

            sessionOne.save(emp);
            sessionOne.getTransaction().commit();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            sessionOne.close();
        }

    }
}

2
Bạn nên xem xét chỉnh sửa câu trả lời của mình để hiển thị mã được thực hiện và sau đó có thể xem xét kết xuất mã đầy đủ ở cuối. Khi nó đứng, chúng ta phải cuộn xuống và xem các nhận xét. Xem Cách trả lời .
Lỗi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.