JDBC学习(七)事务

什么是事务?

银行转账,张三给李四转100元,在数据库中需要2条sql语句:

  • 张三账户减去100
  • 李四账户添加100

银行转账这个步骤就是一个事务。事务中的多个操作,要么完全成功,要么完全失败。

事务的四大特性(ACID)

  • 原子性(Atomicity):事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。
  • 一致性(Consistency):事务执行后,数据库状态与其它业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账号余额之和应该是不变的。
  • 隔离性(Isolation):隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。
  • 持久性(Durability):一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。

MySQL中的事务

默认情况下,MySQL每执行一条语句都是一个单独的事务。如果一个事务包含多条语句,需要单独开启和结束

  • 开启事务:start transaction
  • 结束事务:commitrollback

JDBC中的事务

Connection的三个方法与事务相关:

  • setAutoCommit(boolean):设置是否为自动提交事务,如果true(默认值就是true)表示自动提交,也就是每条执行的SQL语句都是一个单独的事务,如果设置false,那么就相当于开启了事务了;con.setAutoCommit(false)表示开启事务!
  • commit():提交结束事务;con.commit();表示提交事务
  • rollback():回滚结束事务。con.rollback();表示回滚事务

jdbc处理事务的代码格式:

try {

  con.setAutoCommit(false);//开启事务…

  ….

  …

  con.commit();//try的最后提交事务

} catch() {

  con.rollback();//回滚事务

}

首先建立数据库 account

create table account(
	id int auto_increment,
	`name` varchar(30),
	balance FLOAT,
	PRIMARY key(id)
);

建立数据库操作类 :AccountDAO.java

public class AccountDAO {

    /**
     * 更新账户的金额
     * @param cn 连接对象
     * @param name 账户
     * @param balance 转入多少钱
     */
    public static void updateBalance(Connection cn, String name, float balance) throws SQLException {
        //设置sql模板
        String sql="update account set balance=balance+? where `name`=?";
        //得到PreparedStatement对象
        PreparedStatement ps=cn.prepareStatement(sql);
        //参加参数
        ps.setFloat(1,balance);
        ps.setString(2,name);
        //执行
        ps.executeUpdate();
    }
}

其中jdbcUtils类,可以参考JDBC学习(四)时间类型

添加测试类:test.java

public class test {

    /**
     * 从from转到to money元
     * @param from
     * @param to
     * @param money
     */
    private void account(String from,String to,Float money) {


        Connection cn=null;
        try{
            cn=jdbcUtils.getConnection();

            //开启事务
            cn.setAutoCommit(false);
            AccountDAO.updateBalance(cn,from,-money);//转出money
            AccountDAO.updateBalance(cn,to,money);//转入
            if(true){
                throw new RuntimeException();
            }
            cn.commit();//提交
        } catch (SQLException e) {
            try {
                cn.rollback();//回退
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }

    }

    @Test
    public void fun1() {
        account("zhangsan","lisi",100.0f);
    }

}

事务隔离级别

事务的并发读问题

  1. 脏读(dirty read):读到另一个事务的未提交更新数据,即读取到了脏数据;
  2. 不可重复读(unrepeatable read):对同一记录的两次读取不一致,因为另一事务对该记录做了修改;
  3. 幻读(虚读)(phantom read):对同一张表的两次查询不一致,因为另一事务插入了一条记录;

四大隔离级别

4个隔离级别,在相同的数据环境,使用相同的输入,执行相同的工作,根据不同的隔离级别,可以导致不同的结果。

1、SERIALIZABLE(串行化)

  • 不会发生任何并发问题,因为它对数据的访问是串行的。
  • 性能最差

2、REPEATABLE READ(可重复读)

  • 防止脏数据和不可重复读,不能处理幻读问题。
  • 性能比SERIALIZABLE好

3、READ COMMITTED(读已提交)

  • 防止脏数据,没有处理不可重复读和幻读
  • 性能比REPEATABLE READ好

4、READ UNCOMMITTED(读未提交)

  • 可能出现任何事务并发问题
  • 性能最好

其中MySQL默认隔离级别:REPEATABLE READ;oracle默认READ COMMITTED

MySQL查看隔离级别语句

8.0以前是 select @@tx_isolation

8.0以后:select @@transaction_isolation

JDBC设置隔离级别

Connection.setTransactionIsolation(int level)

参数可选值:

  • Connection.TRANSACTION_READ_UNCOMMITTED;
  • Connection.TRANSACTION_READ_COMMITTED;
  • Connection.TRANSACTION_REPEATABLE_READ;
  • Connection.TRANSACTION_SERIALIZABLE

猜你喜欢

转载自blog.csdn.net/SICAUliuy/article/details/88803273