如果我使用 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 方法中。
我有一个 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 方法中。