美文网首页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