webentwicklung-frage-antwort-db.com.de

Vorbereitete Anweisungen mit JDBCTemplate verwenden

Ich verwende die JDBC-Vorlage und möchte mit vorbereiteten Anweisungen aus einer Datenbank lesen. Ich durchlaufe viele Zeilen in einer CSV-Datei und führe in jeder Zeile einige SQL-Auswahlabfragen mit entsprechenden Werten aus.

Ich möchte das Lesen aus der Datenbank beschleunigen, weiß aber nicht, wie ich die JDBC-Vorlage zum Arbeiten mit vorbereiteten Anweisungen bringen kann.

Es gibt den PreparedStatementCreator und den PreparedStatementSetter . Wie in dieses Beispiel werden beide mit anonymen inneren Klassen erstellt. In der PreparedStatementSetter-Klasse habe ich jedoch keinen Zugriff auf die Werte, die ich in der vorbereiteten Anweisung festlegen möchte.

Da ich eine CSV-Datei durchlaufe, kann ich sie nicht als Zeichenfolge fest codieren, da ich sie nicht kenne. Ich kann sie auch nicht an den PreparedStatementSetter übergeben, da es keine Argumente für den Konstruktor gibt. Und meine Werte auf final zu setzen, wäre auch dumm.

Ich war es gewohnt, dass vorbereitete Aussagen ziemlich einfach waren. Etwas wie

PreparedStatement updateSales = con.prepareStatement(
    "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
updateSales.setInt(1, 75); 
updateSales.setString(2, "Colombian"); 
updateSales.executeUpdate():

wie in diesem Java-Tutorial .

26
user321068

Ich habe jetzt eine select-Anweisung mit einem PreparedStatement ausprobiert, aber es stellte sich heraus, dass sie nicht schneller als die Jdbc-Vorlage war. Vielleicht werden, wie von Mezmo vorgeschlagen, automatisch vorbereitete Anweisungen erstellt.

Wie auch immer, der Grund dafür, dass mein SQL SELECT so langsam ist, war ein anderer. In der WHERE - Klausel habe ich immer den Operator LIKE verwendet, wenn ich nur eine genaue Übereinstimmung finden wollte. Wie ich herausgefunden habe, sucht LIKE nach einem Muster und ist daher ziemlich langsam.

Ich benutze den Operator = jetzt und es ist viel schneller.

2
user321068

Standardmäßig macht das JDBCTemplate intern sein eigenes PreparedStatement, wenn Sie nur das .update(String sql, Object ... args) -Formular verwenden. Spring und Ihre Datenbank verwalten die kompilierte Abfrage für Sie, sodass Sie sich nicht um das Öffnen, Schließen, den Ressourcenschutz usw. kümmern müssen. Ein Link zu Spring 2.5s Dokumentation dazu. Ich hoffe, es macht die Dinge klarer. Das Cachen von Anweisungen kann auch auf JDBC-Ebene erfolgen, wie im Fall von zumindest einigen der JDBC-Treiber von Oracle. Das wird viel detaillierter sein, als ich es kompetent kann.

28
mezmo
class Main {
    public static void main(String args[]) throws Exception {
        ApplicationContext ac = new
          ClassPathXmlApplicationContext("context.xml", Main.class);
        DataSource dataSource = (DataSource) ac.getBean("dataSource");
// DataSource mysqlDataSource = (DataSource) ac.getBean("mysqlDataSource");

        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

        String prasobhName = 
        jdbcTemplate.query(
           "select first_name from customer where last_name like ?",
            new PreparedStatementSetter() {
              public void setValues(PreparedStatement preparedStatement) throws
                SQLException {
                  preparedStatement.setString(1, "nair%");
              }
            }, 
            new ResultSetExtractor<Long>() {
              public Long extractData(ResultSet resultSet) throws SQLException,
                DataAccessException {
                  if (resultSet.next()) {
                      return resultSet.getLong(1);
                  }
                  return null;
              }
            }
        );
        System.out.println(machaceksName);
    }
}
19
Prasobh.K

Versuche Folgendes:

PreparedStatementCreator creator = new PreparedStatementCreator() {
    @Override
    public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
        PreparedStatement updateSales = con.prepareStatement(
        "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
        updateSales.setInt(1, 75); 
        updateSales.setString(2, "Colombian"); 
        return updateSales;
    }
};
10
Kevin

Ich würde die vorbereitete Anweisungsbehandlung zumindest auf eine Methode reduzieren. In diesem Fall ist es ziemlich einfach, da es keine Ergebnisse gibt (und vorausgesetzt, die Verbindung ist eine Instanzvariable, die sich nicht ändert):

private PreparedStatement updateSales;
public void updateSales(int sales, String cof_name) throws SQLException {
    if (updateSales == null) {
        updateSales = con.prepareStatement(
            "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ?");
    }
    updateSales.setInt(1, sales);
    updateSales.setString(2, cof_name);
    updateSales.executeUpdate();
}

An diesem Punkt ist es dann nur eine Frage des Aufrufs:

updateSales(75, "Colombian");

Was ist ziemlich einfach in andere Dinge zu integrieren, ja? Und wenn Sie die Methode mehrmals aufrufen, wird das Update nur einmal erstellt, was die Dinge viel schneller macht. Angenommen, Sie machen keine verrückten Dinge wie das Ausführen jedes Updates in einer eigenen Transaktion ...

Beachten Sie, dass die Typen festgelegt sind. Dies liegt daran, dass für bestimmte Abfragen/Aktualisierungen sollte behoben werden, damit die Datenbank ihre Arbeit effizient ausführen kann. Wenn Sie nur beliebige Zeichenfolgen aus einer CSV-Datei ziehen, übergeben Sie sie als Zeichenfolgen. Es gibt auch keine Verriegelung; Vielmehr ist es besser, einzelne Verbindungen von einem einzigen Thread aus zu verwenden.

3
Donal Fellows