0
点赞
收藏
分享

微信扫一扫

事务

书呆鱼 2021-09-21 阅读 68

事务

事务是以一种可靠、一致的方式、访问和操作数据库中数据的程序单元。

事务的4大特性ACID

  • 原子性
    事务中的多个操作要么都完成,要不都不完成,不会只完成其中的一部分
  • 一致性
    事务执行之后,状态改变是一致的或者说结果是完整的。
  • 隔离性
    当前事务的操作对于其他事务是否可见
  • 持久性
    事务提交之后,操作的结果会进入数据库被永久保存。如果事务没有提交,出现数据库宕机,数据不会被保存到数据库中。
eg: 张三给李四转100元钱


原子性:转钱成功后,张三的账户一定是扣掉了100元,李四的账户一定是增加了100元,不会出现单方面账户变化。
一致性:转账成功后,张三的账户扣掉的一定是100元,李四的账户一定是增加了100元,不会出现张三的账户被扣了120元而李四的账户增加了80。
隔离性:张三给李四转账执行的时候的中间状态是否对李四可见,比如张三的账户被扣了100元后,李四的账户还没有加100元这个中间状态是否对李四可见。
持久性:转账成功后(事务提交后)数据被永久存储在数据库中,不会出现数据丢失的情况。

用SQL实现事务
  1. 创建数据库和表数据
create database test;
use test;
create table t_user(id int PRIMARY key auto_increment,username varchar(32),amount int);
insert t_user(username,amount) values('张三',500),('李四',500);

  1. 转账事务
START TRANSACTION; 
UPDATE t_user SET amount = amount - 100 WHERE username = '张三';
UPDATE t_user SET amount = amount + 100 WHERE username = '李四';
COMMIT;

mysql 的默认隔离级别是可重复读,事务执行的任何中间状态都不会被其他事务看到,也就是说,在转账事务执行的时候,如果另一个事务进行查询操作,查到的账户余额都是事务开始时的余额即,张三,500;李四,500。

使用JDBC实现事务

public class LocalJdbcTransaction {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        Connection connection = getConnection();
        //关闭自动提交,相当于开启事务
        connection.setAutoCommit(false);

        String plusSQL = "UPDATE t_user SET amount = amount + 100 WHERE username = ?";
        PreparedStatement plusPS = connection.prepareStatement(plusSQL);
        plusPS.setString(1, "张三");
        plusPS.execute();

        String minusSQL = "UPDATE t_user SET amount = amount - 100 WHERE username = ?";
        PreparedStatement minusPS = connection.prepareStatement(minusSQL);
        minusPS.setString(1, "李四");
        minusPS.execute();
        
        plusPS.close();
        minusPS.close();
        //提交事务
        connection.commit();
    }

    /**
     * 获取数据库连接
     *
     * @return Connection
     * @throws SQLException           SQLException
     * @throws ClassNotFoundException ClassNotFoundException
     */
    private static Connection getConnection() throws SQLException, ClassNotFoundException {
        String driver = "com.mysql.cj.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF8&autoReconnect=true&serverTimezone=UTC";
        String username = "root";
        String password = "******";
        Class.forName(driver);
        return DriverManager.getConnection(url, username, password);
    }
}

[具体实现]

    public void test() throws SQLException, ClassNotFoundException {
        Connection connection = getConnection();
        //关闭自动提交,相当于开启事务
        connection.setAutoCommit(false);
        String selectSQL = "SELECT * from t_user where username = ? for update";
        PreparedStatement selectQuery;
        selectQuery = connection.prepareStatement(selectSQL);
        selectQuery.setString(1,"李四");
        ResultSet resultSet = selectQuery.executeQuery();
        Long amount = null;
        while (resultSet.next()){
            String username = resultSet.getString(2);
            amount = resultSet.getLong(3);
            System.out.println(username+"==>"+amount);
        }
        String minusSQL = "UPDATE t_user SET amount = ? + 100 WHERE username = ?";
        PreparedStatement minusPS = connection.prepareStatement(minusSQL);
        minusPS.setLong(1,amount);
        minusPS.setString(2, "李四");
        minusPS.execute();
        minusPS.close();
        //提交事务
        connection.commit();
    }

Spring 事务

Spring事务抽象

  • PlatFormTransactionManager
    事务管理器的接口;包括事务开启,提交,回滚等操作
public interface PlatformTransactionManager {
    TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
            throws TransactionException;
    void commit(TransactionStatus status) throws TransactionException;
    void rollback(TransactionStatus status) throws TransactionException;
}
  • TransactionDefinition
    事务的定义,可以通过该接口定义事务的属性,例如:传播属性,隔离属性
public interface TransactionDefinition {

    int PROPAGATION_REQUIRED = 0;

    int PROPAGATION_SUPPORTS = 1;

    int PROPAGATION_MANDATORY = 2;

    int PROPAGATION_REQUIRES_NEW = 3;

    int PROPAGATION_NOT_SUPPORTED = 4;

    int PROPAGATION_NEVER = 5;

    int PROPAGATION_NESTED = 6;

    int ISOLATION_DEFAULT = -1;

    int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;

    int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;

    int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;

    int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;

    int TIMEOUT_DEFAULT = -1;

    int getPropagationBehavior();

    int getIsolationLevel();

    int getTimeout();

    boolean isReadOnly();

    @Nullable
    String getName();

}
  • TransactionStatus
    相当于事务运行过程中的句柄。
public interface TransactionStatus extends SavepointManager, Flushable {

    boolean isNewTransaction();

    boolean hasSavepoint();

    void setRollbackOnly();

    boolean isRollbackOnly();

    @Override
    void flush();

    boolean isCompleted();
}
编程形式使用Spring事务
@Service
public class OrderService {
    @Resource
    private PlatformTransactionManager txManager;
    
    void buyTicket(){
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = txManager.getTransaction(def);
        try {
            // todo 执行业务代码
            txManager.commit(status);
        }catch (Exception e){
            txManager.rollback(status);
        }
    }
}

声明式事务管理
方法体上加@Transactional

举报

相关推荐

0 条评论