Spring Hibernate – Transaction trong Spring Hibernate. Code ví dụ Spring Hibernate Transaction.

Spring Hibernate – Transaction trong Spring Hibernate. Code ví dụ Spring Hibernate Transaction.

Ở phần trước chúng ta đã tìm hiểu về Spring ORM và code ví dụ với Spring Hibernate

Ở phần này chúng ta sẽ thực hiện quản lý trasaction của các truy vấn thông qua hibernate.

1. Transaction trong Spring Hibernate

(Xem lại Transaction là gì? Code ví dụ transaction với JDBC)

Để thực hiện quản lý hibernate bởi transactionManager ta khai báo trong file spring config:

<!-- Transaction config -->
<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager"
  class="org.springframework.orm.hibernate5.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory" />
</bean>

Ở trong file DAO, để bật chức năng quản lý transaction ta dùng annotation: @Transactional(rollbackFor = Exception.class)

  • Nếu đặt @Transaction ở đầu class thì tất cả các method trong class đó đều nằm trong 1 transaction.
  • Nếu đặt @Transaction ở đầu method thì chỉ các method đó được nằm trong 1 transaction.
  • rollbackFor = Exception.class: Chỉ rõ khi xảy ra exception nào thì rollback, thông thường chỉ các exception khi truy vấn mới bị rollback như SQLException… Ở đây mình để rollbackFor = Exception.class tức là khi xảy exception bất kì thì đều rollback lại.
  • Những method được nằm trong 1 transaction thì chúng ta sẽ gọi sessionFactory.getCurrentSession() để lấy sesion chứ không gọi sessionFactory.openSession().

3. Code ví dụ

Ở ví dụ này mình sử dụng:

Tạo database:

CREATE SCHEMA `demo-spring-hibernate` ;
CREATE TABLE `demo-spring-hibernate`.`customer` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(45) NULL,
  `address` VARCHAR(255) NULL,
  PRIMARY KEY (`id`));

Spring Hibernate - Giới thiệu Spring ORM, Code ví dụ Spring Hibernate

Tạo maven project:

Spring Hibernate - Giới thiệu Spring ORM, Code ví dụ Spring Hibernate

Thư viện sử dụng:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>stackjava.com</groupId>
  <artifactId>DemoJDBC</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <dependencies>
    <!-- Spring -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>

    <!-- Hibernate -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>5.2.12.Final</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>5.2.12.Final</version>
    </dependency>
    <dependency>
      <groupId>commons-dbcp</groupId>
      <artifactId>commons-dbcp</artifactId>
      <version>1.4</version>
    </dependency>

    <!-- MySQL -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.45</version>
    </dependency>

  </dependencies>
</project>

File Spring config:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

  <context:annotation-config />
  <context:component-scan base-package="stackjava.com.springhibernate" />
  

  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url"
      value="jdbc:mysql://localhost:3306/demo-spring-hibernate" />
    <property name="username" value="root" />
    <property name="password" value="admin1234" />
  </bean>
  
  <!-- Transaction config -->
  <tx:annotation-driven transaction-manager="transactionManager" />
  
  <bean id="transactionManager"
    class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
  </bean>

  
  <bean id="sessionFactory"
    class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"></property>
    <property name="packagesToScan" value="stackjava.com.springhibernate.entities" />
    <property name="hibernateProperties" value="classpath:hibernate.properties" />
  </bean>

</beans>
  • org.apache.commons.dbcp.BasicDataSourcechứa các thông tin kết nối tới database
  • org.springframework.orm.hibernate5.LocalSessionFactoryBean: tạo đối tượng sessionFactory.
    • Thuộc tính packagesToScan sẽ chỉ định package chứa các file entity map với table trong database (hoặc bạn cũng có thể chỉ rõ các class entity mapping với table bằng thuộc tính annotatedClasses)
    • Thuộc tính hibernateProperties khai báo file chưa các thông tin config hibernate (hoặc bạn cũng có thể chỉ rõ các thông tin config trong file spring config luôn).
  • <tx:annotation-driven transaction-manager=”transactionManager” />: bật transactionMangement
  • bean transactionManager sẽ quản lý transaction cho những truy vấn thông qua sessionFactory

 File Hibernate config:

hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.hibernate.current_session_context_class=thread
hibernate.show_sql=true

File entity:

package stackjava.com.springhibernate.entities;

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

@Entity
@Table(name = "customer")
public class Customer {
  @Id
  @Column(name = "id")
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private int id;

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

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

  public Customer() {
  }

  public Customer(int id, String name, String address) {
    this.id = id;
    this.name = name;
    this.address = address;
  }

  public Customer(String name, String address) {
    this.name = name;
    this.address = address;
  }

  public int getId() {
    return id;
  }

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

  public String getName() {
    return name;
  }

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

  public String getAddress() {
    return address;
  }

  public void setAddress(String address) {
    this.address = address;
  }

}

File DAO:

package stackjava.com.springhibernate.dao;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import stackjava.com.springhibernate.entities.Customer;

@Repository(value = "customerDAO")
@Transactional(rollbackFor = Exception.class)
public class CustomerDAO {
  
  @Autowired
  private SessionFactory sessionFactory;


  public void test(Customer customer) throws Exception {
    this.save(customer);
    this.demoException();
  }
  
  public void save(Customer customer) {
    Session session = this.sessionFactory.getCurrentSession();
    session.save(customer);
    System.out.println("save done!");
  }
  
  public void demoException() throws Exception {
    // do something
    throw new Exception("demo throw exception");
  }

}
  • @Transactional(rollbackFor = Exception.class): Annotation @Transaction để ở đầu method nên tất cả các method của class CustomerDAO đều nằm trong transaction,
  • rollbackFor = Exception.class tức là rollback khi xảy ra bất kì exception nào.

Demo:

package stackjava.com.springhibernate.main;

import org.springframework.context.support.ClassPathXmlApplicationContext;

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

public class MainApp {
  public static void main(String[] args) throws Exception {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    CustomerDAO customerDAO = (CustomerDAO) context.getBean("customerDAO");
    
    Customer customer = new Customer("Rooney", "Manchester");
    customerDAO.test(customer);
    context.close();
  }
}

Kết quả:

Spring Hibernate - Transaction trong Spring Hibernate. Code ví dụ Spring Hibernate Transaction.

Hành động insert thành công nhưng sau đấy xảy ra lỗi nên dữ liệu sẽ bị rollback lại, không được save vào database nữa:

Spring Hibernate – Transaction trong Spring Hibernate. Code ví dụ Spring Hibernate Transaction.

Okay, Done!

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

stackjava.com