美文网首页sqlJava
JDBC 数据库事务的处理规则

JDBC 数据库事务的处理规则

作者: 一亩三分甜 | 来源:发表于2019-12-17 16:14 被阅读0次

    1.什么叫数据库事务?

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

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

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

    4.哪些操作会导致数据的自动提交?

    DDL操作一旦执行,都会自动提交。set autocommit = false 对DDL操作失效。
    DML默认情况下,一旦执行,就会自动提交。我们可以通过set autocommit = false的方式取消DML操作的自动提交。
    默认在关闭连接时,会自动的提交数据

    只有同时防止上面三种情况,才能防止数据的自动提交。

    正常情况下,若不发生异常
    /*
        针对于数据表user_table来说:
        AA用户给BB用户转账100
        update user_table set balance = balance - 100 where user = 'AA';
        update user_table set balance = balance + 100 where user = 'BB';
        */
        @Test
        public void testUpdate(){
            String sql1 = "update user_table set balance = balance - 100 where user = ?";
            update(sql1,"AA");
    
            String sql2 = "update user_table set balance = balance + 100 where user = ?";
            update(sql2,"BB");
    
            System.out.println("转账成功");
        }
        //通用的增删改操作     -----version 1.0
        public int update(String sql,Object ...args){//sql中占位符的个数与可变形参的个数相同
            Connection conn = null;
            PreparedStatement ps = null;
            try{
                //1.获取数据库的连接
                conn = JDBCUtils.getConnection();
                //2.预编译sql语句,返回PreparedStatement的实例
                ps = conn.prepareStatement(sql);
                //3.填充占位符
                for (int i = 0;i < args.length;i++)
                {
                    ps.setObject(i+1,args[i]);
                }
                //4.执行
    //            ps.execute();
                return ps.executeUpdate();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                //5.资源的关闭
                JDBCUtils.closeResource(conn,ps);
                System.out.println("执行完毕!");
            }
            return 0;
        }
    //输出
    转账成功
    
    WX20191217-135839@2x.png

    模拟网络异常

        @Test
        public void testUpdate(){
            String sql1 = "update user_table set balance = balance - 100 where user = ?";
            update(sql1,"AA");
    
            //模拟网络异常
            System.out.println(10/0);
    
            String sql2 = "update user_table set balance = balance + 100 where user = ?";
            update(sql2,"BB");
    
            System.out.println("转账成功");
        }
    //输出
    执行完毕!
    
    java.lang.ArithmeticException: / by zero
    
        at com.cloud.transaction.TransactionTest.testUpdate(TransactionTest.java:27)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
        at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
        at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
        at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
    
    WX20191217-140554@2x.png

    考虑数据库事务后的转账操作

    @Test
        public void testUpdateWithTx(){
            Connection conn = null;
            try{
                conn = JDBCUtils.getConnection();
                System.out.println(conn.getAutoCommit());//true
                //1.取消数据的自动提交
                conn.setAutoCommit(false);
                String sql1 = "update user_table set balance = balance - 100 where user = ?";
                update(conn, sql1, "AA");
    
                String sql2 = "update user_table set balance = balance + 100 where user = ?";
                update(conn, sql2, "BB");
    
                System.out.println("转账成功");
                //2.提交数据
                conn.commit();
            }catch (Exception e){
                e.printStackTrace();
                //3.回滚数据
                try {
                    conn.rollback();
                }catch (Exception ex){
                    ex.printStackTrace();
                }
            }finally {
                JDBCUtils.closeResource(conn,null);
            }
        }
    
        /*******************考虑数据库事务后的转账操作***************/
    
        //通用的增删改操作     -----version 2.0
        public int update(Connection conn,String sql,Object ...args){//sql中占位符的个数与可变形参的个数相同
            PreparedStatement ps = null;
            try{
                //1.预编译sql语句,返回PreparedStatement的实例
                ps = conn.prepareStatement(sql);
                //3.填充占位符
                for (int i = 0;i < args.length;i++)
                {
                    ps.setObject(i+1,args[i]);
                }
                //4.执行
                return ps.executeUpdate();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                //5.资源的关闭
                JDBCUtils.closeResource(null,ps);
                System.out.println("执行完毕!");
            }
            return 0;
        }
    //输出
    true
    执行完毕!
    执行完毕!
    转账成功
    
    WX20191217-160510@2x.png

    模拟网络异常情况

    @Test
        public void testUpdateWithTx(){
            Connection conn = null;
            try{
                conn = JDBCUtils.getConnection();
                //1.取消数据的自动提交
                conn.setAutoCommit(false);
                String sql1 = "update user_table set balance = balance - 100 where user = ?";
                update(conn, sql1, "AA");
    
                //模拟网络异常情况
                System.out.println(10/0);
                String sql2 = "update user_table set balance = balance + 100 where user = ?";
                update(conn, sql2, "BB");
    
                System.out.println("转账成功");
                //2.提交数据
                conn.commit();
            }catch (Exception e){
                e.printStackTrace();
                //3.回滚数据
                try {
                    conn.rollback();
                }catch (Exception ex){
                    ex.printStackTrace();
                }
            }finally {
                JDBCUtils.closeResource(conn,null);
            }
        }
    //输出
    java.lang.ArithmeticException: / by zero
    
    WX20191217-161303@2x.png

    Connection没有被关闭,还可能被重复使用,则需要回复其自动提交状态setAutoCommit(true)。尤其是在使用数据库连接池技术时,执行close()方法前,建议恢复自动提交状态。

       //通用的增删改操作     -----version 2.0
        public int update(Connection conn,String sql,Object ...args){//sql中占位符的个数与可变形参的个数相同
            PreparedStatement ps = null;
            try{
                //1.预编译sql语句,返回PreparedStatement的实例
                ps = conn.prepareStatement(sql);
                //3.填充占位符
                for (int i = 0;i < args.length;i++)
                {
                    ps.setObject(i+1,args[i]);
                }
                //4.执行
                return ps.executeUpdate();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                //修改其为自动提交数据
                //主要针对于使用数据库连接池的使用
                //5.资源的关闭
                JDBCUtils.closeResource(null,ps);
                System.out.println("执行完毕!");
            }
            return 0;
        }
    

    相关文章

      网友评论

        本文标题:JDBC 数据库事务的处理规则

        本文链接:https://www.haomeiwen.com/subject/zepsnctx.html