Introduction to programmatic transaction usage postures for SpringBoot series tutorials

Introduction to programmatic transaction usage postures for SpringBoot series tutorials

The blog posts on the aforementioned transactions mainly make use of the declarative posture of the @Transactional annotation, which has the advantages of simple use, low intrusiveness and high identifiability (you know you are using the transaction at a glance); however, the drawbacks are obvious, not flexible enough, and not paying attention to it, probably because of the incorrect posture, the transaction will not take effect

This article introduces another transaction usage posture, programmatic transaction with TransactionTemplate

<!-- more -->

I. Configuration

This article focuses on an example demo of jdbcTemplate+transactionTemplate to complete a programmatic transaction

Create a SpringBoot project, version 2.2.1.RELEASE, use mysql as the target database, store engine select Innodb, transaction isolation level RR

1. Project Configuration

In the project pom.xml file, plus spring-boot-starter-jdbc, a DataSourceTransactionManager bean is injected, providing transaction support

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

2. Database Configuration

Go to the spring configuration file application.properties to set up db-related information

## DataSource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=

3. Database

Create a new simple table structure for testing

CREATE TABLE `money` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '' COMMENT 'User name',
  `money` int(26) NOT NULL DEFAULT '0' COMMENT 'money',
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0',
  `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Time',
  `update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update Time',
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=551 DEFAULT CHARSET=utf8mb4;

II. Instructions for use

1. Initialization

Create several pieces of data for transactional operations

@Service
public class ManualDemo {
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @PostConstruct
    public void init() {
        String sql = "replace into money (id, name, money) values (220, 'Initialization', 200)";
        jdbcTemplate.execute(sql);
    }
}

2. Use case

To demonstrate the nature of transactions, we design a few simple sql operations and throw exceptions that cause a rollback, as follows

  • In the doUpdate method, display the update name, output the result of the update, update the money value, and throw an exception expecting the transaction to roll back
private boolean doUpdate(int id) throws Exception {
    if (this.updateName(id)) {
        this.query("after updateMoney name", id);
        if (this.updateMoney(id)) {
            return true;
        }
    }

    throw new Exception("Parameter Exception");
}


private boolean updateName(int id) {
    String sql = "update money set `name`='To update' where id=" + id;
    jdbcTemplate.execute(sql);
    return true;
}

public void query(String tag, int id) {
    String sql = "select * from money where id=" + id;
    Map map = jdbcTemplate.queryForMap(sql);
    System.out.println(tag + " >>>> " + map);
}

private boolean updateMoney(int id) {
    String sql = "update money set `money`= `money` + 10 where id=" + id;
    jdbcTemplate.execute(sql);
    return false;
}

This logic is familiar if you look at the previous blog posts, except that the doUpdate method does not have the @Transactional annotation added to it, and its calls will not be executed in the transaction at this time

Next, let's look at the core writing of programmatic transactions

public void testTransaction(int id) {
    transactionTemplate.execute(new TransactionCallback<Boolean>() {
        @Override
        public Boolean doInTransaction(TransactionStatus transactionStatus) {
            try {
                return doUpdate(id);
            } catch (Exception e) {
                transactionStatus.setRollbackOnly();
                return false;
            }
        }
    });
}

As above, encapsulate method calls in transactionTemplate.execute calls, marking rollback by setting transactionStatus.setRollbackOnly()

From the previous blog posts, we know that in real use, the isolation level of transactions and the transfer of attributes are also important. In programmatic transactions, of course, they can be set

// Set isolation level
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
// Setting propagation properties
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

Finally, write a test code to verify that it works

@Component
public class TransactionalSample {
    @Autowired
    private ManualDemo manualDemo;

    public void testManualCase() {
        System.out.println("======= Programmatic Transactions start ========== ");
        manualDemo.query("transaction before", 220);
        manualDemo.testTransaction(220);
        manualDemo.query("transaction end", 220);
        System.out.println("======= Programmatic Transactions end ========== ");
    }
}

The output is as follows, and the final data big has not been modified

======= Programmatic Transactions start ==========
transaction before >>>> {id=220, name=Initialization, money=200, is_deleted=false, create_at=2020-02-03 13:52:39.0, update_at=2020-02-03 13:52:39.0}
after updateMoney name >>>> {id=220, name=To update, money=200, is_deleted=false, create_at=2020-02-03 13:52:39.0, update_at=2020-02-03 13:52:39.0}
transaction end >>>> {id=220, name=Initialization, money=200, is_deleted=false, create_at=2020-02-03 13:52:39.0, update_at=2020-02-03 13:52:39.0}
======= Programmatic Transactions end ==========

III. Other

0.Series Blog & Source

Series Blog

Source code

1.A grey Blog

Unlike letters, the above are purely family statements. Due to limited personal abilities, there are unavoidable omissions and errors. If bug s are found or there are better suggestions, you are welcome to criticize and correct them with gratitude.

Below is a grey personal blog, which records all the blogs in study and work. Welcome to visit it

Keywords: Programming SpringBoot Spring SQL MySQL

Added by Syphon on Wed, 05 Feb 2020 03:57:57 +0200