Java sql sqlexception no operations allowed after statement closed

Возврат ResultSet

Я пытаюсь создать метод, из которого я могу запросить мою базу данных и получить целую таблицу. В настоящее время он отлично работает, если я использую данные внутри метода. Однако я хочу, чтобы метод возвращал результаты. Я получаю java.sql.SQLException: Operation not allowed after ResultSet closed для текущего кода. Как я могу это достичь?

public ResultSet select() < con = null; st = null; rs = null; try < con = DriverManager.getConnection(url, user, password); st = con.createStatement(); rs = st.executeQuery("SELECT * FROM biler"); /* if (rs.next()) < System.out.println(rs.getString("model")); >*/ > catch (SQLException ex) < Logger lgr = Logger.getLogger(MySQL.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); >finally < try < if (rs != null) < rs.close(); >if (st != null) < st.close(); >if (con != null) < con.close(); >> catch (SQLException ex) < Logger lgr = Logger.getLogger(MySQL.class.getName()); lgr.log(Level.WARNING, ex.getMessage(), ex); >> return rs; > 

Почему вы не можете интерпретировать очевидное сообщение об ошибке — « java.sql.SQLException: операция не разрешена после закрытия ResultSet »?

5 ответов

Вы не должны передавать ResultSet через общедоступные методы. Это подвержено утечке ресурсов, потому что вы вынуждены сохранять отчет и соединение открыто. Закрытие их неявно закрывает набор результатов. Но держать их открытыми приведет к тому, что они будут болтаться и заставить БД исчерпывать ресурсы, когда их слишком много.

Сопоставьте его с коллекцией Javabeans, как это, и верните его вместо:

public List list() throws SQLException < Connection connection = null; PreparedStatement statement = null; ResultSet resultSet = null; Listbilers = new ArrayList(); try < connection = database.getConnection(); statement = connection.prepareStatement("SELECT id, name, value FROM Biler"); resultSet = statement.executeQuery(); while (resultSet.next()) < Biler biler = new Biler(); biler.setId(resultSet.getLong("id")); biler.setName(resultSet.getString("name")); biler.setValue(resultSet.getInt("value")); bilers.add(biler); >> finally < if (resultSet != null) try < resultSet.close(); >catch (SQLException ignore) <> if (statement != null) try < statement.close(); >catch (SQLException ignore) <> if (connection != null) try < connection.close(); >catch (SQLException ignore) <> > return bilers; > 

Или, если вы уже на Java 7, просто используйте try-with-resources выражение, которое автоматически закрывает эти ресурсы

public List list() throws SQLException < Listbilers = new ArrayList(); try ( Connection connection = database.getConnection(); PreparedStatement statement = connection.prepareStatement("SELECT id, name, value FROM Biler"); ResultSet resultSet = statement.executeQuery(); ) < while (resultSet.next()) < Biler biler = new Biler(); biler.setId(resultSet.getLong("id")); biler.setName(resultSet.getString("name")); biler.setValue(resultSet.getInt("value")); bilers.add(biler); >> return bilers; > 

Кстати, вы не должны объявлять Connection , Statement и ResultSet как переменные экземпляра вообще (основная проблема безопасности потоков!) и не проглатывать SQLException в этой точке вообще ( вызывающий не будет знать, что возникла проблема), а также не закрывать ресурсы в том же try (если, например, закрытие результата закрывает исключение, то инструкция и соединение все еще открыты). Все эти проблемы исправлены в приведенных выше фрагментах кода.

Читайте также:  Kotlin bitmap to string

Спасибо, что нашли время написать подробный ответ. Используя этот код, я должен был бы создать метод для каждой таблицы. Это действительно лучший способ сделать это?

Да, когда вы придерживаетесь низкого уровня JDBC. Тем не менее, вы можете провести рефакторинг повторяющегося стандартного кода в довольно высокой степени, как это сделал Hibernate десять лет назад. Нет, по моему скромному мнению, JPA — лучший способ. Тогда это вопрос return em.createQuery(«SELECT b FROM Biler b», Biler.class).getResultList(); один лайнер.

Не могли бы вы объяснить, почему вы указали «серьезную проблему безопасности потоков», например, переменную «conn»? Если это не статично, почему проблема параллелизма? Я не вижу, потому что conn доступен только внутри экземпляра, а не класса

Если вы не знаете, что хотите от ResultSet при получении времени, я предлагаю сопоставить всю вещь на карте следующим образом:

 List> resultList = new ArrayList>(); Map row = null; ResultSetMetaData metaData = rs.getMetaData(); Integer columnCount = metaData.getColumnCount(); while (rs.next()) < row = new HashMap(); for (int i = 1; i resultList.add(row); > 

Итак, в основном вы имеете то же самое, что и ResultSet (без ResultSetMetaData).

Использует ли этот подход больше памяти, когда мы создаем отдельный hashMap, чем просто имеем resultSet и не закрываем его?

Вы можете закрыть оператор и соединение после цикла while, тогда у вас будет только объект resultlist, что означает, что это не будет проблемой.

Хорошо, вы do звоните rs.close() в свой finally -block.

Это в основном хорошая идея, так как вы должны закрыть все свои ресурсы (соединения, операторы, результирующие наборы. ).

Но вы должны закрыть их после их использования.

Существует как минимум три возможных решения:

  • не закрывать набор результатов (и соединение. ) и требовать, чтобы вызывающий вызывал отдельный метод «закрыть». Это в основном означает, что теперь вызывающему абоненту нужно помнить, что он звонит близко, и на самом деле не упрощает работу.
  • пусть вызывающий проходит в классе, который получает переданный набор результатов и вызывает это в вашем методе Это работает, но может стать немного подробным, поскольку для каждого блока кода, который вы хотите выполнить на наборе результатов, вам понадобится подкласс какого-либо интерфейса (возможно, как анонимный внутренний класс). Интерфейс выглядел следующим образом:

public interface ResultSetConsumer

public List select(String query, ResultSetConsumer consumer) < Connection con = null; Statement st = null; ResultSet rs = null; try < con = DriverManager.getConnection(url, user, password); st = con.createStatement(); rs = st.executeQuery(query); Listresult = new ArrayList(); while (rs.next()) < result.add(consumer.consume(rs)); >> catch (SQLException ex) < // logging >finally < try < if (rs != null) < rs.close(); >if (st != null) < st.close(); >if (con != null) < con.close(); >> catch (SQLException ex) < Logger lgr = Logger.getLogger(MySQL.class.getName()); lgr.log(Level.WARNING, ex.getMessage(), ex); >> return rs; > 

Я бы использовал третий вариант, но не могу понять, как составить список, содержащий всю информацию, независимо от выбранной таблицы.

@PatrickReck: почему вы хотите сделать это независимо от выбранной таблицы ? Разные таблицы содержат разные типы данных.

Именно так. То, что я хочу, это один метод, из которого я могу передать вызов SQL и вернуть данные, полученные из вызова. Если бы я выбрал всю таблицу автомобилей (идентификатор, модель), я бы хотел, чтобы эти двое вернулись. Если бы это была таблица клиентов (идентификатор, имя, адрес, телефон), я бы хотел, чтобы все эти данные были возвращены одним и тем же способом.

@PatrickReck: Я бы категорически не одобрял это, но вы могли бы вернуть List> если хотите (карта, очевидно, содержит карту от имени поля до значения для каждого результата).

@PatrickReck: Кроме того, посмотрите мой обновленный пост с примером кода для варианта № 2, возможно, это поможет.

Как все передо мной говорили о своей плохой идее передать результирующий набор. Если вы используете библиотеку пулов Connection, например c3p0, вы можете безопасно использовать CachedRowSet и его реализация CachedRowSetImpl. Используя это, вы можете закрыть соединение. При необходимости он будет использовать соединение. Вот фрагмент из документа java:

Объект CachedRowSet — это несвязанный набор строк, что означает, что он использует короткое соединение с источником данных. Он подключается к источнику данных, пока он считывает данные, чтобы заполнить себя строками и снова, пока он распространяет изменения обратно в исходный источник данных. В остальное время объект CachedRowSet отключается, в том числе при изменении его данных. Будучи отключенным, объект RowSet становится намного более компактным и, следовательно, намного проще передать другому компоненту. Например, отключенный объект RowSet может быть сериализован и передан по проводу тонкому клиенту, например, персональному цифровому помощнику (PDA).

Вот фрагмент кода для запроса и возврата ResultSet:

public ResultSet getContent(String queryStr) < Connection conn = null; Statement stmt = null; ResultSet resultSet = null; CachedRowSetImpl crs = null; try < Connection conn = dataSource.getConnection(); stmt = conn.createStatement(); resultSet = stmt.executeQuery(queryStr); crs = new CachedRowSetImpl(); crs.populate(resultSet); >catch (SQLException e) < throw new IllegalStateException("Unable to execute query: " + queryStr, e); >finally < try < if (resultSet != null) < resultSet.close(); >if (stmt != null) < stmt.close(); >if (conn != null) < conn.close(); >> catch (SQLException e) < LOGGER.error("Ignored", e); >> return crs; > 

Вот фрагмент для создания источника данных с помощью c3p0:

 ComboPooledDataSource cpds = new ComboPooledDataSource(); try < cpds.setDriverClass(""); //loads the jdbc driver > catch (PropertyVetoException e) < e.printStackTrace(); return; >cpds.setJdbcUrl("jdbc:"); cpds.setMinPoolSize(5); cpds.setAcquireIncrement(5); cpds.setMaxPoolSize(20); javax.sql.DataSource dataSource = cpds; 

Источник

Java Error Operation Not Allowed After ResultSet Closed

Java Error Operation Not Allowed After ResultSet Closed

  1. Java Error java.sql.SQLException: Operation not allowed after ResultSet closed
  2. Fix Java Error java.sql.SQLException: Operation not allowed after ResultSet closed

This tutorial demonstrates the java.sql.SQLException: Operation not allowed after ResultSet closed error in Java.

Java Error java.sql.SQLException: Operation not allowed after ResultSet closed

The error Operation Not Allowed After Resultset Closed is an SQL exception when we try to access a closed result set. As the Java Doc mentions, whenever a statement object is closed, If its Resultset object exists, it will also be closed.

The problem with the error is that the Resultset instance will also save the underlying statement. So when the underlying statement is closed, the Resultset will also be closed, which throws the error.

Here’s a snippet of code that will throw the same error.

 ResultSet Result_Set; // class variable   Statement Demo_Statement = null;  try  Demo_Statement = DB_Connection.createStatement();  Result_Set = Demo_Statement.getGeneratedKeys();  >  catch (Exception e)  throw e;  >  finally  try  if (Demo_Statement != null)  Demo_Statement.close();  > catch (SQLException e)  throw e;  >  >   System.out.println(Result_Set.next()); 

The code above with a database connection will throw the following error.

java.sql.SQLException: Operation not allowed after ResultSet closed 

Fix Java Error java.sql.SQLException: Operation not allowed after ResultSet closed

The problem in the code is that we cannot close the statement instance before we are done with Resultset . Once we are done with the Resultset , we can close both Resultset and Statement Instance.

As we can see, we are trying to print the Boolean from Result_Set.next() , but we are using the Resultset after closing the statement instance, which is also closing the Resultset .

In the code above, the fix will be not to close the statement at this place or not to use the Resultset after closing the statement instance. It is based on your application either we can remove the Demo_Statement.close() or the System.out.println(Result_Set.next()); statement.

 ResultSet Result_Set; // class variable   Statement Demo_Statement = null;  try  Demo_Statement = DB_Connection.createStatement();  Result_Set = Demo_Statement.getGeneratedKeys();  >  catch (Exception e)  throw e;  >  finally  try  if (Demo_Statement != null)  Demo_Statement.close();  > catch (SQLException e)  throw e;  >  > 

We just removed the part where we are trying the use the Resultset after the statement instance is closed. Once all the operations are done with the Resultset , we can close both the statement instance and Resultset .

Sheeraz is a Doctorate fellow in Computer Science at Northwestern Polytechnical University, Xian, China. He has 7 years of Software Development experience in AI, Web, Database, and Desktop technologies. He writes tutorials in Java, PHP, Python, GoLang, R, etc., to help beginners learn the field of Computer Science.

Related Article — Java Error

Источник

Getting java.sql.SQLException: Operation not allowed after ResultSet closed

The problem is with the way you fetch data in getStuff(). Each time you visit getStuff() you obtain a fresh ResultSet but you don’t close it. , Cool. I created a new Statement in getStuff() and that solved the problem. – samxli Apr 30 ’11 at 11:59 , Can we tell which way AC power is going through a cable without cutting the cable? ,I guess after while(rs2.next()) you are trying to access something from rs1. But it’s already closed since you reexecuted statement to get rs2 from it. Since you didn’t close it, I beleive it’s used again below.

The problem is with the way you fetch data in getStuff() . Each time you visit getStuff() you obtain a fresh ResultSet but you don’t close it.

The problem is with the way you fetch data in getStuff() . Each time you visit getStuff() you obtain a fresh ResultSet but you don’t close it.

The problem is with the way you fetch data in getStuff() . Each time you visit getStuff() you obtain a fresh ResultSet but you don’t close it.

Answer by Raelyn Burns

Page generated in 0.009 sec. using MySQL 8.0.26-commercial ,The file you have requested (bug.php?id=620) does not exist., © 2021, Oracle Corporation and/or its affiliates

The file you have requested ( bug.php?id=620 ) does not exist.

Answer by Sky Pollard

Detect Loop in Linked List And Identify the Start . Count Number of Words in the given input String,Shortest Distance in m x n Matrix from Source to D. HackerRank Problem: Birthday Chocolate

 ResultSet resultSet; // class variable . . Statement st = null; try < st = conn.createStatement(); resultSet = st.getGeneratedKeys(); >catch (Exception e) < throw e; >finally < try < if (st != null) st.close(); >catch (SQLException e) < throw e; >> 

Answer by Amias Singh

Getting java.sql.SQLException: Operation not allowed after ResultSet closed ,Copyright © 2021 SemicolonWorld. All Rights Reserved. ,Bottom line: you have several ResultSet pertaining to the same Statement object concurrently opened.,What makes things even worse is the rs from the calling code. It is also derived off-of the statement field but it is not closed.

When I execute the following code, I get an exception. I think it is because I’m preparing in new statement with he same connection object. How should I rewrite this so that I can create a prepared statement AND get to use rs2? Do I have to create a new connection object even if the connection is to the same DB?

 try < //Get some stuff String name = ""; String sql = "SELECT `name` FROM `user` WHERE `id` = " + userId + " LIMIT 1;"; ResultSet rs = statement.executeQuery(sql); if(rs.next()) < name = rs.getString("name"); >String sql2 = "SELECT `id` FROM `profiles` WHERE `id` =" + profId + ";"; ResultSet rs2 = statement.executeQuery(sql2); String updateSql = "INSERT INTO `blah`. "; PreparedStatement pst = (PreparedStatement)connection.prepareStatement(updateSql); while(rs2.next()) < int int stuff = getStuff(id); pst.setInt(1, stuff); pst.addBatch(); >pst.executeBatch(); > catch (Exception e) < e.printStackTrace(); >private int getStuff(int id) < try < String sql = "SELECT . ;"; ResultSet rs = statement.executeQuery(sql); if(rs.next()) < return rs.getInt("something"); >return -1; >//code continues 

Источник

Оцените статью