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 maven project
<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’
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 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ả:
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