• JDBC API 事务的实践


    使用了持久化框架几乎没有使用过原生的jdbc API ,发现原来使用jdbc API来实现事务也是很简单的。

    数据库的链接connection具有一个属性autocommit,这个属性默认是true,作用是控制是否把执行的命令提交给数据库。一旦命令被提交就无法回滚数据库。

    而我们实现事务的方式也是很简单,就是手动设置属性autocommit的值为false,等执行完全部命令之后再手动提交所有命令就可以了。

    try (Connection connection = DriverManager.getConnection(url, username, password)) {
    System.out.println("数据库链接成功!");

    try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY)) {
    String command = "insert into a_dept(name) values('1'),('2')";
    int count = statement.executeUpdate(command);
    System.out.println("受影响行数:" + count);

    String selectSql = "select * from a_dept";
    String updateSql = "update a_dept set name=? where id=?";
    String insertSql = "insert into a_dept(name) values(?)";
    try (ResultSet resultSet = statement.executeQuery(selectSql)) {
    while (resultSet.next()) {
    System.out.print("修改前id " + resultSet.getInt("id") + "的值是: ");
    System.out.println(resultSet.getString("name"));
    }
    resultSet.beforeFirst();
    connection.setAutoCommit(false);
    while (resultSet.next()) {
    PreparedStatement updateState = connection.prepareStatement(updateSql);
    updateState.setString(1, "I am new" + resultSet.getInt("id"));
    updateState.setInt(2, resultSet.getInt("id"));
    updateState.executeUpdate();
    }

    // Savepoint savepoint = connection.setSavepoint();
    PreparedStatement updateState = connection.prepareStatement(insertSql);
    updateState.setString(1, "我是插入的");
    updateState.executeUpdate();
    try {
    PreparedStatement updateStateFail = connection.prepareStatement(insertSql);
    updateStateFail.setString(1, "我是插入的,但是我太长了,所以我是插不进去的,会报错!");
    updateStateFail.executeUpdate();

    } catch (Exception e) {
    connection.rollback();
    System.err.println(e.getMessage());
    }
    connection.commit();
    Statement newStatement = connection.createStatement();
    ResultSet newSet = newStatement.executeQuery(selectSql);
    System.out.println("打印出所有的值:");
    while (newSet.next()) {
    System.out.print(newSet.getInt("id") + ": ");
    System.out.println(newSet.getString("name"));
    }
    }
    }
    }

      贴运行结果:

    红色字体就是报错的信息。我们可以发现,在这个结果集当中没有进行修改,也没有进行插入,所有的修改和插入命令因为插入操作的错误都被回滚了。

    但是我们发现我们的修改操作和插入操作都被回滚了,这在一些情况下我们不希望所有的操作都被回滚,那么我们可以设置回滚的节点,设置回滚的节点也很简单,在想要的地方添加如下代码,

    Savepoint savepoint = connection.setSavepoint();

    那么就会在该地生成一个节点,回滚把这个节点作为参数传递给回滚的方法 rollback() ,那么回滚的时候会放过该节点之前的操作,需要注意的是节点使用完之后必须释放它。

    结果如下(不要在意Id亲,我清了数据库了):
    Connected to the target VM, address: '127.0.0.1:17576', transport: 'socket'
    数据库链接成功!
    受影响行数:2
    修改前id 479的值是: 1
    修改前id 480的值是: 2
    Data truncation: Data too long for column 'name' at row 1
    打印出所有的值:
    479: I am new479
    480: I am new480
    Disconnected from the target VM, address: '127.0.0.1:17576', transport: 'socket'

    简单吧:

    最后附上使用节点回滚的全部代码,可以不看~:

            try (Connection connection = DriverManager.getConnection(url, username, password)) {
                System.out.println("数据库链接成功!");
    
                try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY)) {
                    String command = "insert into a_dept(name) values('1'),('2')";
                    int count = statement.executeUpdate(command);
                    System.out.println("受影响行数:" + count);
    
                    String selectSql = "select * from a_dept";
                    String updateSql = "update a_dept set name=? where id=?";
                    String insertSql = "insert into a_dept(name) values(?)";
                    try (ResultSet resultSet = statement.executeQuery(selectSql)) {
                        while (resultSet.next()) {
                            System.out.print("修改前id " + resultSet.getInt("id") + "的值是: ");
                            System.out.println(resultSet.getString("name"));
                        }
                        resultSet.beforeFirst();
                        connection.setAutoCommit(false);
                        while (resultSet.next()) {
                            PreparedStatement updateState = connection.prepareStatement(updateSql);
                            updateState.setString(1, "I am new" + resultSet.getInt("id"));
                            updateState.setInt(2, resultSet.getInt("id"));
                            updateState.executeUpdate();
                        }
    
                        Savepoint savepoint = connection.setSavepoint();
                        PreparedStatement updateState = connection.prepareStatement(insertSql);
                        updateState.setString(1, "我是插入的");
                        updateState.executeUpdate();
                        try {
                            PreparedStatement updateStateFail = connection.prepareStatement(insertSql);
                            updateStateFail.setString(1, "我是插入的,但是我太长了,所以我是插不进去的,会报错!");
                            updateStateFail.executeUpdate();
    
                        } catch (Exception e) {
                            connection.rollback(savepoint);
                   connection.releaseSavepoint(savepoint);
                            System.err.println(e.getMessage());
                        }
                        connection.commit();
                        Statement newStatement = connection.createStatement();
                        ResultSet newSet = newStatement.executeQuery(selectSql);
                        System.out.println("打印出所有的值:");
                        while (newSet.next()) {
                            System.out.print(newSet.getInt("id") + ": ");
                            System.out.println(newSet.getString("name"));
                        }
                    }
                }
            }
    

      

  • 相关阅读:
    redis缓存和mysql数据库同步
    msf生成shellcode
    转 如何用mt7620方案的rt2860v2驱动实现wifi探针功能,网上能搜到一些方法,但是讲的好模糊?
    解决 “不支持尝试执行的操作”错误
    解决win7资源监视器不能开启
    mp3文件 ID3v2 帧标识的含义
    LoadImage函数问题
    AutoCAD ObjectARX(VC)开发基础与实例教程2014版光盘镜像
    Python计算文件MD5值
    objectARX 获取指定图层上所有实体ID
  • 原文地址:https://www.cnblogs.com/heisehenbai/p/7886760.html
Copyright © 2020-2023  润新知