PreparedStatement'ı birden çok kez kullanmak


98

PreparedStatement'ın herhangi bir havuz olmadan tek bir ortak bağlantıyla kullanılması durumunda, hazırlanan ifadelerin gücünü koruyan her dml / sql işlemi için bir örnek oluşturabilir miyim?

Demek istediğim:

for (int i=0; i<1000; i++) {
    PreparedStatement preparedStatement = connection.prepareStatement(sql);
    preparedStatement.setObject(1, someValue);
    preparedStatement.executeQuery();
    preparedStatement.close();
}

onun yerine:

PreparedStatement preparedStatement = connection.prepareStatement(sql);
for (int i=0; i<1000; i++) {
    preparedStatement.clearParameters();
    preparedStatement.setObject(1, someValue);
    preparedStatement.executeQuery();
}
preparedStatement.close();

Sorum bu kodu çok iş parçacıklı bir ortama koymak istememden kaynaklanıyor, bana biraz tavsiye verebilir misiniz? Teşekkürler


yani sorgunuz sqldöngüde değişmiyor mu? bu sorgu döngünün her yinelemesi için değişmiyorsa, o zaman neden PreparedStatementher yineleme için yeni bir tane oluşturuyorsunuz (ilk kod parçacığında)? Bunu yapmak için herhangi bir sebep var mı?
Sabir Khan

diyelim ki sorgu değişiyorsa, ikinci yaklaşım hala daha iyidir, değil mi? Herhangi bir dezavantaj var mı?
Stunner

Yanıtlar:


146

İkinci yol biraz daha etkilidir, ancak çok daha iyi bir yol onları gruplar halinde yürütmektir:

public void executeBatch(List<Entity> entities) throws SQLException { 
    try (
        Connection connection = dataSource.getConnection();
        PreparedStatement statement = connection.prepareStatement(SQL);
    ) {
        for (Entity entity : entities) {
            statement.setObject(1, entity.getSomeProperty());
            // ...

            statement.addBatch();
        }

        statement.executeBatch();
    }
}

Bununla birlikte, aynı anda kaç grup yürütebileceğiniz JDBC sürücü uygulamasına bağımlısınız. Örneğin bunları her 1000 partide bir yürütmek isteyebilirsiniz:

public void executeBatch(List<Entity> entities) throws SQLException { 
    try (
        Connection connection = dataSource.getConnection();
        PreparedStatement statement = connection.prepareStatement(SQL);
    ) {
        int i = 0;

        for (Entity entity : entities) {
            statement.setObject(1, entity.getSomeProperty());
            // ...

            statement.addBatch();
            i++;

            if (i % 1000 == 0 || i == entities.size()) {
                statement.executeBatch(); // Execute every 1000 items.
            }
        }
    }
}

Çok iş parçacıklı ortamlarla ilgili olarak, bağlantı ve ifadeyi mümkün olan en kısa kapsamda aynı yöntem bloğu içinde, try-with-resources deyimini kullanarak normal JDBC deyimine göre alır ve kapatırsanız, bu konuda endişelenmenize gerek yoktur . parçacıkların üstünde.

Bu gruplar işlemsel ise, bağlantının otomatik taahhüdünü kapatmak ve işlemi yalnızca tüm gruplar bittiğinde uygulamak istersiniz. Aksi takdirde, ilk grup başarılı olduğunda ve daha sonra başarısız olduğunda kirli bir veritabanına neden olabilir.

public void executeBatch(List<Entity> entities) throws SQLException { 
    try (Connection connection = dataSource.getConnection()) {
        connection.setAutoCommit(false);

        try (PreparedStatement statement = connection.prepareStatement(SQL)) {
            // ...

            try {
                connection.commit();
            } catch (SQLException e) {
                connection.rollback();
                throw e;
            }
        }
    }
}

inside the same method block- Her iş parçacığının kendi yığını olacağını ve bu bağlantı ve ifadelerin bir taraftan yığın halinde olduğunu ve başka bir veri kaynağından gelen her yeni executeFunction (== her iş parçacığı) çağrısına ayrı bağlantı örneği vereceğini söylüyorsunuz. Seni doğru anlıyor
muyum

İlk yöntemi yapıyorum ancak SQL profilerinde izleme yaparken bir yerine birden çok hazırlanmış ifadenin tekrarlandığını görüyorum. Neden birden çok ifade gösterdiğini anlayamadım. yardım gerekli.
haydut delikanlı

Cevabınız, sorgu döngüde değişmediği sürece iyidir. Ya sorgu değişiyorsa, örneğin, benim durumumda sorgu değiştirildiğinde .. Yine de ikinci yaklaşımın daha iyi olduğunu varsayıyorum. lütfen doğrulayın
Stunner

13

Kodunuzdaki döngü yalnızca aşırı basitleştirilmiş bir örnektir, değil mi?

PreparedStatementYalnızca bir kez oluşturmak ve döngü içinde tekrar tekrar kullanmak daha iyi olacaktır .

Bunun mümkün olmadığı durumlarda (program akışını çok karmaşıklaştırdığı için), PreparedStatementyalnızca bir kez kullansanız bile a kullanmak yararlıdır , çünkü işin sunucu tarafı (SQL'i ayrıştırmak ve yürütmeyi planı), yine de azaltılacaktır.

Java tarafını yeniden kullanmak istediğiniz durumu ele almak için PreparedStatement, bazı JDBC sürücülerinin (Oracle gibi) bir önbelleğe alma özelliği vardır: PreparedStatementAynı bağlantıda aynı SQL için bir tane oluşturursanız, size aynı ) örnek.

Çoklu iş parçacığı hakkında: JDBC bağlantılarının zaten birden çok iş parçacığı arasında paylaşılabileceğini (yani birden çok iş parçacığı tarafından aynı anda kullanılabileceğini) düşünmüyorum. Her iş parçacığı havuzdan kendi bağlantısını almalı, kullanmalı ve tekrar havuza döndürmelidir.


1
Aslında bağlantının kendi özel iş parçacığı vardır ve her deyim içinde çalıştırılır, ancak bu iş parçacığına açık bir hazırlanmış ifadeler yığını aracılığıyla erişirim. Bu nedenle, diğer eşzamanlı iş parçacıkları başlangıçta yalnızca hazırlanmış tüm ifadeleri oluşturmak için gereken parametreleri geçirirler, ancak daha sonra aynı anda parametreleri değiştirebilirler
Steel Plume
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.