JDBC事务使用实例(二)

  1. MySQL和Oracle比较
    MySQL数据库 默认情况下一条SQL就是一个单独事务,事务是自动提交的。
    Oracle 数据库 默认情况下事务不是自动提交,所有SQL都将处于一个事务中,你需要手动进行commit提交/rollback回滚。
  2. 事务使用
    2.1 MySQL中使用事务
    start transaction 开启事务(所有对数据表增加、修改、删除操作 临时表进行)
    rollback 回滚事务 (取消刚才的操作)
    commit 提交事务(确认刚才的操作)
    SQL语言中只有DML才能被事务管理 insert update delete。
    2.2 JDBC中使用事务
    Connection.setAutoCommit(false); // 设置不自动提交
    Connection.rollback();
    Connection.commit();
    2.3 事务回滚点
    当时事务特别复杂,有些情况不会回滚到事务最开始状态,需要将事务回滚到指定位置。
    Savepoint sp = conn.setSavepoint(); 设置回滚点
    Conn.rollback(sp); 事务回滚到指定位置
public void demo3() {
        // 创建person 表 插入20000条数据,如果插入过程中发生错误,保证插入的数据是1000的整数倍
        Connection conn = null;
        PreparedStatement stmt = null;
        Savepoint savepoint = null;

        try {
            conn = JDBCUtils.getConnection();// 连接数据库
            conn.setAutoCommit(false);// 设置不自动提交
            savepoint = conn.setSavepoint();// 设置回滚点

            String sql = "insert into person values(?,?)";// 设置预编译的sql语句
            stmt = conn.prepareStatement(sql);// 预编译sql

            for (int i = 0; i < 20000; i++) {
                // 给添加的参数赋值
                stmt.setInt(1, i);
                stmt.setString(2, "name" + i);

                // 添加到批处理
                stmt.addBatch();

                // 制造错误
                if (i == 4699) {
                    int d = 1 / 0;
                }

                // 每隔200条向数据库发送一次
                if (i % 200 == 0) {
                    stmt.executeBatch();// 执行批处理
                    stmt.clearBatch();// 清楚批处理缓存

                }

                if (i % 1000 == 0) {
                    savepoint = conn.setSavepoint();// 执行1000条插入之后再次保存回滚点
                    conn.commit();// 提交
                }
            }
            stmt.executeBatch();// 确保缓存没有内容

        } catch (Exception e) {
            try {
                conn.rollback(savepoint);// 出现错误则回到回滚点
                conn.commit();// 再次进行提交
            } catch (SQLException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }

            e.printStackTrace();
        } finally {
            JDBCUtils.release(stmt, conn);
        }

    }

3.事务隔离
不考虑事务隔离将引发:脏读、不可重复读、虚读
脏读:一个事务读取另一个事务 未提交数据 —- 是数据库隔离中最重要问题
不可重复读:一个事务读取另一个事务 已提交数据,在一个事务中两次读取结果不同
虚读:一个事务读取另一个事务 插入数据,造成在一个事务中两次读取记录条数不同
* 虚读 不可重复读 区别? 不可重复读读取 update数据 ,虚读读取insert 数据

数据库为了解决三类隔离引发问题:提供四个数据隔离级别
Serializable : 串行处理 —- 解决三类问题
Repeatable read :可以解决 不可重复读、脏读,会发生虚读 ——- MySQL 默认级别
read committed : 可以 解决脏读 ,会发生 不可重复读、虚读 ——– Oracle默认级别
read uncommitted : 会导致三类问题发生
Serializable > Repeatable read > read committed > read uncommitted
数据库隔离问题危害 脏读> 不可重复读 > 虚读
安全级别越高,处理效率越低;安全级别越低,效率高

在数据库中通过
set (session)transaction isolation level 设置事务隔离级别
select @@tx_isolation 查询当前事务隔离级别
4.事务丢失更新
介绍:两个事务同时读取同一条记录,A先修改记录,B也修改记录(B是不知道A修改过),B提交数据后B的修改结果覆盖了A的修改结果。
解决方法: 悲观锁 和乐观锁
4.1 悲观锁
原理:使用数据库内部锁机制,进行table的锁定,在A修改数据时,A就将数据锁定,B此时无法进行修改。无法发生两个事务同时修改,假设丢失更新会发生。

在mysql中默认情况下,当你修改数据,自动为数据加锁(在事务中)。事务和锁和不可分开的,锁一定是在事务中使用 ,当事务关闭锁自动释放。
(1)读锁:读锁(共享锁) 一张表可以添加多个读锁,如果表添加读锁(不是当前事务添加的),该表不可以修改。共享锁容易发生死锁。
select * from account lock in share mode;
(2)写锁:(排它锁) 一张表只能加一个排它锁,排他锁和其它共享锁、排它锁都具有互斥效果 。
select * from account for update ;
可以使用排它锁解决丢失更新问题。
4.2 乐观锁
原理:使用不是数据库锁机制,而是一个特殊标记字段,如果控制字段状态和内容,得知数据是否发生并发访问!假设丢失更新不会发生
* 数据库timestamp 时间戳字段。
通过给数据库设置一个时间戳。比较操作数据的时间,来解决丢失更新问题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值