Spring 事务系列 - 编程式事务

什么是事务?

数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。

事务应该具有4个属性:原子性、一致性、隔离性、持久性,这四个属性通常称为ACID特性。
* 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
* 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
* 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
* 持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。

事务的隔离级别

在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别。我们的数据库锁,也是为了构建这些隔离级别存在的。

隔离级别 脏读(Dirty Read) 不可重复读(NonRepeatable Read) 幻读(Phantom Read)
读未提交(Read uncommitted) 可能 可能 可能
读已提交(Read committed) 不可能 可能 可能
可重复读(Repeatable read) 不可能 不可能 可能
可串行化(Serializable ) 不可能 不可能 不可能

说明:
* 读未提交(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据
* 读已提交(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)
* 可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读
* 串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞

Read Uncommitted这种级别,数据库一般都不会用,而且任何操作都不会加锁,这里就不讨论了。MySQL默认的事务隔离级别为可重复读(Repeated Read)。

一、编程式事务

在 Spring 出现以前,编程式事务管理对开发者来说是唯一选择。熟悉Java JDBC 的人都知道,我们需要在代码中显式调用Connection 的setAutoCommit()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。

1、JDBC 的编程式事务管理

public void save(User user) throws SQLException{
    Connection conn = datasource.getConnection();
    conn.setAutoCommit(false);
    try {
        PreparedStatement ps = conn.prepareStatement("insert into user(name,age) value(?,?)");
        ps.setString(1,user.getName());
        ps.setInt(2,user.getAge());
        ps.execute();
        conn.commit();
    } catch (Exception e) {
        e.printStackTrace();
        conn.rollback();
    }finally{
        conn.close();
    }
}

2、Hibernate 的编程式事务管理

Hibernate 中需要显式调用beginTransaction()、commit()、rollback()等事务管理相关的方法,如下:

public void save(User user){
    Session session = hibernateDao.openSession();
    Transaction tx = null;
    try {
        tx = session.beginTransaction();  
        session.save(user);  
        tx.commit();  
    } catch (Exception e) {
        if(tx!=null){
            tx.rollback();
        }
    }finally{
        session.close();
    }
}

3、MyBatis 的编程式事务管理

MyBatis中,我们可以通过org.apache.ibatis.session.SqlSession 的commit()、rollback() 等事务管理相关的方法,代码如下:

    String resource = "org/mybatis/example/mybatis-config.xml";
    InputStream in = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);

    SqlSession session = sqlSessionFactory.openSession(false); // 打开会话,事务开始  
    try {  
        IUserMapper mapper = session.getMapper(IUserMapper.class);  
        User user = new User(9, "Test transaction");  
        int affectedCount = mapper.updateUser(user); // 因后面的异常而未执行commit语句  
        User user = new User(10, "Test transaction continuously");  
        int affectedCount2 = mapper.updateUser(user2); // 因后面的异常而未执行commit语句  
        int i = 2 / 0; // 触发运行时异常  
        session.commit(); // 提交会话,即事务提交  
    } catch (Exception e) {
        session.rollback(); //回滚
    } finally {  
        session.close(); // 关闭会话,释放资源  
    }  

参考资料

分布式事务系列(1.2)Spring的事务体系:https://yq.aliyun.com/articles/39046?spm=5176.100239.blogcont39044.27.mmXvhw

发布了486 篇原创文章 · 获赞 405 · 访问量 296万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章