Code ví dụ Hibernate annotation @Version (Hibernate Locking Version)

Code ví dụ Hibernate annotation @Version (Hibernate Locking Version)

(Xem lại: Code ví dụ Hibernate + MySQL +Maven + Eclipse)

Hibernate @Version

Xem lại giải thích về annotation @Version https://stackjava.com/hibernate/…#annotation-version

Các công nghệ sử dụng trong ví dụ

Tạo database trên MySQL

Trong ví dụ này mình tạo cơ sở dữ liệu ‘hibernate-version’ với table customer (id, name, address, version) trong đó id tự tăng, column version sẽ lưu trữ version dưới dạng số.

CREATE DATABASE  IF NOT EXISTS `hibernate-version`;

CREATE TABLE `hibernate-version`.`customer` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  `version` int(3) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

Tạo database trên MySQL

Tạo maven project

 Code ví dụ Hibernate annotation @Version (Hibernate Locking Version)
Thư viện sử dụng:
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-core</artifactId>
  <version>5.1.0.Final</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.11</version>
</dependency>

 File cấu hình hibernate:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate-version?useSSL=false</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">admin1234</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.hibernate.current_session_context_class">thread</property>
        
        <mapping class="stackjava.com.hibernateversion.entities.Customer" />
    </session-factory>
</hibernate-configuration>

 File entity

package stackjava.com.hibernateversion.entities;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Version;

@Entity
@Table(name = "customer")
public class Customer implements Serializable{
  private static final long serialVersionUID = 1L;

  @Id
  @Column(name = "id")
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private int id;

  @Column(name = "name")
  private String name;

  @Column(name = "address")
  private String address;
  
  @Column(name = "version")
  @Version
  private int version;
  
  // constructor
  // getter - setter
  
}

File DAO

package stackjava.com.hibernateversion.dao;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import stackjava.com.hibernateversion.entities.Customer;

public class CustomerDAO {
  SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
  
  public void save(Customer customer) {
    Session session = sessionFactory.openSession();
    try {
      session.beginTransaction();
      session.save(customer);
      session.getTransaction().commit();
      System.out.println("saved!");
    } catch (RuntimeException e) {
      session.getTransaction().rollback();
      e.printStackTrace();
    } finally {
      session.flush();
      session.close();
    }
  }

  public Customer findById(int id) {
    Session session = sessionFactory.openSession();
    Customer customer = session.load(Customer.class, id);
    System.out.println(customer);
    session.close();
    return customer;
  }

  public void showAll() {
    Session session = sessionFactory.openSession();
    List<Customer> list = session.createQuery("FROM Customer").list();
    for (Customer customer : list) {
      System.out.println(customer);
    }
    session.close();
  }

  public void update(Customer customer) {
    Session session = sessionFactory.openSession();
    try {
      session.beginTransaction();
      session.update(customer);
      session.getTransaction().commit();
      System.out.println("updated!");
    } catch (RuntimeException e) {
      session.getTransaction().rollback();
      e.printStackTrace();
    } finally {
      session.flush();
      session.close();
    }
  }

  public void delete(Customer customer) {
    Session session = sessionFactory.openSession();
    try {
      session.beginTransaction();
      session.delete(customer);
      session.getTransaction().commit();
      System.out.println("deteted!");
    } catch (RuntimeException e) {
      session.getTransaction().rollback();
      e.printStackTrace();
    } finally {
      session.flush();
      session.close();
    }
  }

}

File MainApp

package stackjava.com.hibernateversion;

import stackjava.com.hibernateversion.dao.CustomerDAO;
import stackjava.com.hibernateversion.entities.Customer;

public class MainApp {
  public static void main(String[] args) {
    demoInsert();
//		demoUpdate();
//		demoSearchByName();
//		demoDelete();
//		demoLocking();
    
  }
  
  public static void demoLocking() {
    CustomerDAO customerDAO = new CustomerDAO();
    Customer customer1 = customerDAO.findById(1);
    Customer customer2 = customerDAO.findById(1);
    
    customer1.setAddress("Nam Dinh");
    customerDAO.update(customer1);
    
    customer2.setAddress("Vinh Phuc");
//		customer2.setVersion(customer1.getVersion());
    customerDAO.update(customer2);
  }
  
  public static void demoUpdate() {
    CustomerDAO customerDAO = new CustomerDAO();
    Customer customer = customerDAO.findById(2);
    customer.setAddress("Titan");
    customerDAO.update(customer);
  }
  
  public static void demoInsert() {
    CustomerDAO customerDAO = new CustomerDAO();
    customerDAO.save(new Customer("Kai", "Viet Nam"));
    customerDAO.save(new Customer("Thanos", "Viet Nam"));
    customerDAO.save(new Customer("Thor", "Asgard"));
    customerDAO.save(new Customer("Hulk", "USA"));
    customerDAO.save(new Customer("Iron Man", "USA"));
  }
  
  public static void demoFindById() {
    CustomerDAO customerDAO = new CustomerDAO();
    customerDAO.findById(2);
  }
  
  public static void demoShowAll() {
    CustomerDAO customerDAO = new CustomerDAO();
    customerDAO.showAll();
  }
  
  public static void demoDelete() {
    CustomerDAO customerDAO = new CustomerDAO();
    Customer customer = customerDAO.findById(5);
    customerDAO.delete(customer);
  }
}

Demo:

Demo1: Thực hiện insert đối tượng customer vào database:

public static void demoInsert() {
  CustomerDAO customerDAO = new CustomerDAO();
  customerDAO.save(new Customer("Kai", "Viet Nam"));
  customerDAO.save(new Customer("Thanos", "Viet Nam"));
  customerDAO.save(new Customer("Thor", "Asgard"));
  customerDAO.save(new Customer("Hulk", "USA"));
  customerDAO.save(new Customer("Iron Man", "USA"));
}

Kết quả: version của các đối tượng mặc định khi insert là ‘0’

Thực hiện insert đối tượng customer vào database:

Demo 2: Update address của customer có id = 2

public static void demoUpdate() {
  CustomerDAO customerDAO = new CustomerDAO();
  Customer customer = customerDAO.findById(2);
  customer.setAddress("Titan");
  customerDAO.update(customer);
}

Kết quả: version của đối tượng tự động tăng lên 1 đơn vị

Demo 2: Update address của customer có id = 2

Demo 3: locking với version.

public static void demoLocking() {
  CustomerDAO customerDAO = new CustomerDAO();
  Customer customer1 = customerDAO.findById(1);
  Customer customer2 = customerDAO.findById(1);
  
  customer1.setAddress("Nam Dinh");
  customerDAO.update(customer1);
  
  customer2.setAddress("Vinh Phuc");
  customerDAO.update(customer2);
}

Nếu không sử dụng @Version thì đoạn code trên sẽ thực hiện như sau: lấy đối tượng customer có id = 1 và lưu vào 2 đối tượng customer1 và customer2. Hai đối tượng customer1 và customer2 sẽ thực hiện update độc lập và kết quả cuối cùng address sẽ là “Vinh Phuc”

Tuy nhiên khi áp dụng @Version, customer1 sau khi update address = “Nam Dinh” thì version của nó sẽ tăng lên một (column version trong database cũng tăng lên 1 đơn vị). Sau đó customer2 update address = “Vinh Phuc” nhưng field version của  customer2 vẫn bằng 0 (version cũ) khác với version hiện tại trong database nên nó sẽ xảy ra lỗi.

Kết quả:

Code ví dụ Hibernate annotation @Version (Hibernate Locking Version)

Code ví dụ Hibernate annotation @Version (Hibernate Locking Version)

Nếu không muốn xảy ra lỗi trong trường hợp trên thì khi customer2 thực hiện update nó cần lấy version mới nhất sau khi đối tượng customer1 thực hiện update.

customer2.setAddress("Vinh Phuc");
customer2.setVersion(customer1.getVersion());
customerDAO.update(customer2);

Code ví dụ Hibernate annotation @Version (Hibernate Locking Version) stackjava.com

Okay, Done!

Download code ví dụ trên tại đây.

 

References:

https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/chapters/locking/Locking.html

stackjava.com