JDBC如何处理事务和隔离级别

JDBC如何处理事务和隔离级别

事务和JDBC相关内容不再做介绍,可以去本人博客中看看:

这里主要说一下在JDBC编程中如何处理事务?
和MySQL一样,JDBC默认不开启事务,每执行一个SQL便提交一次,在MySQL中我们需要set autocommit=0来开启事务功能,然后用begin开始一个事务,用savepoint point1设置名为point1的保存点,用rollback来回滚,用commit来提交。而在JDBC中,我们需要调用connection对象的一些方法:

  • connection.setAutoCommit(false);开启事务功能
  • connection.commit();提交一个事务

我们先来看看上面两个方法的使用:

import java.sql.*;

public class TranDemo {
    public static void select(Connection connection,String sql1) throws SQLException {
        PreparedStatement ps= null;
        try {
            ps = connection.prepareStatement(sql1);//预编译sql1
	        ps.setString(1,"08");
            ResultSet resultSet = ps.executeQuery();
            while (resultSet.next()){
                System.out.println("SID="+resultSet.getString(1)+
                        " Sname="+resultSet.getString(2));
            }//我这里为了方便只打印SID和Sname
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(ps!=null){
                ps.close();//ps是这个方法的局部变量,方法结束需要关闭ps
                ps=null;//防止内存泄露
            }
        }
    }
    
    public static void delete(Connection connection,String sql3){
        PreparedStatement ps= null;
        try {
            ps=connection.prepareStatement(sql3);//预编译sql3
            ps.setString(1,"08");
            ps.execute();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(ps!=null){
                ps.close();//ps是这个方法的局部变量,方法结束需要关闭ps
                ps=null;//防止内存泄露
            }
        }
    }
    public static void main(String[] args) {
        Connection connection=null;
        try {
            String sql1="select * from Student where SID=?";
            String sql3="delete from Student where SID=?";
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test_sql", "root", "123456");
            //开启事务功能
            connection.setAutoCommit(false);//false--不自动提交
            //此时事务功能就已经开启
            //为了看起来有条理,我把查询、删除SID='08'这条记录的三个SQL语句的执行过程封装起来
             select(connection,sql1);//先执行sql1,查询SID='08',打印SID和Sname
            delete(connection,sql3);//再执行sql3,删除SID='08'这条记录
            select(connection,sql1);//查询SID='08',看还能不能查到
             connection.commit();//对比下调用这个方法和不调用的区别
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(connection!=null){
                connection.close();
                connection=null;
            } 
        }
    }
}

当把 connection.commit();注释起来时,执行结果如下:
在这里插入图片描述
可以看到两次查询同样的数据只有一次的打印结果,证明删除成功;
去MySQL中确认一下:
在这里插入图片描述
还查询的出来,证明删除失败,Java代码中执行的结果并没有提交(commit)给MySQL。
来看看放开connection.commit();的注释后的打印结果:
在这里插入图片描述
删除成功,再看看数据库中的数据:
在这里插入图片描述
查询不到,证明删除成功。
注意:事务中的缓存机制是将一个事务访问的数据复制一份为缓存(这里说成副本/快照更合适)去操作,当调用commit时才把缓存的内容提交给数据库。

  • connection.setSavepoint();设置一个保存点
  • connection.rollback()/connection.rollback(point1);回滚到初始状态/point1状态
    注意!!!正常写程序时回滚语句要写在抛SQLException异常的catch块中,如果某个SQL语句执行失败抛异常就可以回滚。

这里为了掩饰回滚效果就放在try块中,方便演示:

import java.sql.*;

public class TranDemo {
    public static void select(Connection connection,String sql1) throws SQLException {
        PreparedStatement ps= null;
        try {
            ps = connection.prepareStatement(sql1);//预编译sql1
            ps.setString(1,"02");
            ResultSet resultSet = ps.executeQuery();
            while (resultSet.next()){
                System.out.println("SID="+resultSet.getString(1)+
                        " Sname="+resultSet.getString(2));
            }//我这里为了方便只打印SID和Sname
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(ps!=null){
                ps.close();//ps是这个方法的局部变量,方法结束需要关闭ps
                ps=null;//防止内存泄露
            }
        }
    }
  
    public static void delete(Connection connection,String sql3){
        PreparedStatement ps= null;
        try {
            ps=connection.prepareStatement(sql3);//预编译sql3
            ps.setString(1,"02");
            ps.execute();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(ps!=null){
                ps.close();//ps是这个方法的局部变量,方法结束需要关闭ps
                ps=null;//防止内存泄露
            }
        }
    }
    public static void main(String[] args) throws SQLException {
        Connection connection=null;
        Savepoint point1=null;
        try {
            String sql1="select * from Student where SID=?";
            String sql3="delete from Student where SID=?";
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test_sql", "root", "123456");
            //开启事务功能
            connection.setAutoCommit(false);//false--不自动提交
            //此时事务功能就已经开启
            //为了看起来有条理,我把查询、删除SID='02'这条记录的三个SQL语句的执行过程封装起来
            select(connection,sql1);//1.先执行sql1,查询SID='02',打印SID和Sname
             point1= connection.setSavepoint();//设置一个保存点point1
            delete(connection,sql3);//2.执行sql3,删除SID='02'这条记录
            select(connection,sql1);//查询SID='02',不打印则删除成功
            connection.rollback(point1);//回滚到point1
            select(connection,sql1);//打印出SID='02'的SID和Sname则回滚成功
            connection.commit();//对比下调用这个方法和不调用的区别,不能写在rollback操作前
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(point1!=null){
                connection.releaseSavepoint(point1);
                point1=null;
            }
            if(connection!=null){
                connection.close();
                connection=null;
            }
        }
    }
}

运行结果:
在这里插入图片描述
打印了两次而不是三次,证明在事务的缓存(副本)中确实删除了一次,最后又回滚到point1,删除掉的数据又回来了。

  • connection.releaseSavepoint(point1);删除point1保存点
  • connection.setTransactionIsolation(int level);设置事务的隔离级别,这个隔离级别只对当前连接有效,在MySQL中一个连接就是打开的一个窗口(终端);在JDBC中,一个连接就是一个connection。
    剖析源码看一下隔离级别对应的int值:
    在这里插入图片描述
    在这里插入图片描述
发布了19 篇原创文章 · 获赞 9 · 访问量 2195

猜你喜欢

转载自blog.csdn.net/weixin_44480874/article/details/99995850
今日推荐