简体   繁体   中英

JDBCTemplate optional parameters

I am using spring JDBCTemplate.


I have a scenario, where the parameters that need to be passed into my query function, are conditional/optional. For example, I have the following code:

List<RealTimeDTO> result = jdbcTemplate.query(sql, new Object[] {custId, 
number, requestType, startDate, endDate}, new CCCRowMapper());

In the code, I passed in custId, number, requestType, etc. However, requestType is an optional parameter that may come back as null or empty so I don't want it to be passed into the Object[] if it is either null or empty .

What can I do to handle this type of situation?

I could introduce logic where I only pass in the parameters I want into the Object[] , however, I was wondering if there is an already built in functionality that handles this instead of me reinventing the wheel.

One option is to use NamedParameterJdbcTemplate , so the parameter "list" (now a Map ) doesn't need to be modified, only the SQL does:

List<RealTimeDTO> query(String name) {
    NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);

    String sql = "SELECT foo, bar" +
                  " FROM FooBar" +
                 " WHERE name" + (name == null ? " IS NULL" : "= :name");
    Map<String, Object> params = new HashMap<>();
    params.put("name", name);
    return jdbcTemplate.query(sql, params, new CCCRowMapper());
}

UPDATE

If you have many conditions that may need to be skipped, and all conditions might be eliminated, then use a StringJoiner to build the WHERE clause:

List<RealTimeDTO> query(String name, String phone, int age) {
    NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);

    StringJoiner where = new StringJoiner(" AND ", " WHERE ", "").setEmptyValue("");
    if (name != null)
        where.add("name = :name");
    if (phone != null)
        where.add("phone = :phone");
    if (age != 0)
        where.add("age = :age");
    String sql = "SELECT foo, bar" +
                  " FROM FooBar" +
                  where;
    Map<String, Object> params = new HashMap<>();
    params.put("name", name);
    params.put("phone", phone);
    params.put("age", age);
    return jdbcTemplate.query(sql, params, new CCCRowMapper());
}

I'd like to add NamedParameter to @Snozzlebert' answer with the next example.

You have to specify the parameters' type if you want to pass null values otherwise you will get a NullPointerException.

@Autowired
NamedParameterJdbcTemplate namedJdbcTemplate;



MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("name", name, Types.VARCHAR);
parameters.addValue("phone", null, Types.VARCHAR);
parameters.addValue("age", null, Types.SMALLINT);

List<RealTimeDTO> list = namedJdbcTemplate.query(
        "SELECT foo, bar\n" +
          " FROM FooBar\n" +
         " WHERE (:name IS NULL OR name = :name) AND \n" +
         " (:phone IS NULL OR phone = :phone) AND \n" +
         " (:age IS NULL OR age = :age)" +,
        parameters,
        new RealTimeDTOMapper());

You can use a static SQL by checking the condition like ? IS NULL OR name = ? ? IS NULL OR name = ? . But you have to pass the argument twice AND pass the argument type ( at.sql.Types ) twice.

String sql = "SELECT foo, bar" +
              " FROM FooBar" +
             " WHERE (? IS NULL OR name = ?) ";
jdbcTemplate.query(sql, new Object[]{name, name}, new int[]{Types.VARCHAR, Types.VARCHAR}, new CCCRowMapper());

IMO not really better than using conditions.

To improve an existing answer, Keep a static query with only bind parameters. Don't 'build' a sql to avoid the pitfall of caching issues and sql injection.

List<RealTimeDTO> query(String name, String phone, int age) {
    NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);

    String sql = "SELECT foo, bar FROM FooBar" +
                 " WHERE (:name IS NULL OR name = :name)" +
                 " AND (:phone IS NULL OR phone = :phone)" +
                 " AND (:age = 0 OR age = :age)";
    params.put("name", name);
    params.put("phone", phone);
    params.put("age", age);
    return jdbcTemplate.query(sql, params, new CCCRowMapper());
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM