STACKJAVA

Spring JDBC – Transaction trong Spring JDBC, Code ví dụ Spring JDBC Transaction

Spring JDBC – Transaction trong Spring JDBC, Code ví dụ Spring JDBC Transaction

1. Transaction là gì?

Transaction là 1 giao dịch (hay còn gọi là 1 giao tác) bao gồm 1 loạt các hành động được phải được thực hiện thành công cùng nhau, nếu 1 hành động thất bại thì tất cả các hành động trong loạt hành động đó sẽ trở về trạng thái ban đầu.

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

2. Code ví dụ Spring JDBC Transaction

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

Tạo database ‘demo-spring-jdbc-transaction’

CREATE SCHEMA `demo-spring-jdbc-transaction` ;

Tạo table ‘user_info’

CREATE TABLE `demo-spring-jdbc-transaction`.`user_info` (
  `id` INT NOT NULL,
  `name` VARCHAR(45) NULL,
  `address` VARCHAR(255) NULL,
  PRIMARY KEY (`id`));

Code ví dụ:

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>SpringJDBC</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.45</version>
    </dependency>
  </dependencies>
</project>

Thư viện spring-tx cung cấp khả năng quản lý transaction bằng annotation. (ví dụ bạn đánh dấu 1 method là @Transactional thì tức là method đó đã được đặt trong 1 transaction)

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"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

  <bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/demo-spring-jdbc-transaction" />
    <property name="username" value="root" />
    <property name="password" value="admin1234" />
  </bean>

  <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
  </bean>

  <!-- Enable Annotation based Declarative Transaction Management -->
  <tx:annotation-driven proxy-target-class="true"
    transaction-manager="transactionManager" />

  <!-- Creating TransactionManager Bean, since JDBC we are creating of type 
    DataSourceTransactionManager -->
  <bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
  </bean>

  <bean id="userDAO"
    class="stackjava.com.springjdbc.dao.UserDAO">
    <property name="jdbcTemplate" ref="jdbcTemplate" />
  </bean>

</beans>

File entity:

package stackjava.com.springjdbc.entities;

public class User {
  private int id;
  private String name;
  private String address;

  public User() {
  }

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

  @Override
  public String toString() {
    return "User [id=" + id + ", name=" + name + ", address=" + address + "]";
  }

  // getter - setter

}

File DAO:

package stackjava.com.springjdbc.dao;

import java.util.List;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;

import stackjava.com.springjdbc.entities.User;

public class UserDAO {
  
  private JdbcTemplate jdbcTemplate;

  @Transactional
  public void insert(List<User> listUser) {
    String sql = "INSERT INTO user_info (id, name, address) VALUES (?, ?, ?);";
    for (User user: listUser) {
      jdbcTemplate.update(sql, user.getId(), user.getName(), user.getAddress());
      System.out.println("Inserted user: " + user.getId() +" - " +user.getName());
    }
  }

  public void insertWithoutTransaction(List<User> listUser) {
    String sql = "INSERT INTO user_info (id, name, address) VALUES (?, ?, ?);";
    for (User user: listUser) {
      jdbcTemplate.update(sql, user.getId(), user.getName(), user.getAddress());
      System.out.println("Inserted user: " + user.getId() +" - " +user.getName());
    }
  }

  public JdbcTemplate getJdbcTemplate() {
    return jdbcTemplate;
  }

  public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
    this.jdbcTemplate = jdbcTemplate;
  }
  
}

Demo:

package stackjava.com.springjdbc.mainapp;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import stackjava.com.springjdbc.dao.UserDAO;
import stackjava.com.springjdbc.entities.User;

public class Demo {
  public static void main(String[] args) throws SQLException {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserDAO userDAO = (UserDAO) ctx.getBean("userDAO");
    List<User> listUser = new ArrayList<User> ();
    listUser.add(new User(1, "Nicolas Cage", "USA"));
    listUser.add(new User(2, "Abramovic", "Russia"));
    listUser.add(new User(1, "Thor", "Asgard"));
    userDAO.insert(listUser);
//		userDAO.insertWithoutTransaction(listUser);
    
    ((ClassPathXmlApplicationContext) ctx).close();
    System.out.println("Done!");
  }
}

Kết quả:

User thứ nhất và thứ hai insert bình thường nhưng user thứ ba insert thất bại ví nó có id trùng với user thứ nhất.

Do method insert của UserDAO được đánh dấu @Transactional nên cả 2 user đầu tiên sẽ bị rollback lại không được save vào database.

Bây giờ bạn dùng method insertWithoutTransaction thay vì method insert.

Kết quả:

Cũng xảy ra lỗi khi insert user thứ ba nhưng 2 user đầu không bị rollback lại:

 

Okay, Done!

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

Spring JDBC – Transaction trong Spring JDBC, Code ví dụ Spring JDBC Transaction

References:

https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html

https://spring.io/guides/gs/managing-transactions/