Можно ли использовать один и тот же объект BasicDataSource, Connection, Statement и ResultSet в нескольких методах класса?

У меня есть код ниже, который использует статические объекты BasicDataSource, Sql Connection, Statement и ResultSet. Приведенный ниже код работает нормально, но я просто хочу знать о безопасности использования таких методов кодирования. или как я могу оптимизировать приведенный ниже код, чтобы он стал более стабильным и надежным.

public class Testing {
     static BasicDataSource bds = DBConnection.getInstance().getBds();
     static Connection con = null;
     static PreparedStatement stmt = null;
     static ResultSet rs = null;

    private void show() {
        try {
            con = bds.getConnection();
            stmt = con.prepareStatement("SELECT * FROM users");
            rs = stmt.executeQuery();
            if(rs.next()) {
                System.out.println(rs.getString("firstname") + " " + rs.getString("lastname"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    private void display() {
        try {
            con = bds.getConnection();
            stmt = con.prepareStatement("SELECT * FROM agent_cities");
            rs = stmt.executeQuery();
            while(rs.next()) {
                System.out.println(rs.getString("city_name"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    private void add() {
        try {
            con = bds.getConnection();
            stmt = con.prepareStatement("UPDATE users SET firstname = 'shsh' WHERE id = 2");
            stmt.executeUpdate();
            System.out.println("updated successfully");
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        Testing t = new Testing();
        t.show();
        t.display();
        t.add();
    }
}

Заранее спасибо. Поделитесь своими случаями, когда вы можете сломать код выше, и задайте вопрос о его безопасности.

Обновление: Обновление только для того, чтобы гарантировать, что никто не должен использовать статические поля, как я использовал в приведенной выше программе, потому что указанная выше программа содержит ошибку при развертывании на сервере разработки.

После использования приведенного выше кода в больших системах я обнаружил ошибку. месяц назад у меня не было проблем с приведенным выше кодом, и он работал нормально, но сегодня я обнаружил ошибку.

Ошибка:

После 6-7 ударов по моим API он перестал давать ответ на 8-м ударе. я действительно не знаю почему и понятия не имею о лазейках, присутствующих в программе. Но теперь, когда я принял ответ, я изменил свой исходный код и начал использовать ресурсы try-with в своем коде и удалил статические поля.

Но мне все еще любопытно узнать об ошибке, которую я нашел в приведенном выше коде. который не дает ответа и зависает после 7-8 обращений к API. Пожалуйста, поделитесь своими мыслями по этому поводу. Я использую сервер Apache Tomcat 8.5.32. Заранее спасибо.


person Onkar Musale    schedule 06.03.2019    source источник
comment
В зависимости от сложности приложения вам действительно не следует использовать поля для соединений, операторов и наборов результатов (а статические поля - еще больший запах).   -  person Mark Rotteveel    schedule 06.03.2019
comment
Тогда какие есть лучшие альтернативы.   -  person Onkar Musale    schedule 07.03.2019
comment
Локальные переменные, конечно.   -  person Mark Rotteveel    schedule 07.03.2019
comment
и в чем причина этого   -  person Onkar Musale    schedule 07.03.2019
comment
Это предотвращает слишком долгое существование соединения, предотвращает непреднамеренное совместное использование соединений между несколькими потоками и предотвращает другие типы утечек ресурсов.   -  person Mark Rotteveel    schedule 07.03.2019
comment
вам не кажется, что объявление локальных переменных каждый раз в отдельных методах требует много времени для больших систем, которые у меня есть.   -  person Onkar Musale    schedule 07.03.2019
comment
Как я уже сказал в своем первоначальном комментарии: это зависит от того, но в целом их статика - это запах кода.   -  person Mark Rotteveel    schedule 07.03.2019


Ответы (3)


Лучше используйте попробовать с ресурсами. Это автоматически закрывает Connection, Statement и ResultSet даже при возникновении исключения или при внутреннем возврате.

    String sql = "UPDATE users SET firstname = ? WHERE id = ?";
    try (Connection con = bds.getConnection();
            PreparedStatement stmt = con.prepareStatement()) {
        stmt.setString(1, "shsh");
        stmt.setLong(2, 2);
        stmt.executeUpdate();
        System.out.println("updated successfully");
    }

    String sql = "SELECT city_name FROM agent_cities";
    try (Connection con = bds.getConnection();
            PreparedStatement stmt = con.prepareStatement()) {
        try (ResultSet rs = stmt.executeQuery()) {
            while(rs.next()) {
                System.out.println(rs.getString("city_name"));
            }
        }
    }

Это лучше для сбора мусора. Мешает некрасивость rs2, rs3. Разрешает многопользовательский параллелизм, как в серверном приложении. Вызывает этот запрос самостоятельно. А static еще больше в стиле глобальных переменных.

person Joop Eggen    schedule 06.03.2019
comment
Речь идет не о сборке мусора, а об очистке ресурсов, тогда как «ресурс» означает любой ресурс, не управляемый сборщиком мусора Java. Память этих объектов в куче Java является лишь незначительной проблемой. - person Holger; 06.03.2019
comment
@ Хольгер, правда, спасибо. На самом деле я немного теряюсь, не находя здесь правильных слов. Программист C/Fortran старого стиля будет использовать глобальные переменные, как это было предложено. - person Joop Eggen; 06.03.2019
comment
Формулировка сложная, как и в других языках программирования, все, что требует выделения и освобождения, является «ресурсом», который включает явно управляемую память. Умственная работа Java-программиста состоит в том, чтобы исключить управляемую память кучи из набора ресурсов, при этом рассматривая «ресурс» как нечто, что все еще нуждается в явном закрытии (с учетом использования try(…) в качестве явного управления) и должно быть закрыто как можно раньше. Тогда становится легче понять тщетность старой идеи закрытия ресурсов в финализаторе, поскольку сборщик мусора только заботится о памяти кучи. - person Holger; 06.03.2019
comment
Спасибо. теперь я буду использовать вышеуказанный блок try-with-resources. - person Onkar Musale; 07.03.2019
comment
@JoopEggen, пожалуйста, посмотрите на рассматриваемую часть обновления и поделитесь своим мнением о ней. - person Onkar Musale; 09.04.2019
comment
Это может быть своего рода утечка ресурсов (комментарий Хольгера), слишком много соединений, операторы для каждого соединения остаются открытыми. Но это чистое предположение. Когда поле перезаписывается, старый объект не закрывается и так далее. пул соединений? Максимальное количество подключений? Механизмы баз данных имеют переключатели отладки. - person Joop Eggen; 09.04.2019

Это более-менее нормально, если мы говорим о такой маленькой программе. Но нет необходимости держать con, stmt и rs как статические переменные, их можно объявить внутри метода. Кроме того, вам нужно переписать блоки try catch finally и правильно закрыть ресурсы:

Connection con = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
  // your code
} catch (SQLException e) {
  e.printStackTrace();
} finally {
  try { if (rs != null) rs.close(); } catch (Exception e) {e.printStackTrace();}
  try { if (stmt != null) stmt.close(); } catch (Exception e) {e.printStackTrace();}
  try { if (conn != null) conn.close(); } catch (Exception e) {e.printStackTrace();}
}

В качестве следующего шага вы можете проверить try-with-resources. конструкция для очистки этого кода.

person Mykhailo Hodovaniuk    schedule 06.03.2019
comment
Ага. но у меня много большой программы, в которой я не могу создавать новые объекты для каждой сигнатуры метода, так каково ваше решение для очень большой программы, содержащей много сигнатур методов. - person Onkar Musale; 06.03.2019
comment
Это зависит от стека технологий. Если у вас есть java без spring/hibernate, вам нужен один источник данных (который у вас уже есть static BasicDataSource bds = DBConnection.getInstance().getBds();) и правильно закрыть ресурсы. - person Mykhailo Hodovaniuk; 06.03.2019
comment
да, я не использую Spring/Hibernate. я использую Java Servlets и Maven в качестве инструмента сборки с Eclipse IDE. - person Onkar Musale; 06.03.2019

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

В следующем примере считывается первая строка из файла. Он использует экземпляр BufferedReader для чтения данных из файла. BufferedReader — это ресурс, который необходимо закрыть после того, как программа закончит работу с ним:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}
person Community    schedule 21.05.2019