исключение java.sql.SQLException: набор результатов закрыт при обновлении на основе порядка определения в основном классе

#java #database #sqlite #connection

Вопрос:

У меня есть класс, который будет подключаться к своей собственной базе данных SQLite и имеет функции для взаимодействия с базой данных. В моем коде есть два экземпляра этого класса customerDB и merchantDB . По какой-то причине экземпляр, определенный первым в основном классе, выдаст ошибку, если я попытаюсь вызвать функцию addBalance(); или reduceBalance(); после определения другого экземпляра класса.

Ошибка, которую я получаю в этом случае, заключается в следующем:

Исключение в потоке «основной» Исключение java.sql.SQLException: набор результатов закрыт

И когда я первоначально попытался позвонить addBalance(); позже в своей основной программе, я получил ошибку:

Исключение в потоке «основной» Исключение java.sql.SQLException: соединение с базой данных закрыто

Я использую библиотеку JBDC в своей Java-программе, и users таблица внутри базы данных имеет точно такой же макет для обеих баз данных. Любая помощь будет признательна.

Users.db

 import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;

public class UsersDB {
    private static Connection conn = null;
    
    private boolean loggedIn = false;
    private boolean merchant = false;
    private String username;
    private float balance;
    
    public UsersDB(String dbName, boolean merchant) {
        this.merchant = merchant;
        // try to connect to DB
        try {
            Class.forName("org.sqlite.JDBC");
            conn = DriverManager.getConnection("jdbc:sqlite:"   dbName);
        } catch (Exception e) {
            System.out.println("Error - "   e.getMessage());
        }
    }
    
    public void login(String username, String password) throws NoSuchAlgorithmException, SQLException {
        
        // Check the fields contain data and that the user is not already logged in
        if (!Util.isNullOrEmpty(username) amp;amp; !Util.isNullOrEmpty(password) amp;amp; loggedIn == false) {
            ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM users WHERE username = '"   username   "'");
            
            // Check if username exists
            if (rs.next()) {
                String passwordInDB = rs.getString("password");
                
                MessageDigest digest = MessageDigest.getInstance("SHA-256");
                byte[] passwordHash = digest.digest(password.getBytes(StandardCharsets.UTF_8));
                
                // Check if passwords match
                if (Util.bytesToHex(passwordHash).equals(passwordInDB)) {
                    loggedIn = true;
                    
                    this.username = username;
                    balance = rs.getFloat("balance");
                    System.out.println("Successful login, "   this.username);
                }
            } else {
                System.out.println("Incorrect Username or Password");
            }
            
        } else {
            System.out.println("Sorry, there was an error logging in!");
        }
    }
    
    public float getBalance() throws SQLException {
        if (loggedIn) {
            ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM users WHERE username = '"   username   "'");          
            return rs.getFloat("balance");          
        }
        else {
            System.out.println("Action may not be performed. User must be logged in.");
        }
        return 0;
    }
    
    public void reduceBalance(float price) throws Exception {
        // User must be logged in to update balance
        // Price must be valid and not exceed the user's balance
        if (loggedIn amp;amp; price > 0 amp;amp; getBalance() >= price) {
            float newBalance = balance - price;
            conn.createStatement().executeUpdate("UPDATE users SET balance = "   newBalance   " WHERE username = '"   username   "'");
            // Update the value of balance to the new once stored in the database
            balance = getBalance();
            if (balance != newBalance) {
                throw new Exception("Balance Update Failed");
            } else {
                System.out.println("Customer balance decreased by "   price);
                System.out.println("");
            }
        }
        else {
            System.out.println("Cannot reduce balance");
            System.out.println("");
        }
    }
    
    public void addBalance(float price) throws Exception {
        if (loggedIn amp;amp; price > 0) {
            float newBalance = balance   price;
            conn.createStatement().executeUpdate("UPDATE users SET balance = "   newBalance   " WHERE username = '"   username   "'");
            // Update the value of balance to the new once stored in the database
            balance = getBalance();
            if (balance != newBalance) {
                throw new Exception("Balance Update Failed");
            }
        } else {
            System.out.println("Cannot add balance");
        }
    }
    
    public boolean isLoggedIn() {
        return loggedIn;
    }
    
    public boolean isMerchant() {
        return merchant;
    }
    
    public void closeConnection() throws SQLException {
        conn.close();
    }
}
 

Definition

 UsersDB merchantDB = new UsersDB("Merchants.db", true);
        merchantDB.login("merchant", "merchantpass");
        // Works
        merchantDB.addBalance(20);
        
        UsersDB customerDB = new UsersDB("Customers.db", false);
        customerDB.login("test", "testpass");   
        
        // Does not work
        merchantDB.addBalance(20);
 

Комментарии:

1. Опубликуйте полученное сообщение об ошибке.

2. @forpas Я обновил вопрос, включив в него сообщения об ошибках.

Ответ №1:

Вы определили соединение как статическое:

 private static Connection conn = null;
 

Это означает, что все экземпляры класса UsersDB будут использовать одно и то же соединение.

Удалите ключевое static слово из его определения.

Комментарии:

1. Я не могу поверить, что не видел этого — это объясняет, почему сообщение об ошибке изменилось на «соединение закрыто» после закрытия соединения с customerDB. Спасибо.