Close

Spring - Subclasses of SqlQuery

[Last Updated: Apr 6, 2017]

In the last tutorial we saw how to use SqlQuery as reusable compiled sql object. In this tutorial we are going to quickly explore the subclasses of SqlQuery.

java.lang.ObjectObjectorg.springframework.jdbc.object.RdbmsOperationRdbmsOperationorg.springframework.jdbc.object.SqlOperationSqlOperationorg.springframework.jdbc.object.SqlQuerySqlQueryorg.springframework.jdbc.object.MappingSqlQueryWithParametersMappingSqlQueryWithParametersorg.springframework.jdbc.object.GenericSqlQueryGenericSqlQueryorg.springframework.jdbc.object.UpdatableSqlQueryUpdatableSqlQueryorg.springframework.jdbc.object.MappingSqlQueryMappingSqlQueryorg.springframework.jdbc.object.SqlFunctionSqlFunctionLogicBig

Using GenericSqlQuery

Generic Sql Query is a concrete subclass of SqlQuery. Functionally, it achieves the same outcome as SqlQuery. We would prefer to use it in situations where a RowMapper is easier to pass to a setter method rather than subclassing SqlQuery class and overriding newRowMapper(..) method.

Following code demonstrates how to use GenericSqlQuery:

public class GenericSqlQueryExample {
  @Autowired
  private DataSource dataSource;
  private SqlQuery<Person> personSqlQuery;

  @PostConstruct
  private void postConstruct() {
      GenericSqlQuery<Person> genericSqlQuery = new GenericSqlQuery<>();
      genericSqlQuery.setDataSource(dataSource);
      genericSqlQuery.setSql("select * from Person where id = ?");
      genericSqlQuery.setRowMapper(createPersonRowMapper());
      genericSqlQuery.declareParameter(new SqlParameterValue(Types.BIGINT, "id"));
      this.personSqlQuery = genericSqlQuery;
  }

  private RowMapper<Person> createPersonRowMapper() {
      return (rs, rowNum) -> {
          Person person = new Person();
          person.setId(rs.getLong("ID"));
          person.setFirstName(rs.getString("FIRST_NAME"));
          person.setLastName(rs.getString("LAST_NAME"));
          person.setAddress(rs.getString("ADDRESS"));
          return person;
      };
  }

  public void runExample() {
      Person person1 = Person.create("Dana", "Whitley", "464 Gorsuch Drive");
      Person person2 = Person.create("Robin", "Cash", "64 Zella Park");
      savePersons(new Person[]{person1, person2});
      Person person = loadPersonById(1);
      System.out.printf("Person loaded: %s%n", person);
      person = loadPersonById(2);
      System.out.printf("Person loaded: %s%n", person);
  }

  public Person loadPersonById(long id) {
      List<Person> persons = personSqlQuery.execute(id);
      if (persons.size() == 1) {
          return persons.get(0);
      }
      return null;
  }
    .............
}

Check out the complete code example here.

Using MappingSqlQueryWithParameters

This is also a direct subclass of SqlQuery but it is abstract. This class provides a specialized abstract method:

protected abstract T mapRow(ResultSet rs, int rowNum,
                            Object[] parameters, Map<?,?> context)
                                                       throws SQLException

The main difference with SqlQuery is, we don't have to create a RowMapper, but need to work with ResultSet directly. Check out a complete example here.

Using MappingSqlQuery

Mapping Sql Query is a subclass of Mapping Sql Query With Parameters. This class replaces a new abstract mapRow(..) method, which simplifies the things by dropping parameters and context.

protected abstract T mapRow(ResultSet rs, int rowNum)
                                           throws SQLException

Check out a complete example here.

Using SqlFunction

This is a concrete subclass which can be used to call SQL functions that return a single value result.

public class SqlFunctionExample {

  @Autowired
  private DataSource dataSource;
  private SqlFunction sqlFunction;

  @PostConstruct
  private void postConstruct() {
      this.sqlFunction =
              new SqlFunction<>(dataSource, "select CURRENT_DATE()");
  }

  public void runExample() {
      Object result = sqlFunction.runGeneric();
      System.out.println(result);
  }
}

Note that we are using H2 database specific function CURRENT_DATE(). Check out the complete example here

Using UpdatableSqlQuery

The abstract class UpdatableSqlQuery can be subclassed and can be used to update rows. We have to work with ResultSet#updateXYZ(..) methods.

public class PersonUpdatableSqlQuery extends UpdatableSqlQuery<Person> {

  public PersonUpdatableSqlQuery(DataSource dataSource, String sql) {
      super(dataSource, sql);
  }

  @Override
  protected Person updateRow(ResultSet resultSet, int rowNum, Map<?, ?> context) throws SQLException {

      Person person = UpdatableSqlQueryExample.toPerson(resultSet);
      if (person.getId() == 1) {
          resultSet.updateString("ADDRESS", "XYZ");
      }
      return null;
  }
}

Complete example here.

See Also