Java基础之JDBC之事务

演示 无事务引出错误

先说事务,就先创建一个错误,毕竟事务是为了解决这个问题。

#创建一个表
CREATE TABLE t_count(

ucount  INT,
uname VARCHAR(10),
umoney DECIMAL(10,2)
);
# 插入数据 
INSERT INTO t_count VALUES ('1001','张三',3000);
INSERT INTO t_count VALUES ('1002','李四',2000);

现在看表的数据:

在这里插入图片描述

估计创建一个错误。

// 银河 将张三的钱 1000转如李四账户
public static void test_shiwu(){

        Connection con=null;
        Statement stm=null;
        try {
            con=getCon();
            stm=con.createStatement();
            String sql="UPDATE test.t_count  SET umoney = umoney-1000   WHERE uname = '张三'";
            stm.execute(sql);
            //故意创建一个错误
            System.out.println(1/0);
            sql="UPDATE test.t_count  SET umoney = umoney+1000   WHERE uname = '李四'";
            stm.execute(sql);


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {

                stm.close();
                con.close();
            }catch (Exception e ){

            }

        }
    }

因为java运行错了,但是不看java的错误,而是看myql表中的数据:

在这里插入图片描述

要是银行出现这样事情,还不会被骂死,所以为了解决这样的问题,数据库就引入了事务这个概念。

事务

数据库事务介绍

  • 事务:一组逻辑操作单元,使数据从一种状态变换到另一个状态。

  • 事务处理(事务操作):保证所有事务都作为一个工作单元来执行,即使除了故障,都不能改编这种执行方式。当再一个事务中执行多个操作时,要么所有的事务都被提交,那么这些修改就永久低保存下来,要么数据库管理系统将放弃所作的所有修改,整个事务回滚到最初状态。

  • 为确保数据库中数据的一致性,数据的操作应当是离散的成组逻辑单元,当天全部完成时,数据的一致性可以保持,而当整个单元中的一部分操作失败,这个事务应全部是为错误,所有的起始点以后的操作应全部回退到开始状态。

    其实这个多嘴说一下,操作Mysql的时候数据是自动提交的,而Oralce却是事务需要手动操作的。

而JDBC事务处理会发生什么:

  • 数据一旦提交,就不可回滚。

    • 当一个链接对象被创建时,默认情况下时自动提交事务:每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
    • 关闭数据库连接,数据就会自动提交:如果多个操作,每个操作使用的时自己单独的连接,则无法保证事务。即同一个事务的多个操作必须再同一个连接下。
  • JDBC程序中为了让多个SQL语句作为一个事务执行:

    • 调用Connection 对象的调用con.setAutoCommit(false);就可以取消自动提交事务。

      补充: 如果设置新的Connection 没有被关闭的话,那Connection 还是不手动提交。

    • 在所有的SQL语句都成功执行后,需要调用commit();方法调用事务。

    • 如果出现异常,就会调用rollback();方法回滚事务。

    事务的四特征(ACID)

事务由四个特征,下面具体说一下:

  • 原子性(Atomicity):原子性是指事务是一个 不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
  • 一致性(Consistency): 事务必须是数据库从一个一致性状态变换到另外一个一致性状态。
  • 隔离性(Isolation):事务的隔离性是指一个事务的执行不能被其它事务干扰,即一个事务内的操作及使用的数据对并发的其它事务时隔离的,并发执行的各个事务之间不能互相干扰。
  • 持久性(Durability):持久性是指一个事务一旦被提交,它对数据库中数据的改编就是永久性,接下来的其它操作和数据库故障不应对其有任何影响。

因为这四个特征,所以在加入事务的时候解决了上面模拟银行转钱的问题。

添加事务解决演示的错误

public static void test_shiwu(){

        Connection con=null;
        Statement stm=null;
        try {
            con=getCon();
            con.setAutoCommit(false);
            stm=con.createStatement();
            String sql="UPDATE test.t_count  SET umoney = umoney-1000   WHERE uname = '张三'";
            stm.execute(sql);
            //故意创建一个错误
            System.out.println(1/0);
            sql="UPDATE test.t_count  SET umoney = umoney+1000   WHERE uname = '李四'";
            stm.execute(sql);
            con.commit();

        } catch (Exception e) {
            e.printStackTrace();
            try {
            // 回滚
                con.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        } finally {
            try {
//               修改自动提交
                con.setAutoCommit(true);
                stm.close();
                con.close();
            }catch (Exception e ){

            }

        }
    }

还是不管错误,看数据中的表的数据:

在这里插入图片描述

数据库并发问题

虽然事务解决了问题,但是又有一个新问题,那就是如果并发同时运行多个事务又会出新问题。

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

在前面说四个特征中说到了隔离,但是这个隔离其实又分等级的。如果没有采取必要的隔离机制,就会导致四种并发问题。

  • 脏读:对于两个事务A,B。A读取了已经被B更新但还没有被提交的数据。之后,B回滚,那么A读取的内容就是临时且无效的。
  • 不可重复读:对于两个事务A,B。A读取了某条数据,这个时候B突然更新了,那么A读取数据的时候指就不同了。
  • 幻读:对于两个事务A,B。A读取了数据,然后B这个时候插入了新的数据,之后如果A在读取同一个表,就会多出几行。

一个事务和其它事务隔离的成都称之为隔离级别。数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰成都,**隔离级别越高,数据一致性就越好,但并发性越弱,**所以有的必有失。

数据库中四种隔离级别:

  • READ UNCOMMITTED (读未提交数据)

    允许事务读取未被其它事务提交的变更,脏读,不可重复读的问题都会出现

  • READ COMMITTED (读已提交数据)

    只允许事务读取已经被其它事务提高的变更,可以避免脏读,但不可重复读取和幻读问题仍然可能出现。

  • REPEATABLE READ(重复读)

    确保事务可以多次从一个字段中读取相同的值,这个事务持续期间,禁止其它事务对这个字段进行更新,可以避免脏读和不可重复复读,但幻读的问题仍然存在。

  • SERIALIZABLE (串行)

    确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其它事务对该表执行插入,更新和删除操作。所以并发问题都可以避免,但性能十分低下。

    不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表.

然后整理隔离级别解决三个错误如下:

事务隔离级别脏读不可重复读幻读
READ UNCOMMITTED (读未提交数据)不会解决不会解决不会解决
READ COMMITTED (读已提交数据)解决不会解决不会解决
REPEATABLE READ(重复读)解决解决不会解决
SERIALIZABLE (串行)解决解决解决

ORACLE支持2种事务隔离级别:READ COMMITTED ,SERIALIZABLE 而其默认事务隔离为READ COMMITTED 。而Mysql支持4种事务隔离级别,Mysql默认的事务隔离级别为REPEATABLE READ。

mysql 演示

在mysql种查询隔离级别:

SELECT @@tx_isolation;

在这里插入图片描述

然后看一下MYSQL是否为自动提交;

SELECT @@autocommit;

在这里插入图片描述

这个值为1那么就是自动提交,如果通过set 可以将其设置0就变成不是自动提交。

但是为了方便操作使用

# 开始事务
START TRANSACTION;

更新事务的级别

## 会话级别的
SET TRANSACTION ISOLATION  LEVEL 隔离级别 ;

## 全局级别的
SET GLOBAL TRANSACTION ISOLATION  LEVEL 隔离级别 ;

首先需要两个连接,连接某一个数据库,暂时命名A连接和B连接。

只演示一个,不都演示了,不然又要让篇幅很大。具体步骤都写了,如果要全部演示的话按照步骤即可。

READ UNCOMMITTED

A连接

# A开始事务,然后插入数据,但是不提交数据 这两句要一起执行
START TRANSACTION;
INSERT INTO t_count VALUES ('1001','王五',1000);

B连接

#B 查询这个表
SELECT 	ucount, uname, umoney FROM test.t_count; 

在这里插入图片描述

然后将A连接回滚:

ROLLBACK;

然后再看B连接的数据:

在这里插入图片描述

JDBC演示

在这里插入图片描述

 public static void test_shiwu(){

        Connection con=null;
        Statement stm=null;
        try {
            con=getCon();
            con.setAutoCommit(false);
//            得到当前的隔离级别
            System.out.println(con.getTransactionIsolation());
//            创建当前的隔离级别 
            con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
            stm=con.createStatement();
            String sql="UPDATE test.t_count  SET umoney = umoney-1000   WHERE uname = '张三'";
            stm.execute(sql);

            con.commit();

        } catch (Exception e) {
            e.printStackTrace();
            try {
                con.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        } finally {
            try {
//               修改自动提交
                con.setAutoCommit(true);
                stm.close();
                con.close();
            }catch (Exception e ){

            }

        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值