2010-06-07 12 views
19

Ich verwende die JDBC-Vorlage und möchte mithilfe vorbereiteter Anweisungen aus einer Datenbank lesen. Ich iteriere über viele Zeilen in einer .csv-Datei, und in jeder Zeile führe ich einige SQL-Select-Abfragen mit entsprechenden Werten aus.Verwenden vorbereiteter Anweisungen mit JDBCTemplate

Ich möchte mein Lesen aus der Datenbank beschleunigen, aber ich weiß nicht, wie die JDBC-Vorlage mit vorbereiteten Anweisungen arbeiten soll.

Es gibt die PreparedStatementCreator und die PreparedStatementSetter. Wie in this example werden beide mit anonymen inneren Klassen erstellt. Aber innerhalb der PreparedStatementSetter-Klasse habe ich 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 String hart codieren, weil ich sie nicht kenne. Ich kann sie auch nicht an den PreparedStatementSetter übergeben, weil es keine Argumente für den Konstruktor gibt. Und meine Werte auf final zu setzen wäre auch dumm.

Ich war es gewohnt, vorbereitete Aussagen zu erstellen, die ziemlich einfach sind. 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.

Antwort

2

Ich habe eine Select-Anweisung jetzt mit einer PreparedStatement versucht, aber es stellte sich heraus, dass es nicht schneller als die Jdbc Vorlage war. Vielleicht, wie Mezmo vorgeschlagen hat, erstellt es automatisch vorbereitete Aussagen.

Wie auch immer, der Grund für meine sql SELECT s so langsam war ein anderer. In der WHERE Klausel habe ich immer den Operator LIKE verwendet, als ich nur eine exakte Übereinstimmung finden wollte. Wie ich herausgefunden habe LIKE sucht nach einem Muster und ist daher ziemlich langsam.

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

9

Versuchen Sie 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; 
    } 
}; 
+0

Das würde funktionieren, aber die Werte, die ich festlegen möchte, liegen außerhalb der inneren anonymen Klasse. Innerhalb der Klasse sollte etwas wie 'updateSales.setString (2, fileRow.getName())' sein, aber ich kann nicht auf 'fileRow' Formular innerhalb der Klasse zugreifen. –

+6

markieren Sie die var fileRow als final – Inv3r53

3

Ich würde die vorbereitete Anweisung zumindest auf ein Verfahren der Handhabung ausklammern. In diesem Fall, da es keine Ergebnisse gibt, ist es ziemlich einfach (und unter der Annahme, dass die Verbindung eine Instanzvariable ist, 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"); 

Welche ist ziemlich einfach mit anderen Dingen zu integrieren, ja? Und wenn Sie die Methode mehrmals aufrufen, wird das Update nur einmal erstellt und das macht die Dinge viel schneller. Nun, vorausgesetzt, Sie machen keine verrückten Dinge wie jede Aktualisierung in einer eigenen Transaktion ...

Beachten Sie, dass die Typen festgelegt sind. Dies liegt daran, dass sie für eine bestimmte Abfrage/Aktualisierung sollten behoben werden, damit die Datenbank ihre Arbeit effizient erledigen kann. Wenn Sie nur willkürliche Zeichenfolgen aus einer CSV-Datei ziehen, übergeben Sie sie als Zeichenfolgen. Es gibt auch keine Verriegelung; viel besser, einzelne Verbindungen stattdessen aus einem einzigen Thread zu verwenden.

+0

Für Abfragen, die einen einzelnen Wert zurückgeben, ist es ziemlich einfach, diese Technik auch zu verwenden. Die Hauptkomplexität ergibt sich, wenn Sie Abfragen haben, die viele Werte zurückgeben. Entweder gibt man ein 'ResultSet 'zurück oder gibt einen Callback zurück, der jede zurückgegebene Zeile behandelt (wobei natürlich die Werte aus dem' ResultSet 'herausgebrochen werden). –

+1

Sorry, aber ich weiß nicht, was das mit meinem JDBC Template Problem zu tun hat. Ich kann keine jdbc-Vorlagenabfrage mit einem PreparedStatement einspeisen. Es scheint, dass ich einen 'PreparedStatementCreator' oder einen' PreparedStatementSetter' benötige. –

24

Standardmäßig verwendet die JDBCTemplate intern PreparedStatement, wenn Sie einfach das Formular .update(String sql, Object ... args) verwenden. Spring und Ihre Datenbank verwalten die kompilierte Abfrage für Sie, sodass Sie sich nicht um das Öffnen, Schließen, Ressourcenschutz usw. kümmern müssen. Eine der erlösenden Gnaden von Spring. A link to Spring 2.5's documentation on this. Hoffe es macht die Dinge klarer. Auch das Zwischenspeichern von Anweisungen kann auf der JDBC-Ebene erfolgen, wie im Fall von at least some of Oracle's JDBC drivers. . Das wird viel ausführlicher, als ich kompetent gehen kann.

+3

Aber ich möchte eine Auswahl auf der Datenbank durchführen, kein Update. Im Frühjahr wird unter http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/jdbc/core/JdbcTemplate.html geschrieben, dass mit 'update' nur ein Einfügen, Aktualisieren oder Löschen erfolgt kann durchgeführt werden. –

+0

@ user3211068 gibt es eine 'query' Methode, die Sie für wählen können – linqu

+1

@mezmo würden Sie etwas dagegen tun, eine Quelle für Ihre Aussage hinzuzufügen? Und gilt das Gleiche für die Abfrage (String sql, ...)? – leo

14
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); 
    } 
} 
+0

der Abfrageteil als Java 8 Lambda-Stil: 'jdbcTemplate.query (sql, ps -> ps.setString (1," Wert "), (rs, ich) -> rs.getLong (1)' –

Verwandte Themen