传统JDBC SQL调用形式一般为
update customer set customerName=?, email=? where id=?
insert into customer (customerName, email ) values(?, ?)
这种由于?与参数关系的不直观,带来的修改bug以及维护麻烦折磨着后续程序猿。那么,有没有可能通过对代码的改造,实现类似于命名参数SQL支持呢?
update customer set customerName=:customerName, email=:email where id=:id
insert into customer (customerName, email ) values(:customerName, :email)
答案是肯定的, 本文通过对 NamedParameterJdbcTemplate 实现机制源码的解读,借鉴了NamedParameterUtils 源码的方法对上面需求的实现做了可行性验证。
关键代码
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.TreeMap;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterUtils;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
/**
*
* 将namedParamSQL转换为带参数列表的传统SQL执行
*
* @author 00fly
* @version [版本号, 2018年11月10日]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class ConvertSQLTest
{
private static final Logger logger = LoggerFactory.getLogger(ConvertSQLTest.class);
private static QueryRunner queryRunner;
static
{
MysqlDataSource dataSource = new MysqlDataSource();
ResourceBundle config = ResourceBundle.getBundle("jdbc");
dataSource.setUrl(config.getString("jdbc.url"));
dataSource.setUser(config.getString("jdbc.username"));
dataSource.setPassword(config.getString("jdbc.password"));
queryRunner = new QueryRunner(dataSource);
logger.info("QueryRunner = {}", queryRunner);
}
@Test
public void test1()
throws SQLException
{
// 将namedParamSQL转换为带参数列表的传统SQL
String namedParamSQL = "select id, name from student where id<>:id and (id=:id1 or id=:id2)";
Map paramMap = new TreeMap<>();
paramMap.put("id", 1);
paramMap.put("id1", 2);
paramMap.put("id2", 3);
paramMap.put("name", "001");
paramMap.put("name1", "002");
paramMap.put("name2", "003");
String realSql = buildRealSQL(namedParamSQL, paramMap);
Object[] paramArr = buildValueArray(namedParamSQL, paramMap);
List
运行结果
2018-11-10 13:33:24 |INFO |main|★★★★ before: namedParamSQL = select id, name from student where id<>:id and (id=:id1 or id=:id2)|
2018-11-10 13:33:24 |INFO |main|★★★★ before: paramMap = {id=1, id1=2, id2=3, name=001, name1=002, name2=003}|
2018-11-10 13:33:24 |INFO |main|★★★★ execute: realSql = select id, name from student where id<>? and (id=? or id=?)|
2018-11-10 13:33:24 |INFO |main|★★★★ execute: paramArr = [1, 2, 3]|
2018-11-10 13:33:24 |INFO |main|★★★★ execute: result = [{id=2, name=Phil}, {id=3, name=Jenny}]|
2018-11-10 13:33:24 |INFO |main|★★★★ before: namedParamSQL = select id, name from student where id in (:ids)|
2018-11-10 13:33:24 |INFO |main|★★★★ before: paramMap = {ids=[1, 2, 3, 4, 5]}|
2018-11-10 13:33:24 |INFO |main|★★★★ execute: realSql = select id, name from student where id in (?, ?, ?, ?, ?)|
2018-11-10 13:33:24 |INFO |main|★★★★ execute: paramArr = [1, 2, 3, 4, 5]|
2018-11-10 13:33:24 |INFO |main|★★★★ execute: result = [{id=1, name=Jack}, {id=2, name=Phil}, {id=3, name=Jenny}]|
2018-11-10 13:33:24 |INFO |main|★★★★ before: namedParamSQL = select id, name from student where id=:id or id in (:ids)|
2018-11-10 13:33:24 |INFO |main|★★★★ before: paramMap = {id=1, ids=[1, 2, 3, 4, 5]}|
2018-11-10 13:33:24 |INFO |main|★★★★ execute: realSql = select id, name from student where id=? or id in (?, ?, ?, ?, ?)|
2018-11-10 13:33:24 |INFO |main|★★★★ execute: paramArr = [1, 1, 2, 3, 4, 5]|
2018-11-10 13:33:24 |INFO |main|★★★★ execute: result = [{id=1, name=Jack}, {id=2, name=Phil}, {id=3, name=Jenny}]|
完整的项目代码请参考:
https://gitee.com/00fly/java-code-frame/tree/master/jdbc