08. jdbc 事务

it2022-05-05  161

jdbc 系列文章列表, 请查看目录: 《jdbc学习笔记》

1. 数据库事务

数据库事务, 通俗来将, 就是将多个增删改操作组成一个原子操作来执行, 原子操作要么同时成功, 要么失败. 而且在事务的执行过程中, 子操作涉及到的数据具有线程安全的特性, 不会被并发的其它事务所篡改.

1.1 事务四大特性

数据库事务有四大特性, 简称ACID:

原子性(Atomicity): 指事务作为一个整体, 事务包含的所有操作要么同时成功, 要么同时失败. 不存在部分成功情况一致性(Consistency): 事务执行必须从一个执行状态变化为另一个一致性状态隔离线(Isolation): 事务的执行不能被其它事务干扰, 即事务执行过程中, 内部设计到的各个数据对其它并发事务来讲是隔离的.持久性(Durability): 事务一旦被提交, 便是永久. 后续数据库故障等不应该对已提交的事务产生影响.

1.2 jdbc操作事务

数据库事务是由Connection 控制的, 也就是说只能是同一连接中的操作才能组成一个事务.默认情况下, Connection 是自动提交事务的, 也就是说任何一条增删改操作语句执行后, 立刻会自动提交事务. 不具备回滚功能使用jdbc开发事务的步骤如下: 1. 获取数据库连接 2. 关闭自动提交事务 3. 执行1-n条数据库操作 4. 手工提交事务, 执行commit方法 5. 出现异常时, 回滚事务. 恢复连接的自动提交事务状态. 6. 释放资源(关闭连接, 或将连接规划连接池), 当采用连接池时, 归还连接时应该恢复连接的自动提交事务!

1.3 事务回滚与不提交的差别

虽然说事务不提交和事务回滚, 数据库表中数据均不会产生变化, 但这两者还是有很大的差别的:

开启手动提交事务之后, 所有增删改操作, 都会被暂时存在数据库的"临时区域中", 当执行提交操作时, 才会将"临时区域"中的修改才会生效.当执行回滚操作时, 会将"临时区域"中的修改清空 当发生异常时, 若不进行回滚, 那会带来一下隐患: "临时区域"不会提交, 当其它操作再拿到相同连接时, 执行commit操作时, 会将之前的操作也同时提交数据库是有隔离级别的, 虽然说事务未提交,也可能由于数据库隔离级别的问题, 导致被其它线程所有读取. 因此会导致脏读问题

1.4 理解误区

jdbc 对数据库事务的管控是通过Connection来控制的, 若想实现声明式事务(类似于Spring), 需要从控制Connection入手.通常数据库的查询是不需要开启事务的, 对数据库的增删改才需要开启事务.不开启事务, 并非是说不能对数据库进行增删改操作, 只是说在发生异常时, 不能进行回滚而已. 也不能保证多个操作能同时执行成功或失败.事务一旦提交成功, 便不能进行回滚操作. 这一点需要特别注意.在使用连接池时, 当归还数据库连接时, 应恢复连接的自动提交事务功能!

2. 事务测试

虽然说, 在企业开发过程中, 我们通常无须手工管控事务, 通常都是交由Spring 处理. 但是我们依然需要了解Jdbc 是如何控制事务的, 因为Spring 底层也是通过jdbc 来控制事务的. 有兴趣的话完全可以通过动态代理自己实现一个类似Spring 的声明式事务.

通过控制int a=1/10; 代码来测试事务提交与回滚需要注意的是, 如果事务提交之后,再抛异常, 是不生效的. public void test_transcation() { //1. 获取数据库连接 Connection connection = DbConnUtil.getConnection(); Statement statement = null; try { //2. 关闭手工提交事务 connection.setAutoCommit(false); //3. 执行数据库操作 statement = connection.createStatement(); statement.execute("insert into t_user values(1001, 'zhangsan', 'zhangsan123')"); statement.execute("insert into t_user values(1002, 'lisi', 'lisi123')"); // 模拟异常, 需要注意的是, 需要在事务提交前抛出异常. 事务一旦提交, 纵使发生了异常, 也不能进行回滚了. // int a=1/10; //4. 提交事务 connection.commit(); } catch (SQLException e) { // 回滚事务 connection.rollback(); e.printStackTrace(); }finally { // 关闭连接, connection, Statement 等... DbConnUtil.release(statement, connection); } }

最新回复(0)