如果我使用 try-with-resources,我怎么能因为事务不关闭连接?

How can I not close the connection due to a transaction if I use try-with-resources?

我有一个 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 class 帮助我回滚事务如果提交为假

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);
}

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

删除各种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 方法中。