时隔三个多月,我终于想起我还有个博客,其实也不是忘了我这个博客,只是平时工作繁忙没时间去写博客,故今晚腾出时间来记录一下上次工作中遇到的一个问题,给园友们分享出来,以免入坑。
上个星期在工作中使用JdbcTemplate执行了一个select * from table where id in (?,?,?) and name = ? 的SQL,这个SQL大家都明白什么意思吧,然后我得给这几个 "?" 赋值,没问题吧。可是在执行的时候给我报了一个异常:java.sql.SQLException: No value specified for parameter 3 纳尼?这就有点奇怪了,几个意思?是因为jdbcTemplate这个对象不支持括号内的问号和括号外的问号同时出现,什么意思呢?就是说 where id in (?) 是正确的 where name = ? 也是正确的,但是 where id in (?) and name = ? 就不支持了;需要将 jdbcTemplate 对象换成 NamedParameterJdbcTemplate 即可,下面我会把代码贴出来,首先创建一个SpringBoot项目,将Web,MySQL,Jdbc,Lombok的依赖导入进去,然后我们开始撸代码:
我们先来看一下数据库的数据:
下面是建表语句,有需要的同志们可以复制过去:
CREATE TABLE `t_book` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `isbn` varchar(255) DEFAULT NULL, `publish` varchar(255) DEFAULT NULL, `publisher` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
实体类和表映射的RowMapper实现类的代码就不贴了,按照表字段去建一个就可以了,这一步跳过
下面是controller和dao的代码:
@RestController @RequestMapping("/api/v1/book") public class BookRestController { @Resource private ObjectMapper jsonMapper; // 这里为了方便就省略service层,直接将dao注入进来了 @Resource private BookDAO bookDAO; @GetMapping("/list") public JsonNode list(){ ObjectNode respJson = jsonMapper.createObjectNode(); ListidList = Arrays.asList(1, 2, 3); String name = "mybatis从入门到精通"; List bookList = bookDAO.selectByDynamicParams(idList, name); return respJson.putPOJO("data",bookList); } }
@Component("bookDAO") public class BookDAOImpl implements BookDAO { @Autowired private JdbcTemplate jdbcTemplate; @Override public ListselectByDynamicParams(List idList, String name) { StringBuffer sql = new StringBuffer(); sql.append("select * from t_book where id in ( "); // 拼装? List stringList = new ArrayList<>(); for (int i = 0;i < idList.size();i++){ stringList.add("?"); } sql.append(String.join(",",stringList)); sql.append(" ) and name = ?"); System.err.println(sql.toString()); return jdbcTemplate.query(sql.toString(),new BookMapper(),idList,name); } }
好了,执行一把,看一下结果吧,访问 localhost:8080/api/v1/book/list ,控制台保如下错误:
可以看出来,SQL语句的没有问题的,那么我们尝试换一种写法,使用 NamedParameterJdbcTemplate ,由于spring默认是加载jdbcTemplate的,所以NamedParameterJdbcTemplate 对象需要我们自己去配置,创建一个配置类或者直接在启动类配置也可以,启动类其实就是一个配置类,进行如下配置:
// 从容器中将dataSource这个对象注入进来 @Autowired private DataSource dataSource; @Bean public NamedParameterJdbcTemplate namedParameterJdbcTemplate(){ // 要构造NamedParameterJdbcTemplate对象需要依赖dataSource return new NamedParameterJdbcTemplate(dataSource); }
dao层将NamedParameterJdbcTemplate 对象注入进来并执行SQL:
@Component("bookDAO") public class BookDAOImpl implements BookDAO { @Autowired private JdbcTemplate jdbcTemplate; @Autowired private NamedParameterJdbcTemplate namedParameterJdbcTemplate; @Override public ListselectByDynamicParams(List idList, String name) { String sql = "select * from t_book where id in (:idList) and name = :bookName"; // 集合中的key一定要与sql中定义的参数变量相同,这里的集合里的参数不需要进行手动处理,直接将集合作为一个参数对象传进去即可 Map params = new HashMap<>(2); params.put("idList",idList); params.put("bookName",name); return namedParameterJdbcTemplate.query(sql,params,new BookMapper()); } }
这次再执行一把看一下结果:
这次就执行成功了,控制台也没有报错,很舒服,我记得以前使用原生jdbc进行查询的时候当时使用的是sqlserver数据库,写了一条分页的SQL,当时也是有问号的,同样会报错,没想到spring的这个jdbc跟原生的jdbc一样坑,只能说技术这种东西学无止境呀。
革命尚未成功,同志仍需努力!