web-dev-qa-db-fra.com

Deux instructions préparées différentes dans un seul lot

Je veux envoyer deux déclarations préparées différentes en un seul lot

Actuellement, je le fais en deux comme vous pouvez le voir dans les lignes commentées et cela fonctionne, mais ce n'est pas l'objectif principal ici. Quelqu'un peut-il me dire quoi mettre en place de ces commentaires pour que cette chose fonctionne?

import Java.lang.ClassNotFoundException;
import Java.math.BigDecimal;
import Java.sql.Connection;
import Java.sql.PreparedStatement;
import Java.sql.SQLException;
import Java.sql.DriverManager;

public class Main
{
    public static void main(String[] args)
    {
        Connection connection = null;
        PreparedStatement preparedStatementWithdraw = null;
        PreparedStatement preparedStatementDeposit = null;

        try
        {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/youtube", "root", "root");

            preparedStatementWithdraw = withdrawFromChecking(connection, preparedStatementWithdraw, new BigDecimal(100), 1);
            preparedStatementDeposit = depositIntoSaving(connection, preparedStatementDeposit, new BigDecimal(300), 1);

            //preparedStatementDeposit.executeBatch();
            //preparedStatementWithdraw.executeBatch();
            System.out.println("Account Modified!");
        }
        catch(ClassNotFoundException error)
        {
            System.out.println("Error: " + error.getMessage());
        }
        catch(SQLException error)
        {
            System.out.println("Error: " + error.getMessage());
        }
        finally
        {
            if(connection != null) try{connection.close();} catch(SQLException error) {}
            if(preparedStatementDeposit != null) try{preparedStatementDeposit.close();} catch(SQLException error) {}
        }
    }

    public static PreparedStatement withdrawFromChecking(Connection connection, PreparedStatement preparedStatement, BigDecimal balance, int id) throws SQLException
    {
        preparedStatement = connection.prepareStatement("UPDATE bankAccount SET checkingBalance = checkingBalance - ? WHERE id = ?");
        preparedStatement.setBigDecimal(1, balance);
        preparedStatement.setInt(2, id);
        preparedStatement.addBatch();

        return preparedStatement;
    }

    public static PreparedStatement depositIntoSaving(Connection connection, PreparedStatement preparedStatement, BigDecimal balance, int id) throws SQLException
    {
        preparedStatement = connection.prepareStatement("UPDATE bankAccount SET savingBalance = savingBalance + ? WHERE id = ?");
        preparedStatement.setBigDecimal(1, balance);
        preparedStatement.setInt(2, id);
        preparedStatement.addBatch();

        return preparedStatement;
    }
}
14
gmustudent

Vous ne pouvez pas exécuter deux instructions différentes dans un même lot. Comme @dan l’a mentionné, vous pouvez - et devez - les effectuer en une seule transaction.

Une autre option consiste à utiliser une procédure stockée qui peut tout faire en un seul aller-retour vers le serveur tout en conservant les avantages d'une transaction unique.

7
Miserable Variable

Vous pouvez essayer d'exécuter les deux instructions en une seule transaction, comme ceci:

connection.setAutoCommit(false);
try {
    stmt1.execute();
    stmt2.execute();
    connection.commit();
} catch (Exception ex) {
    connection.rollback();
}

Le problème est que addBatch fonctionne sur une seule instruction préparée, voir ceci est comment utiliser plusieurs instructions SQL avec addBatch.

9
dan

J'essaie d'utiliser des déclarations préparées et un lot! Je dis déclarations parce que je voudrais envoyer deux déclarations préparées dans un lot.

Lorsque vous parlez de PreparedStatement, un lot est associé au lot de commandes de cet objet PreparedStatement _ et PAS à l'inverse. Vous devriez regarder la méthode javadoc pour addBatch() pour en savoir plus à ce sujet.

Donc, dans votre cas, voici ce que j'aurais fait:

  • Créer une nouvelle transaction et définir une limite de lot
  • Création d'un ensemble de lots pour chaque PreparedStatement et incrémentation d'un compteur de lots
  • Exécuté le lot lorsque j'atteins la limite et réinitialise le compteur
  • Engagé ma transaction une fois que j'ai terminé

Donc, votre code ressemblerait à quelque chose comme ça:

preparedStatementWithdraw = connection.prepareStatement(....);
preparedStatementDeposit  = connection.prepareStatement(....);
boolean autoCommit        = connection.getAutoCommit();

int batchLimit = 1000; //limit that you can vary
int batchCounter = 0;
try{
    connection.setAutoCommit(false);

    //set the params and start adding your batch statements, as per your requirement, something like
    preparedStatementWithdraw.addBatch();
    preparedStatementDeposit.addBatch();
    batchCounter++;

    if(batchCounter == batchLimit){
        try{
            preparedStatementWithdraw.executeBatch();
            preparedStatementDeposit.executeBatch();
        }catch(Exception exe){
            //log your error
        }finally{
            preparedStatementWithdraw.clearBatch();
            preparedStatementDeposit.clearBatch();
            batchCounter = 0;
        }
    }
}finally{
        //process if any more statements are remaining in the batch
        try{
            preparedStatementWithdraw.executeBatch();
            preparedStatementDeposit.executeBatch();
        }catch(Exception exe){
            //log your error
        }finally{
            preparedStatementWithdraw.clearBatch();
            preparedStatementDeposit.clearBatch();
        }

    //1. depending on your requirement, commit/rollback the transation
    //2. Set autocommit to its original value
    connection.setAutoCommit(autoCommit);
    //3. Resoure management statements
}
2
Sujay

Je pense que vous voudrez peut-être fusionner vos requêtes de relevé et faire quelque chose comme ceci:

 String updateAccount= "UPDATE bankAccount 
                      SET if(? is not null ) 
                        then checkingBalance = checkingBalance - ? end if, 
                        if(? is not null ) 
                         then savingBalance = savingBalance + ? end if
                      WHERE id = ?";                
 PreparedStatement = dbConnection.prepareStatement(updateAccount);

 preparedStatement.setDouble(1, new Double(100));
 preparedStatement.setDouble(2, new Double(100));
 preparedStatement.setDouble(3, null);
 preparedStatement.setDouble(4, null);
 preparedStatement.setInt(5, 1);
 preparedStatement.addBatch();

 preparedStatement.setDouble(1, null);
 preparedStatement.setDouble(2, null);
 preparedStatement.setDouble(3, new Double(100));
 preparedStatement.setDouble(4, new Double(100));
 preparedStatement.setInt(5, 1);
 preparedStatement.addBatch();
 preparedStatement.executeBatch();

 dbConnection.commit();
0
Yogendra Singh