Question

Considérez le code:

PreparedStatement ps = null;
ResultSet rs = null;
try {
  ps = conn.createStatement(myQueryString);
  rs = ps.executeQuery();
  // process the results...
} catch (java.sql.SQLException e) {
  log.error("an error!", e);
  throw new MyAppException("I'm sorry. Your query did not work.");
} finally {
  ps.close();
  rs.close();
}

Ce qui précède ne compile pas car PreparedStatement.close () et ResultSet.close () jettent un java.sql.SQLException . Alors, est-ce que j'ajoute un bloc try / catch à la clause finally? Ou déplacer les déclarations proches dans la clause try? Ou tout simplement pas la peine d'appeler à proximité?

Était-ce utile?

La solution

Pour les entrées / sorties de fichiers, j’ajoute généralement un try / catch au bloc finally. Cependant, vous devez faire attention à ne pas lancer d’exceptions du bloc finally, car elles entraîneraient la perte de l’exception originale (le cas échéant).

Voir cet article pour un exemple plus spécifique de la fermeture d'une connexion à une base de données.

Autres conseils

Sous Java 7, vous ne devez pas les fermer explicitement, mais utilisez automatic. gestion des ressources pour vous assurer que les ressources sont fermés et les exceptions sont traitées de manière appropriée. La gestion des exceptions fonctionne comme ceci:

Exception in try | Exception in close | Result
-----------------+--------------------+----------------------------------------
      No         |        No          | Continue normally
      No         |        Yes         | Throw the close() exception
      Yes        |        No          | Throw the exception from try block
      Yes        |        Yes         | Add close() exception to main exception
                 |                    |  as "suppressed", throw main exception

Espérons que cela a du sens. En permet joli code, comme ceci:

private void doEverythingInOneSillyMethod(String key)
  throws MyAppException
{
  try (Connection db = ds.getConnection()) {
    db.setReadOnly(true);
    ...
    try (PreparedStatement ps = db.prepareStatement(...)) {
      ps.setString(1, key);
      ...
      try (ResultSet rs = ps.executeQuery()) {
        ...
      }
    }
  } catch (SQLException ex) {
    throw new MyAppException("Query failed.", ex);
  }
}

Avant Java 7, il était préférable d'utiliser des blocs nested finally, plutôt que de tester les références pour null.

L'exemple que je vais montrer peut paraître moche avec l'imbrication profonde, mais en pratique, un code bien conçu ne va probablement pas créer une connexion, une instruction et des résultats de la même manière; souvent, chaque niveau d'imbrication implique le passage d'une ressource à une autre méthode, qui l'utilise comme usine pour une autre ressource. Avec cette approche, les exceptions d'un close () masqueront une exception à l'intérieur du bloc try . Cela peut être surmonté, mais le code est encore plus compliqué et nécessite une classe d’exception personnalisée qui fournit le code "supprimé". exception chaînant présente dans Java 7.

Connection db = ds.getConnection();
try {
  PreparedStatement ps = ...;
  try {
    ResultSet rs = ...
    try {
      ...
    }
    finally {
      rs.close();
    }
  } 
  finally {
    ps.close();
  }
} 
finally {
  db.close();
}

Si vous lancez votre propre jdbc à la main, il devient vraiment compliqué. La fin () dans le doit enfin être emballée avec sa propre capture try, qui, à tout le moins, est laide. Vous ne pouvez pas ignorer la fermeture, bien que les ressources soient effacées lorsque la connexion est fermée (ce qui peut ne pas être le cas si vous utilisez un pool). En fait, l’un des principaux arguments de vente liés à l’utilisation d’un framework (par exemple, hibernate) pour gérer votre accès à une base de données est la gestion de la connexion et de la gestion des ensembles de résultats afin de ne pas oublier de fermer.

Vous pouvez faire quelque chose de simple comme celui-ci, qui cache au moins le désordre et vous garantit de ne pas oublier quelque chose.

public static void close(ResultSet rs, Statement ps, Connection conn)
{
    if (rs!=null)
    {
        try
        {
            rs.close();

        }
        catch(SQLException e)
        {
            logger.error("The result set cannot be closed.", e);
        }
    }
    if (ps != null)
    {
        try
        {
            ps.close();
        } catch (SQLException e)
        {
            logger.error("The statement cannot be closed.", e);
        }
    }
    if (conn != null)
    {
        try
        {
            conn.close();
        } catch (SQLException e)
        {
            logger.error("The data source connection cannot be closed.", e);
        }
    }

}

et ensuite,

finally {
    close(rs, ps, null); 
}

Ne perdez pas votre temps à coder la gestion des exceptions de bas niveau, utilisez une API de niveau supérieur, telle que Spring-JDBC, ou un wrapper personnalisé autour des objets connection / statement / rs, pour masquer le code désordonné try-catch désordonné.

Notez également:

" Lorsqu'un objet Statement est fermé, son objet ResultSet actuel, s'il en existe un, est également fermé. "

http: // java.sun.com/j2se/1.5.0/docs/api/java/sql/Statement.html#close ()

Il devrait suffire de ne fermer que l'état PreparedStatement de manière finale, et uniquement s'il n'est pas déjà fermé. Cependant, si vous voulez être vraiment particulier, fermez le ResultSet en premier, pas après avoir fermé le PreparedStatement (le fait de le fermer après, comme certains exemples ici, devrait en réalité garantir une exception, puisqu'il est déjà fermé).

J'ai généralement une méthode utilitaire qui peut fermer des choses comme celle-ci, en prenant soin de ne rien faire avec une référence null.

Habituellement, si close () lève une exception, cela ne me dérange pas vraiment, alors je me connecte à l'exception et je l'avale - mais une autre solution consisterait à la convertir en RuntimeException . Quoi qu'il en soit, je vous recommande de le faire à l'aide d'une méthode utilitaire facile à appeler, car vous devrez peut-être le faire à de nombreux endroits.

Notez que votre solution actuelle ne fermera pas le ResultSet si la fermeture de PreparedStatement échoue. Il est préférable d'utiliser des blocs nested finally.

Si vous utilisez Java 7, vous pouvez utiliser les améliorations apportées aux mécanismes de gestion des exceptions dans les classes qui implémentent AutoCloseable (c'est-à-dire PreparedStatement , Resultset )

Vous pouvez également trouver cette question intéressante: Clôturer ResultSet en Java 7

Je sais que c'est une vieille question, mais juste au cas où quelqu'un chercherait la réponse, java dispose désormais de la solution try-with-resouce.

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

N'omettez pas d'appeler à proximité. Cela peut causer des problèmes.

Je préfère ajouter le bloc try / catch à la dernière.

Probablement une vieille façon (bien que simple) de faire les choses, mais cela fonctionne toujours:

public class DatabaseTest {

    private Connection conn;    
    private Statement st;   
    private ResultSet rs;
    private PreparedStatement ps;

    public DatabaseTest() {
        // if needed
    }

    public String getSomethingFromDatabase(...) {
        String something = null;

        // code here

        try {
            // code here

        } catch(SQLException se) {
            se.printStackTrace();

        } finally { // will always execute even after a return statement
            closeDatabaseResources();
        }

        return something;
    }

    private void closeDatabaseResources() {
        try {
            if(conn != null) {
                System.out.println("conn closed");
                conn.close();
            }

            if(st != null) {
                System.out.println("st closed");
                st.close();
            }

            if(rs != null) {
                System.out.println("rs closed");
                rs.close();
            }

            if(ps != null) {
                System.out.println("ps closed");
                ps.close();
            }

        } catch(SQLException se) {
            se.printStackTrace();
        }               
    }
}

En vous appuyant sur la réponse de @ erickson, pourquoi ne pas le faire en un seul essayer comme ceci?

private void doEverythingInOneSillyMethod(String key) throws MyAppException
{
  try (Connection db = ds.getConnection();
       PreparedStatement ps = db.prepareStatement(...)) {

    db.setReadOnly(true);
    ps.setString(1, key);
    ResultSet rs = ps.executeQuery()
    ...
  } catch (SQLException ex) {
    throw new MyAppException("Query failed.", ex);
  }
}

Notez que vous n'avez pas besoin de créer l'objet ResultSet dans le bloc try car ResultSet est automatiquement fermé lorsque le < code> PreparedStatement est fermé.

  

Un objet ResultSet est automatiquement fermé lorsque l'objet Statement   qui l’a généré est fermé, ré-exécuté ou utilisé pour récupérer le prochain   résulte d'une séquence de résultats multiples.

Référence: https://docs.oracle .com / javase / 7 / docs / api / java / sql / ResultSet.html

focus enfin la clause,

finally {
   try {
      rs.close();
      ps.close();
   } catch (Exception e) {
      // Do something
   }
}

Je pense que vous devez modifier 2 points.

D'abord, utilisez try & amp; attraper à nouveau dans la clause fainlly.

Deuxièmement, exécutez rs.close () avant ps.close ().

fly1997@naver.com

Je l'utilise ..

finally
{
    if (ps != null) ps.close();
    if (rs != null) rs.close();
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top