前面介绍了 JdbcTemplate 的插入数据和查询数据,占用 CURD 中的两项,本文则将主要介绍数据更新和删除。从基本使用上来看,姿势和前面的没啥两样
<!– more –>
I. 环境准备
环境依然借助前面一篇的配置,链接如:190407-SpringBoot 高级篇 JdbcTemplate 之数据插入使用姿势详解
或者直接查看项目源码:https://github.com/liuyueyi/spring-boot-demo/blob/master/spring-boot/101-jdbctemplate
我们查询所用数据,正是前面一篇插入的结果,如下图
II. 更新使用说明
对于数据更新,这里会分为两种进行说明,单个和批量;这个单个并不是指只能一条记录,主要针对的是 sql 的数量而言
1. update 方式
看过第一篇数据插入的童鞋,应该也能发现,新增数据也是用的这个方法,下面会介绍三种不同的使用姿势
先提供一个数据查询的转换方法,用于对比数据更新前后的结果
private MoneyPO queryById(int id) {
return jdbcTemplate.queryForObject("select id, `name`, money, is_deleted as isDeleted, unix_timestamp(create_at) as" +
"created, unix_timestamp(update_at) as updated from money where id=?",
new BeanPropertyRowMapper<>(MoneyPO.class), id);
}
a. 纯 sql 更新
这个属于最基本的方式了,前面几篇博文中大量使用了,传入一条完整的 sql,执行即可
int id = 10;
// 最基本的 sql 更新
String sql = "update money set money=money + 999 where id =" + id;
int ans = jdbcTemplate.update(sql);
System.out.println("basic update:" + ans + "| db:" + queryById(id));
b. 占位 sql
问好占位,实际内容通过参数传递方式
// 占位方式
sql = "update money set money=money + ? where id = ?";
ans = jdbcTemplate.update(sql, 888, id);
System.out.println("placeholder update:" + ans + "| db:" + queryById(id));
c. statement
从前面的几篇文章中可以看出,使用 statement 的方式,最大的好处有几点
- 可以点对点的设置填充参数
-
PreparedStatementCreator
方式可以获取 db 连接,主动设置各种参数
下面给出两个常见的使用方式
// 通过 PreparedStatementCreator 方式更新
ans = jdbcTemplate.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
// 设置自动提交,设置 100ms 的超时,这种方式最大的好处是可以控制 db 连接的参数
try {connection.setAutoCommit(true);
connection.setNetworkTimeout(Executors.newSingleThreadExecutor(), 10);
PreparedStatement statement =
connection.prepareStatement("update money set money=money + ? where id" + "= ?");
statement.setInt(1, 777);
statement.setInt(2, id);
return statement;
} catch (Exception e) {e.printStackTrace();
return null;
}
}
});
System.out.println("statementCreator update:" + ans + "| db:" + queryById(id));
// 通过 PreparedStatementSetter 来设置占位参数值
ans = jdbcTemplate.update(sql, new PreparedStatementSetter() {
@Override
public void setValues(PreparedStatement preparedStatement) throws SQLException {preparedStatement.setInt(1, 666);
preparedStatement.setInt(2, id);
}
});
System.out.println("statementSetter update:" + ans + "| db:" + queryById(id));
注意下第一种调用中,设置了超时时间,下面给出一个动图,演示超时的使用姿势
在上图中,
- 首先是一个开启一个事物,并修改了一条记录,这个时候这条记录会加上写锁
- 然后 JdbcTemplate 中修改上面的这条记录,尝试加写锁,但是会失败,所以一直阻塞,当超时之后,抛出异常
2. batchUpdate 方式
批量方式,执行多个 sql,从使用上看和前面没有太大的区别,先给出一个查询的通用方法
private List<MoneyPO> queryByIds(List<Integer> ids) {StringBuilder strIds = new StringBuilder();
for (Integer id : ids) {strIds.append(id).append(",");
}
return jdbcTemplate.query("select id, `name`, money, is_deleted as isDeleted, unix_timestamp(create_at) as" +
"created, unix_timestamp(update_at) as updated from money where id in (" +
strIds.substring(0, strIds.length() - 1) + ")", new BeanPropertyRowMapper<>(MoneyPO.class));
}
a. 纯 sql 更新
// 批量修改,// 执行多条 sql 的场景
int[] ans = jdbcTemplate
.batchUpdate("update money set money=1300 where id =10", "update money set money=1300 where id = 11");
System.out.println("batch update by sql ans:" + Arrays.asList(ans) + "| db:" + queryByIds(Arrays.asList(10, 11)));
b. 占位 sql
// 占位替换方式
ans = jdbcTemplate.batchUpdate("update money set money=money + ? where id = ?",
Arrays.asList(new Object[]{99, 10}, new Object[]{99, 11}));
System.out.println("batch update by placeHolder ans:" + Arrays.asList(ans) + "| db:" +
queryByIds(Arrays.asList(10, 11)));
c. statement
// 通过 statement
ans = jdbcTemplate
.batchUpdate("update money set money=money + ? where id = ?", new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement preparedStatement, int i) throws SQLException {preparedStatement.setInt(1, 99);
preparedStatement.setInt(2, i + 10);
}
@Override
public int getBatchSize() {return 2;}
});
System.out.println("batch update by statement ans:" + Arrays.asList(ans) + "| db:" + queryByIds(Arrays.asList(10, 11)));
注意下上面的方法中,getBatchSize
返回实际的 sql 条数,setValues
中的 i 从 0 开始
3. 测试
原始数据中,money 都是 300,通过一系列的修改,输出如下
III. 数据删除
删除的操作姿势和上面基本一样,也就是 sql 的写法不同罢了,因此没有太大的必要重新写一篇,下面给出一个简单的 demo
@Component
public class DeleteService {
@Autowired
private JdbcTemplate jdbcTemplate;
public void delete() {int ans = jdbcTemplate.update("delete from money where id = 13");
System.out.println("delete:" + ans);
}
}
IV. 其他
相关博文
- 190407-SpringBoot 高级篇 JdbcTemplate 之数据插入使用姿势详解
- 190412-SpringBoot 高级篇 JdbcTemplate 之数据查询上篇
- 190417-SpringBoot 高级篇 JdbcTemplate 之数据查询下篇
- 工程:https://github.com/liuyueyi/spring-boot-demo
- 项目:https://github.com/liuyueyi/spring-boot-demo/blob/master/spring-boot/101-jdbctemplate
2. 声明
尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现 bug 或者有更好的建议,欢迎批评指正,不吝感激
- 一灰灰 Blog 个人博客 https://blog.hhui.top
- 一灰灰 Blog-Spring 专题博客 http://spring.hhui.top
- 微博地址: 小灰灰 Blog
- QQ:一灰灰 /3302797840