时隔三个多月, 我终于想起我还有个博客, 其实也不是忘了我这个博客, 只是平时工作繁忙没时间去写博客, 故今晚腾出时间来记录一下上次工作中遇到的一个问题, 给园友们分享出来, 以免入坑.
上个星期在工作中使用 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;
- View Code
实体类和表映射的 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();
- List<Integer> idList = Arrays.asList(1, 2, 3);
- String name = "mybatis 从入门到精通";
- List<TBook> bookList = bookDAO.selectByDynamicParams(idList, name);
- return respJson.putPOJO("data",bookList);
- }
- }
- View Code
- @Component("bookDAO")
- public class BookDAOImpl implements BookDAO {
- @Autowired
- private JdbcTemplate jdbcTemplate;
- @Override
- public List<TBook> selectByDynamicParams(List<Integer> idList, String name) {
- StringBuffer sql = new StringBuffer();
- sql.append("select * from t_book where id in (");
- // 拼装?
- List<String> 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);
- }
- }
- View Code
好了, 执行一把, 看一下结果吧, 访问 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 List<TBook> selectByDynamicParams(List<Integer> idList, String name) {
- String sql = "select * from t_book where id in (:idList) and name = :bookName";
- // 集合中的 key 一定要与 sql 中定义的参数变量相同, 这里的集合里的参数不需要进行手动处理, 直接将集合作为一个参数对象传进去即可
- Map<String,Object> 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 一样坑, 只能说技术这种东西学无止境呀.
革命尚未成功, 同志仍需努力!
来源: https://www.cnblogs.com/maolinjava/p/10743522.html