【问题标题】:How can I not close the connection due to a transaction if I use try-with-resources?如果我使用 try-with-resources,如何不因事务而关闭连接?
【发布时间】:2021-08-19 20:54:14
【问题描述】:

我有一个 DAO,它具有将实体插入 MySQL 数据库的方法。该方法将连接和实体作为参数。在 Context.xml 文件中,我设置该连接将具有 defaultAutoCommit="false" 属性,因此我不需要在 DAO 方法中设置它。

defaultAutoCommit="false"
@Override
public boolean insertCarCategory(Connection connection, CarCategory carCategory) {
    int rowNum = 0;
    String query = "INSERT INTO car_category values(?,?,?,?);";
    try (Connection con = connection;
         AutoRollback autoRollback = new AutoRollback(con);
         PreparedStatement statement = con.prepareStatement(query)) {
        statement.setString(1, carCategory.getCarCategory());
        statement.setDouble(2, carCategory.getCostPerOneKilometer());
        statement.setDouble(3, carCategory.getDiscount());
        statement.setBytes(4, ImageUtil.imageToByte(carCategory.getCarCategoryImage()));
        rowNum = statement.executeUpdate();
        //if it used as transaction dont commit and close connection
        autoRollback.commit();
    } catch (SQLException e) {
        LOGGER.error(e);
    }
    return rowNum > 0;
}

将在服务层中使用的 UserDao 方法

@Override
public boolean insertUser(Connection connection,User user) {
    int rowNum = 0;
    String query = "INSERT INTO user_info(login,userPassword,userType,userEmail)values(?,?,?,?);";
    ResultSet keys = null;
    try(Connection con = connection;
        AutoRollback autoRollback = new AutoRollback(con);
        PreparedStatement statement = con.prepareStatement(query,Statement.RETURN_GENERATED_KEYS)) {
        statement.setString(1, user.getLogin());
        statement.setString(2, PasswordUtil.generateStrongPasswordHash(user.getPassword()));
        statement.setString(3, user.getUserType());
        statement.setString(4, user.getUserEmail());
        rowNum = statement.executeUpdate();
        keys = statement.getGeneratedKeys();
        if (keys.next()) {
            user.setUserId(keys.getInt(1));
        }
        autoRollback.commit();
    } catch (SQLException e) {
        LOGGER.error(e);
    } finally {
        if (keys != null) {
            try {
                keys.close();
            } catch (SQLException e) {
                LOGGER.error(e);
            }
        }
        }
    return rowNum > 0;
}

如果提交为假,我使用 AutoRollBack 类来帮助我回滚事务

public class AutoRollback implements AutoCloseable  {
    private Connection conn;
    private boolean committed;
    public AutoRollback(Connection conn) throws SQLException {
        this.conn = conn;
    }
    public void commit() throws SQLException {
        conn.commit();
        committed = true;
    }
    @Override
    public void close() throws SQLException {
        if(!committed) {
            conn.rollback();
        }
    }
}

在服务层,我使用 DAO 方法。我从连接池中获取连接并将其传递给 DAO 方法。

private void insertCarUser(User user,CarCategory carCategory){
    Connection connection = MySQLDAOFactory.getConnection();
    categoryDao.insertCarCategory(connection,carCategory);
    userDao.insertUser(connection,user);
}

如何不关闭其中一种方法的连接,以便在第二种方法中使用?

【问题讨论】:

    标签: java mysql database jdbc database-connection


    【解决方案1】:

    去掉各种DAO方法中的try-with-resources,取而代之的是在获取连接时立即应用try-with-resource:

    private void insertCarUser(User user,CarCategory carCategory){
        try (Connection connection = MySQLDAOFactory.getConnection()) {
            categoryDao.insertCarCategory(connection,carCategory);
            userDao.insertUser(connection,user);
        }
    }
    

    同样,如果此操作需要原子操作,您将希望将事务处理移到那里,而不是在 DAO 方法中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-24
      • 2017-12-04
      • 2017-05-06
      • 1970-01-01
      • 2019-03-12
      • 2020-01-01
      • 2019-01-18
      • 2011-10-16
      相关资源
      最近更新 更多