MyBatis 的事务回滚例子

事务的概念及其特性

事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元。

原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。

一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

MyBatis 的事务回滚例子

注意:在 MyBatis 中,每一个 SqlSession(SQL 会话)都对应一个 Transaction(事务):

在这里插入图片描述

/**
 * <p> 从数据源中打开一个会话
 * @param execType 执行类型
 * @param level 事务隔离级别
 * @param autoCommit 自动提交
 * @return SqlSession(SQL 会话)
 */
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level,
        boolean autoCommit) {
    // 事务。一个 SqlSession 对应一个事务
    Transaction tx = null;
    try {
        // 获取环境参数,即 MyBatis 配置文件中定义的环境
        final Environment environment = configuration.getEnvironment();
        // 从环境中获取事务工厂
        final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
        // 从事务工厂中获取事务
      	// 在 MyBatis 中有两种类型的事务管理器:JDBC 和 MANAGED
      	// JDBC – 这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
      	// MANAGED – 这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。
      	// 参考:https://mybatis.org/mybatis-3/zh/configuration.html#environments
        tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        // 执行器
        final Executor executor = configuration.newExecutor(tx, execType);
        // 返回 SqlSession
        return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
        closeTransaction(tx); // may have fetched a connection so lets call close()
        throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}

一个操作异常,事务回滚的例子:

package com.mk;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.log4j.Logger;

import com.mk.pojo.Flower;

public class Application {
    private static final Logger logger = Logger.getLogger(Application.class);

    public static void main(String[] args) {
        InputStream is = null;
        try {
            is = Resources.getResourceAsStream("mybatis.xml");
            System.out.println(is);
        } catch (IOException e) {
            logger.error("Exception: ", e);
        }
        
        if (is != null) {
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); // 获取 SQL 会话工厂
            SqlSession session = factory.openSession(); // 获取 SQL 会话
            
            // 待插入数据 1
            String name = "火龙果";
            BigDecimal price = new BigDecimal("999.99");
            String production = "中美洲";
            Flower f1 = new Flower(null, name, price, production);
            
            // 待插入数据 2
            name = "葡萄";
            price = new BigDecimal("1000"); // 价格不满足表中字段类型要求,将导致错误发生
            production = "亚洲西部";
            Flower f2 = new Flower(null, name, price, production); 
            
            // 新增
            Integer result = 0;
            try {
                result += session.insert("com.mk.mapper.FlowerMapper.insert", f1);
                result += session.insert("com.mk.mapper.FlowerMapper.insert", f2);
            } catch (Exception e) {
                logger.error("Exception: ", e);
                session.rollback(); // 回滚
                result = 0;
            } finally {
                session.commit(); // 提交
                session.close(); // 关闭会话
                try {
                    if (is != null) {
                        is.close();
                    }
                } catch (IOException e) {
                    logger.error("Exception: ", e);
                }
            }
            
            System.out.println("执行结果:" + result);
        }
    }
}

控制台输出:

java.io.BufferedInputStream@2f4d3709
16:48:05:688 [main] DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger 143 - ==>  Preparing: insert into t_flower values(default, ?, ?, ?) 
16:48:05:716 [main] DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger 143 - ==> Parameters: 火龙果(String), 999.99(BigDecimal), 中美洲(String)
16:48:05:721 [main] DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger 143 - <==    Updates: 1
16:48:05:721 [main] DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger 143 - ==>  Preparing: insert into t_flower values(default, ?, ?, ?) 
16:48:05:722 [main] DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger 143 - ==> Parameters: 葡萄(String), 1000(BigDecimal), 亚洲西部(String)
16:48:05:729 [main] ERROR com.mk.Application 49 - Exception: 
org.apache.ibatis.exceptions.PersistenceException: 
### Error updating database.  Cause: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Out of range value for column 'price' at row 1
### The error may exist in com/mk/mapper/FlowerMapper.java (best guess)
### The error may involve com.mk.mapper.FlowerMapper.insert-Inline
### The error occurred while setting parameters
### SQL: insert into t_flower values(default, ?, ?, ?)
### Cause: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Out of range value for column 'price' at row 1
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:199)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:184)
	at com.mk.Application.main(Application.java:47)
执行结果:0

数据库中表的记录:

mysql> select * from t_flower;
+----+--------+-------+------------+
| id | name   | price | production |
+----+--------+-------+------------+
|  1 | 矮牵牛 |  2.50 | 南美阿根廷 |
|  2 | 百日草 |  5.00 | 墨西哥     |
|  3 | 半枝莲 |  4.30 | 巴西       |
+----+--------+-------+------------+
3 rows in set (0.00 sec)

因为一个事务中的某些操作失败,导致事务回滚,所以最终不会影响到数据库的数据。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值