Datenbankabfragen mit Spring aus dem Java Quellcode auslagern
Wer Spring JDBC verwendet, kennt das Problem: längere Datenbankabfragen können nur umständlich im Java Quellcode untergebracht werden. Meist werden solche Abfragen über einen StringBuilder, einen StringJoiner oder die seit Java 8 zur Verfügung stehende String join Methode zusammengesetzt. Man kann sich jedoch das Properties System von Spring zu nutze machen, um Datenbankabfragen aus dem Quellcode auszulagern.
Als Basis für den Artikel dient die folgende (eigentlich in eine Zeile passende) Abfrage:
SELECT *
FROM users
WHERE username = :username
Im Java Quellcode wird die Abfrage z.B. wie folgt hinterlegt:
package de.patrickgotthard.springjdbc;
import java.util.Collections;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.EmptySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class UserDAO {
private final NamedParameterJdbcTemplate jdbc;
@Autowired
public UserDAO(final NamedParameterJdbcTemplate jdbc) {
this.jdbc = jdbc;
}
public User getUser(String username) {
// @formatter:off
final String sql = String.join(" ",
"SELECT *",
"FROM users",
"WHERE username = :username");
// @formatter:on
final Map<String, Object> params = Collections.singletonMap("username", username);
return this.jdbc.queryForObject(sql, params, new BeanPropertyRowMapper<>(User.class));
}
}
Statt die Abfrage wie oben dargestellt im Quellcode zu hinterlegen, wird sie in eine XML basierte Properties Datei ausgelagert:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="getUserQuery">
SELECT *
FROM users
WHERE username = :username
</entry>
</properties>
Unter der Annahme, dass diese Properties Datei als UserDAO.xml auf oberster Ebene im classpath liegt, wird die Abfrage nun wie folgt eingebunden:
package de.patrickgotthard.springjdbc;
import java.util.Collections;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
@PropertySource("UserDAO.xml")
public class UserDAO {
private final NamedParameterJdbcTemplate jdbc;
@Value("${getUserQuery}")
private String getUserQuery;
@Autowired
public UserDAO(final NamedParameterJdbcTemplate jdbc) {
this.jdbc = jdbc;
}
public User getUser(String username) {
final Map<String, Object> params = Collections.singletonMap("username", username);
return this.jdbc.queryForObject(this.getUserQuery, params, new BeanPropertyRowMapper<>(User.class));
}
}
Der große Vorteil dieser Methode ist vor allem die Lesbarkeit, aber auch dass Abfragen unkompliziert zwischen Datenbank Editor und der XML Datei ausgetauscht werden können. Das gilt natürlich nur solange die Abfragen weitestgehend statisch sind. Müssen Abfragen dynamisch aufgebaut werden (z.B. Suchabfragen mit variierenden Suchkriterien), empfehle ich den Einsatz anderer Frameworks wie z.B. MyBatis oder Hibernate ORM.