今天整理下Spring JDBC,相信不少的Java开发人员都有过使用JDBC API的经历,但是每一次的操作都需要获取链接,创建Statement,异常处理,最后释放资源,这样的工作乏味而枯燥的,好在Spring JDBC为我们提供了对JDBC API的轻量封装,这样我们就可以轻松的使用JDBC了.
Spring JDBC提供了JdbcTmplate用于完成JDBC操作,JdbcTmplate对JDBC API进行了封装,获取链接,创建Statement,异常处理,最后释放资源这些工作都交给了他帮我们处理,我们只需要编写SQL,然后执行SQL获取结果即可,同时JdbcTmplate中还提供了几个用于设置底层JDBC API的属性如下:
queryTimeout:用于设置JdbcTemplate所创建的Statement的最大查询超时时间,默认为0,即表示使用底层JDBC API的默认设置
fetchSize:设置底层的ResultSet每次冲数据库放回的行数,默认为0,即使用底层jdbc默认配置,这个属性和影响性能,设置过大,将大量在用内存,设置过小,从数据库读取次数将增加都很影响性能
ignoreWarnings:是否忽略SQL警告,默认true,当为false时,出现警告JdbcTmplate将抛出异常
JdbcTmplate的配置相对简单,只需要在Spring配置中向JdbcTmplate注入DataSource既可以获取JdbcTmplate进行操作,所以这里就不再介绍配置直接开始使用。
增删改操作都可以使用JdbcTemplate的 int update(String sql, Object[] params)执行,因为增删改操作都返回影响的行数,此方法还有很多的重载方法:
int update(String sql):为不带占位符的SQL语句提供方便
int update(String sql, Object[] params, int[] argTypes):除了占位符的入参数组外,后面的数组用于指定前面入参的类型,值为java.sql.Types类中的常量属性值
int update(String sql, PreparedStatementSetter pss):PreparedStatementSetter 是一个回调接口,当你希望可以自己为PreparedStatement设置时可以使用,例:
jdbcTemplate.update(sql, new PreparedStatementSetter() { public void setValues(PreparedStatement ps) throws SQLException { ps.setString(1, "test1"); ps.setString(2, "test2"); ps.setString(3, "test3"); } });
int update(PreparedStatementCreator psc):PreparedStatementCreator 也是一个回调接口,当你希望自己创建PreparedStatement时可以使用,例:
jdbcTemplate.update(new PreparedStatementCreator() { public PreparedStatement createPreparedStatement(Connection conn) throws SQLException { PreparedStatement ps = conn.preparedStatement(sql);//字符串sql必须是final的才能在内部类中使用 ps.setString(1, "test1"); ps.setString(2, "test2"); ps.setString(3, "test3"); return ps; } });
int update(PreparedStatementCreator psc,PreparedStatementSetter pss):双回调用法是上面两种的结合
我们经常会将表的主键设置成自增的,很多时候都会遇到插入一条数据后需要得到新插入数据的主键值得情况,通常我们会先执行insert语句后再去select出这个值,JDBC3.0中当新增记录时,允许将数据库自动产生的主键值绑定到Statement或者PrepareStatement中:
Statement可以使用int executeUpdate(String sql, int autoGeneratedKeys)
PrepareStatement可以在创建时设置使用Connection的PrepareStatement prepareStatement(String sql, int autoGeneratedKeys)方法
autoGeneratedKeys的值都应该设置为Statement.RETURN_GENERATED_KEYS,再执行SQL获取到ResultSet对象后,调用ResultSet对象的getInt()方法既可以获得自增主键值。
Spring利用这一技术,提供了一个可以返回新增记录对应主键值的方法:
int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder)
org.springframework.jdbc.support.KeyHolder是一个回调接口,Spring使用他保存返回的主键,该接口有如下方法:
Number getKey() throws InvalidDataAccessApiUsageException:当一次仅插入一条且主键为数字类型时使用此方法返回主键
Map<String, Object> getKeys() throws InvalidDataAccessApiUsageException:一次仅插入一条且是复合主键用这个方法key为列名,value为值
List<Map<String, Object>> getKeyList():当新增多条记录是用这个方法返回
上述方法使用实例:
...... KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(new PrepareStatementCreator() { public PreparedStatement createPreparedStatement(Connection conn) throws SQLException { PreparedStatement ps = conn.preparedStatement(sql);//字符串sql必须是final的才能在内部类中使用 ps.setString(1, "test1"); ps.setString(2, "test2"); ps.setString(3, "test3"); return ps; }, keyHolder); //之后使用keyHolder对象就可以获得自增的主键值了 int id = keyHolder.getKey().intValue();
一般情况下可以使用for循环执行SQL语句实现批量更改,但是这样做是效率低下的,因为底层代码没更改一次都需要获取连接创建Statement,执行SQL再释放资源,而Spring提供的int[] batchUpdate(String[] sql)方法只会连接一次然后将SQL批量的交个数据库,这样会效率更高,这个方法也有一个重载方法:
int[] batchUpdate(String sql, BatchPreparedStatementSetter pss)
例:
...... jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { public int getBatchSize() { //viewSpaces是PrepareStatement的传入参数List return viewSpaces.size(); } public void setValue(PreparedStatement ps, int index) throws SQLException { ViewSpace viewSpace = viewSpaces.get(index); ps.setString(1, viewSpace.getSapceName()); ...... } });