深入详解数据库事务(开发必用)
一.事务的概念:
一组逻辑操作单元,时数据从一个状态转换到另一个状态。
二.事务处理的原则:
保证所有的事务都被当做一个操作单元来执行,即使出现了故障,也不能改变这种处置原则。要么与事务相关的数据全部被修改,并永远的提交保存下来,要么所有的事务全部回滚到事务没被执行的状态。
三.那些操作会影响数据库的提交
(一).数据库连接一旦断开,数据库的数据都被会提交
(二).DDL操作完成,数据自动提交,并且无法回滚
(三).DML操作默认为提交,但是可以通过 set auto commit = false;来设置不允许自动提交
四.模拟事务提交
事务执行过程图:
通用的包含事务的更新方法
public static int update(Connection conn,String sql,Object... args){ int temp = -1; PreparedStatement pst = null; try{ //2.预编译sql语句 pst = conn.prepareStatement(sql); //3.填充占位符 for (int i = 0; i < args.length; i++) { pst.setObject(i+1,args[i]); } //4.执行 // pst.execute(); temp = pst.executeUpdate(); }catch (Exception e){ e.printStackTrace(); }finally { //5.释放资源 closeResource(null,pst); } return temp; }
(一).模拟存在异常情况下的102给103转账100元操作;
public void testTransaction() throws Exception { Connection conn = null; //102向103转账100元 try{ conn = JDBCUtils.getConnection(); //关闭DML自动调教功能 conn.setAutoCommit(false); String sql1 = "update user_tab set balance = balance - 100 where id = ?"; update(conn,sql1,102); //模拟异常 System.out.println(10/0); //103接受102转账100元 String sql2 = "update user_tab set balance = balance + 100 where id = ?"; update(conn,sql2,103); //提交事务 conn.commit(); System.out.println("转账成功"); }catch (Exception e ){ e.printStackTrace(); //出现异常数据回滚 conn.rollback(); }finally {//将自动提交功能设置还原为true conn.setAutoCommit(true); JDBCUtils.closeResource(conn,null); } }
转账失败
(二).模拟不存在异常下转账的情况
public void testTransaction() throws Exception { Connection conn = null; //102向103转账100元 try{ conn = JDBCUtils.getConnection(); //关闭DML自动调教功能 conn.setAutoCommit(false); String sql1 = "update user_tab set balance = balance - 100 where id = ?"; update(conn,sql1,102); //模拟异常// System.out.println(10/0); //103接受102转账100元 String sql2 = "update user_tab set balance = balance + 100 where id = ?"; update(conn,sql2,103); //提交事务 conn.commit(); System.out.println("转账成功"); }catch (Exception e ){ e.printStackTrace(); //出现异常数据回滚 conn.rollback(); }finally {//将自动提交功能设置还原为true conn.setAutoCommit(true); JDBCUtils.closeResource(conn,null); } }
转账成功
四.事务的ACID属性
(一).事务的属性
1.原子性:
原子性是指事务时一个不可分割的工作单元,事务中的操作要么都发生,要么都不发生
2.一致性:
事务必须使数据库从一个一致状态转换到另一个一致状态
3.隔离性:
事务并发在执行时,各个事务之间的数据互不干扰的,各个事务 之间的数据不受任何影响
4.持久性:
事务一旦被提交,就是永久性的改变,接下来发生的事或数据库故障都不会对其有任何我影响。
(二).事务的并发问题
1.脏读:
读出了未提交的数据。
事务T1,事务T2,T1读入一个数据段A,读出值为1,此时T2修改了A的值,T1将A= 2的值读出,但此时T2撤销了事务,回滚到A=1的阶段。此时T1读出的数据无效,即为脏读:
2.不可重复读:
只读提交的数据,并且第一次读出来是什么,在提交之前,读出来的东西和第一次保持一致;
事务T1在第一次读到A=1,在读到以后,无论其他事务(T2)对字段A怎么更新提交(A=2),T1在提交前读出A字段永远都是A=1;
3.幻读:
事务T1第一次读出100条数据,T2插入3条数据并提交,T1提交后,T1再次读,读出103条数去,即为幻读,
(三).隔离级别
1. READ UNCOMMITED(读未提交的数据)
2. READ COMMITED(读已提交的数据)
3. REPEATED READ(可重复读)
4. 串行化:SERIALIZABLE(各个事务顺序执行)
(四).java代码实现隔离级别(框架必用,提前打基础)
package Transaction;import UpAndSelMethod.Method;import jdbcUtil.JDBCUtils;import org.junit.Test;import userBean.User;import java.sql.Connection;//*********卧槽,为啥我设置隔离级别为读未提交却读不出来修改了却为体骄傲的数据,麻了******************public class Test隔离级别 { //**************************测试事务并发问题与隔离级别的关系********************************* //测试查询 @Test public void testTransactionSelect() throws Exception { Connection conn = JDBCUtils.getConnection(); //设置sql语句 String sql = "select id,name,balance from user_tab where id = ?"; //查看当前连接的的隔离级别 System.out.println(conn.getTransactionIsolation()); //设置当前连接的隔离级别为读未提交 conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); System.out.println(conn.getTransactionIsolation()); User user = Method.selectinfo(User.class, sql, 103); System.out.println(user); } //测试更新 @Test public void testTransactionUpdate() throws Exception { //获取连接 Connection conn = JDBCUtils.getConnection(); //设置自动提交为false conn.setAutoCommit(false); //sql String sql = "update user_tab set balance = ? where id = ?"; //执行更新操作 Method.update(conn,sql,5000,103); //线程睡眠15秒 Thread.sleep(15000); //睡眠结束 System.out.println("修改完成"); }}
来源地址:https://blog.csdn.net/qq_52655865/article/details/123977638
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341