欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

事务

程序员文章站 2022-05-12 21:29:34
...

事务

什么是事务?

将 n 个组成单元放到一个事务中,要不这 n 个组成单元同时成功,要不就同时失败。一般是指数据库操作。

mysql事务

默认事务: 一条 sql 语句就是一个事务默认就 开启事务提交事务

手动事务:

​ 1、显示的开启一个事务:start transaction 。

​ 2、事务提交:commit代表从开启事务到事务提交 中间的所有的sql都认为有效真正的更新数据库。

​ 3、事务的回滚:rollback 代表事务的回滚 从开启事务到事务回滚中间的所有的 sql 操作都认为无效数据库没有被更新。

JDBC事务操作

//通过 jdbc 去控制事务

try{
    //注册驱动
    Class.forname("com.mysql.jdbc.Driver");
    //获得connection
    Connention conn = Drivermanager.getConnention("jdbc://mysql:///web","root","root");

    //手动开启事务
    conn.setAutoCommit(false);

    //获得执行平台
    Statement stmt = conn.creatStatement();
    //操作sql
    int executeUpdate = stmt.executeUpdate("insert into account values(null,'zhangsan',3000)");

    //提交事务
    conn.commit();
}catch(Exception){
    //如果是失败,就要事务回滚
    conn.rollback();
}

stmt.close();
conn.close();

通过jdbc的API手动事务:

开启事务:conn.setAutoComnmit(false);

提交事务:conn.commit();

回滚事务:conn.rollback();

注意:控制事务的connnection必须是同一个!!!!!!

执行sql的connection与开启事务的connnection必须是同一个才能对事务进行控制。

DBUtils事务操作

Connention conn = null;
try{
    //QueryRunner的构造方法要么传一个连接池,要么就制定一个connection
    QueryRunner runner = new QueryRunner();
    //获得一个connection
    conn.DataSourceUtils.getConnection();
    //开启事务
    conn.setAutoCommit(false);
    
    runner.update(conn,"update account set money=1000 where name='Tom');
    //提交或回滚
     conn.commit();
}catch(SQLExeption){ 
	conn.rollback();
}

**无参构造: **QueryRunner runner = new QueryRunner();

无参的构造没有将数据源(连接池)作为参数传入QueryRunner,那么我们在使 用QueryRunner对象操作数据库时要使用有Connection参数的方法。

使用 ThreadLocal 绑定连接资源

TransferService 包:

//开启事务
MyDataSourceUtils.startTranscation();

MyDataSourceUtils 工具类:

//获取Connection————从连接池获取
private ComboPooledDataSource datasource = new ComboPooledDataSource();

//创建ThreadLocal
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();

//开启事务
public static void startTransaction() throws SQLExeption{
    Connection conn = getCurrentConnection();
    conn.setAutoCommit(false);
}

//回滚事务
public static void rollback(){
    getCurrentConnection().rollback();
}

//提交事务
public static void commit(){
    getCurrentConnection().commit();
    //将Connection从ThreadLocal中移除
    tl.remove();
    getCurrentConnection().close();
}

//获得当前线程上绑定的conn
public static Connection getCurrentConnection() throws SQLExeption{
    //从ThreadLocal中寻找当前线程是否有对应Connection
    Connection conn = tl.getConnection();
    if(conn==null){
        //获得新的Connection
        conn = getConnection();
        //将新的资源绑定到ThreadLocal上
        tl.set(conn);
    }
    return conn;
}

public static Connection getConnection() throws SQLExeption{
    return datasource.getConnection();
}

这样做的目的在于解耦和!!!!不要让 service 包中出现 conn。

事务的特性和隔离级别(概念性问题)

事务的特性 ACID

原子性(Atomicity)

原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

一致性(Consistency)

一个事务中,事务前后数据的完整性必须保持一致。

隔离性(Isolation)

多个事务,事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。

持久性(Durability)

持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

并发访问问题----由隔离性引起

脏读

B事务读取到了A事务尚未提交的数据   ------ 要求B事务要读取A事务提交的数据。

不可重复读

一个事务中两次读取的数据的内容不一致  ----- 要求的是一个事务中多次读取时数据是一致的  — unpdate

幻读 / 虚读

一个事务中两次读取的数据的数量不一致  ----- 要求在一个事务多次读取的数据的数量是一致的 --insert  delete

事务的隔离级别

1)read uncommitted : 读取尚未提交的数据 :哪个问题都不能解决

2)read committed:读取已经提交的数据 :可以解决脏读 ---- oracle默认的

3)repeatable read:重读读取:可以解决脏读 和 不可重复读 —mysql默认的

4)serializable:串行化:可以解决 脏读 不可重复读 和 虚读 —相当于锁表

总结

mysql的事务控制:

开启事务:start transaction;

提交:commit;

回滚:rollback;

JDBC事务控制:

开启事务:conn.setAutoCommit(false);

提交:conn.commit();

回滚:conn.rollback();

DBUtils的事务控制 也是通过 jdbc

ThreadLocal

实现的是通过线程绑定的方式传递参数。

概念

并发问题:脏读、不可重读、虚读\幻读

解决并发:设置隔离级别

read uncommitted

read committed

repeatable read (mysql默认)

serialazable

隔离级别的性能:

read uncommitted>read committed>repeatable read>serialazable

安全性:

read uncommitted<read committed<repeatable read<serialazable