package PreparedStatementCURD;
import Instrument.GetConnection;
import Instrument.Operation;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @description 事务的问题引入
* @author Vodka
* @date 2021/07//18:15
*/
/*
* 1.事务: 一组逻辑操作单元,使数据从一种状态变换到另一种状态 (一组逻辑操作单元代表一组系列相关的DML操作)
* 2.事务处理(事务操作): -保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。
* -当一个事务执行多个操作时,要么所有事务执行被commit保存,要么rollback到最初状态.
* 3.数据提交之后,就不能回滚,以下操作会导致数据自动提交:
* -DDL操作一旦执行,都会自动提交。 (即Delete操作,即使设置set autocommit = false的方式,也是默认提交)
* -DML默认情况下,一旦执行,也会自动提交。(这个可以通过set autocommit = false 取消DML操作的自动提交)
* -默认在关闭连接时,会自动提交数据
*
* */
/*
* 1.原子性(Atomicity):原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
* 2.一致性(Consistency): 事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
* 3.隔离性(Isolation): 事务的隔离指一个事务的执行不能被其他事务干扰,各个事务独立运行。
* 4.持久性(Durability): 事务一旦被提交,它对数据库中的数据的改变也是永久性的,接下来的其他操作和数据库故障都不会
* 对它造成影响。
*
* 数据库的并发问题: 当同时运行多个事务时,如果不采取必要的隔离机制,就会导致事务之间各种并发问题:
* 1.脏读: 对于两个t1 ,t2 , t1读取了已经被t2更新但并未提交的数据。在这时,t2 回滚,t1读取的内容就是临时且无效的
* 2.不可重复读: 对于两个事务t1 , t2, t1读取一个字段,然后t2更新了该字段,之后,t1再次读取同一字段,值已经不一样
* 3.幻读: 对于两个事务t1,t2, t1从一个表中读取了一个字段,然后t2在该表插入了一些新的行,之后如果t1再次读取,就会
* 出现跟上一次不同的新数据。
*
* 1.隔离级别:
* -read uncommitted: 各个事务之间的脏读,不可重复读,幻读等问题都会出现。
*
* -read committed: 避免了脏读,但不可重复读和幻读还会出现。 (与可重复读级别的区别在于,该级别的事务,
* 在读取某个字段一次结束之后,别的事务就可以对之前事务所读的数据进行更改提交,之前的事务第二次读之后,数据不同了,不可重复读)
*
* -repeatable read: 避免了脏读和不可重复读,但幻读仍然存在。
* (与读取已提交数据级别的不同之处是,当前级别可以在某个事务持续重复读取某个字段值时,禁止其它事务对该字段进行更改)
*
* -serializable(串行化): 所有并发问题都可以避免,但性能十分低下。
*
* 1.各个数据库的默认级别: 1.Oracle支持两种事务隔离级别,read committed,serializable。Oracle默认级别为repeatable read.
* 2.Mysql支持4中事务隔离级别,默认隔离级别为: repeatable read.
*
* 1.在Mysql中设置隔离级别:
* -每启动一个mysql程序,就会有一个单独的数据库连接,每个数据库连接都有一个全局变量 @@tx_isolation,
* 表示当前的事务隔离级别。(JDBC可以通过程序设置当前连接的隔离级别,不管数据库系统的全局隔离级别是什么)
*
* -查看当前的隔离级别: select @@tx_isolation;
*
* -设置mysql当前连接的隔离级别: set transaction isolation level read committed;
*
* -设置数据库系统的全局隔离级别: set global transaction isolation level read committed;
*
* -创建mysql数据库用户: create user tom identified by 'abc123';
*
* -授予权限:
* #授予通过网络方式登录的tom用户,对所有库所有表的全部权限,密码为abc123
* grant all privileges on xxx to tom @'%' identified by 'abc123';
*
* #给tom用户使用本地命令行方式,授予yyy库下的所有表的增删查改的权限
* grant select,insert,delete,update on yyy to tom @localhost identified by 'abc123';
* */
public class Transaction {
public static void main(String []args) {
Connection conn = null;
try {
conn = GetConnection.getConnection();
conn.setAutoCommit(false);
// 案例: 体现事务transaction的特性,A给B转账,要封装在一个事务中,原子性
//使用一个连接贯穿一个事务的DML函数,而不是操作一次关闭一次,执行完一次事务后再关闭连接
String DrawUp = "Update Account set deposit = deposit + ? where UId = ? and UName = ?";
String WithDraw = "Update Account set deposit = deposit - ? where UId = ? and UName = ?";
Operation.UpdateTwo(conn, WithDraw, 1000, 1901, "Vodka");
// 模拟网络异常,检验事务的完整性
// System.out.println(100 / 0);
Operation.UpdateTwo(conn, DrawUp, 1000, 1902, "Alice");
//若事务执行过程没有出错,就手动提交数据
conn.commit();
} catch (Exception e) {
e.printStackTrace();
try{
// 如果事务执行过程出错,就进行回滚操作
conn.rollback();
}catch (Exception e2){
JDBC-事务处理(练习)
最新推荐文章于 2024-04-19 09:27:06 发布
本文详细介绍了如何在Java中使用JDBC进行事务处理。通过实例演示了事务的开启、提交、回滚以及隔离级别的应用,帮助开发者理解事务在数据库操作中的重要性和使用技巧。
摘要由CSDN通过智能技术生成