時隔三個多月,我終於想起我還有個博客,其實也不是忘了我這個博客,只是平時工作繁忙沒時間去寫博客,故今晚騰出時間來記錄一下上次工作中遇到的一個問題,給園友們分享出來,以免入坑。 上個星期在工作中使用JdbcTemplate執行了一個select * from table where id in (?, ...
時隔三個多月,我終於想起我還有個博客,其實也不是忘了我這個博客,只是平時工作繁忙沒時間去寫博客,故今晚騰出時間來記錄一下上次工作中遇到的一個問題,給園友們分享出來,以免入坑。
上個星期在工作中使用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一樣坑,只能說技術這種東西學無止境呀。
革命尚未成功,同志仍需努力!