Spring系列第42篇:玩转JdbcTemplate

//1.创建数据源DataSource

DataSource dataSource = DataSourceUtils.getDataSource();

//2.创建JdbcTemplate,new JdbcTemplate(dataSource)

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

//3.调用JdbcTemplate的方法操作db,如增删改查

List<Map<String, Object>> maps = jdbcTemplate.queryForList(“select * from t_user”);

System.out.println(maps);

}

输出

[{id=114, name=路人}, {id=115, name=java高并发}, {id=116, name=spring系列}]

t_user表数据

mysql> select id,name from t_user;

±----±--------------+

| id  | name          |

±----±--------------+

| 114 | 路人          |

| 115 | java高并发    |

| 116 | spring系列    |

±----±--------------+

3 rows in set (0.00 sec)

上面查询返回了t_user表所有的记录,返回了一个集合,集合中是一个Map,Map表示一行记录,key为列名,value为列对应的值。

有没有感觉到特别的方便,只需要jdbcTemplate.queryForList("select * from t_user")这么简单的一行代码,数据就被获取到了。

下面我们继续探索更强大更好用的功能。

增加、删除、修改操作


JdbcTemplate中以update开头的方法,用来执行增、删、改操作,下面来看几个常用的。

无参情况

Api

int update(final String sql)

案例

@Test

public void test1() {

DataSource dataSource = DataSourceUtils.getDataSource();

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

int updateRows = jdbcTemplate.update(“INSERT INTO t_user (name) VALUE (‘maven系列’)”);

System.out.println(“影响行数:” + updateRows);

}

有参情况1

Api

int update(String sql, Object… args)

案例

sql中使用?作为占位符。

@Test

public void test2() {

DataSource dataSource = DataSourceUtils.getDataSource();

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

int updateRows = jdbcTemplate.update(“INSERT INTO t_user (name) VALUE (?)”, “mybatis系列”);

System.out.println(“影响行数:” + updateRows);

}

有参情况2

Api

int update(String sql, PreparedStatementSetter pss)

通过PreparedStatementSetter来设置参数,是个函数式接口,内部有个setValues方法会传递一个PreparedStatement参数,我们可以通这个参数手动的设置参数的值。

案例

@Test

public void test3() {

DataSource dataSource = DataSourceUtils.getDataSource();

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

int updateRows = jdbcTemplate.update(“INSERT INTO t_user (name) VALUE (?)”, new PreparedStatementSetter() {

@Override

public void setValues(PreparedStatement ps) throws SQLException {

ps.setString(1, “mysql系列”);

}

});

System.out.println(“影响行数:” + updateRows);

}

获取自增列的值


Api

public int update(final PreparedStatementCreator psc, final KeyHolder generatedKeyHolder)

案例

@Test

public void test4() {

DataSource dataSource = DataSourceUtils.getDataSource();

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

String sql = “INSERT INTO t_user (name) VALUE (?)”;

KeyHolder keyHolder = new GeneratedKeyHolder();

int rowCount = jdbcTemplate.update(new PreparedStatementCreator() {

@Override

public PreparedStatement createPreparedStatement(Connection con) throws SQLException {

//手动创建PreparedStatement,注意第二个参数:Statement.RETURN_GENERATED_KEYS

PreparedStatement ps = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);

ps.setString(1, “获取自增列的值”);

return ps;

}

}, keyHolder);

System.out.println(“新记录id:” + keyHolder.getKey().intValue());

}

输出

新记录id:122

mysql> select id,name from t_user;

±----±----------------------+

| id | name |

±----±----------------------+

| 114 | 路人 |

| 115 | java高并发 |

| 116 | spring系列 |

| 117 | maven系列 |

| 118 | mysql系列 |

| 122 | 获取自增列的值 |

±----±----------------------+

6 rows in set (0.00 sec)

批量增删改操作


Api

int[] batchUpdate(final String[] sql);

int[] batchUpdate(String sql, List<Object[]> batchArgs);

int[] batchUpdate(String sql, List<Object[]> batchArgs, int[] argTypes);

案例

@Test

public void test5() {

DataSource dataSource = DataSourceUtils.getDataSource();

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

List<Object[]> list = Arrays.asList(

new Object[]{“刘德华”},

new Object[]{“郭富城”},

new Object[]{“张学友”},

new Object[]{“黎明”});

int[] updateRows = jdbcTemplate.batchUpdate(“INSERT INTO t_user (name) VALUE (?)”, list);

for (int updateRow : updateRows) {

System.out.println(updateRow);

}

}

查询操作


查询一列单行

Api

/**

  • sql:执行的sql,如果有参数,参数占位符?

  • requiredType:返回的一列数据对应的java类型,如String

  • args:?占位符对应的参数列表

**/

 T queryForObject(String sql, Class requiredType, @Nullable Object… args)

案例

@Test

public void test6() {

DataSource dataSource = DataSourceUtils.getDataSource();

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

String name = jdbcTemplate.queryForObject(“select name from t_user where id = ?”, String.class, 114);

System.out.println(name);

}

输出

路人

db中对应数据

mysql> select name from t_user where id = 114;

±-------+

| name   |

±-------+

| 路人   |

±-------+

1 row in set (0.00 sec)

使用注意

若queryForObject中sql查询无结果时,会报错

如id为0的记录不存在

mysql> select name from t_user where id = 0;

Empty set (0.00 sec)

@Test

public void test7() {

DataSource dataSource = DataSourceUtils.getDataSource();

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

String name = jdbcTemplate.queryForObject(“select name from t_user where id = ?”, String.class, 0);

System.out.println(name);

}

运行,会弹出一个异常EmptyResultDataAccessException,期望返回一条记录,但实际上却没有找到记录,和期望结果不符,所以报错了

org.springframework.dao.EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0

at org.springframework.dao.support.DataAccessUtils.nullableSingleResult(DataAccessUtils.java:97)

at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:784)

这种如何解决呢,需要用到查询多行的方式来解决了,即下面要说到的queryForList相关的方法,无结果的时候会返回一个空的List,我们可以在这个空的List上面做文章。

查询一列多行

Api

以queryForList开头的方法。

 List queryForList(String sql, Class elementType);

 List queryForList(String sql, Class elementType, @Nullable Object… args);

 List queryForList(String sql, Object[] args, Class elementType);

 List queryForList(String sql, Object[] args, int[] argTypes, Class elementType);

注意:

上面这个T虽然是泛型,但是只支持Integer.class String.class 这种单数据类型的,自己定义的Bean不支持。(所以用来查询单列数据)

elementType:查询结果需要转换为哪种类型?如String、Integer、Double。

案例

@Test

public void test8() {

DataSource dataSource = DataSourceUtils.getDataSource();

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

// List queryForList(String sql, Class elementType);

List list1 = jdbcTemplate.queryForList(“select name from t_user where id>131”, String.class);

System.out.println(“list1:” + list1);

// List queryForList(String sql, Class elementType, @Nullable Object… args);

List list2 = jdbcTemplate.queryForList(“select name from t_user where id>?”, String.class, 131);

System.out.println(“list2:” + list2);

// List queryForList(String sql, Object[] args, Class elementType);

List list3 = jdbcTemplate.queryForList(“select name from t_user where id>?”, new Object[]{131}, String.class);

System.out.println(“list3:” + list3);

// List queryForList(String sql, Object[] args, int[] argTypes, Class elementType);

List list4 = jdbcTemplate.queryForList(“select name from t_user where id>?”, new Object[]{131}, new int[]{java.sql.Types.INTEGER}, String.class);

System.out.println(“list4:” + list4);

}

输出

list1:[郭富城, 张学友, 黎明]

list2:[郭富城, 张学友, 黎明]

list3:[郭富城, 张学友, 黎明]

list4:[郭富城, 张学友, 黎明]

sql结果:

mysql> select name from t_user where id>131;

±----------+

| name      |

±----------+

| 郭富城    |

| 张学友    |

| 黎明      |

±----------+

3 rows in set (0.00 sec)

查询单行记录,将记录转换成一个对象

Api

 T queryForObject(String sql, RowMapper rowMapper);

 T queryForObject(String sql, Object[] args, RowMapper rowMapper);

 T queryForObject(String sql, Object[] args, int[] argTypes, RowMapper rowMapper);

 T queryForObject(String sql, RowMapper rowMapper, Object… args);

上面这些方法的参数中都有一个rowMapper参数,行映射器,可以将当前行的结果映射为一个自定义的对象。

@FunctionalInterface

public interface RowMapper {

/**

* @param ResultSet 结果集

* @param 当前结果集的第几行

* @return 当前行的结果对象,将当前行的结果映射为一个自定义的对象返回

*/

@Nullable

T mapRow(ResultSet rs, int rowNum) throws SQLException;

}

JdbcTemplate内部会遍历ResultSet,然后循环调用RowMapper#mapRow,得到当前行的结果,将其丢到List中返回,如下:

List results = new ArrayList<>();

int rowNum = 0;

while (rs.next()) {

results.add(this.rowMapper.mapRow(rs, rowNum++));

}

return results;

案例

@Getter

@Setter

@NoArgsConstructor

@AllArgsConstructor

@ToString

public class User {

private Integer id;

private String name;

}

@Test

public void test9() {

DataSource dataSource = DataSourceUtils.getDataSource();

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

String sql = “select id,name from t_user where id = ?”;

//查询id为34的用户信息

User user = jdbcTemplate.queryForObject(sql, new RowMapper() {

@Nullable

@Override

public User mapRow(ResultSet rs, int rowNum) throws SQLException {

User user = new User();

user.setId(rs.getInt(1));

user.setName(rs.getString(1));

return user;

}

}, 134);

System.out.println(user);

}

输出

User(id=134, name=134)

使用注意

当queryForObject中sql查询无结果的时候,会报错,必须要返回一行记录

查询单行记录,返回指定的javabean

RowMapper 有个实现了类 BeanPropertyRowMapper,可以将结果映射为javabean。

@Test

public void test10() {

DataSource dataSource = DataSourceUtils.getDataSource();

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

String sql = “select id,name from t_user where id = ?”;

//查询id为34的用户信息

RowMapper rowMapper = new BeanPropertyRowMapper<>(User.class);

User user = jdbcTemplate.queryForObject(sql, rowMapper, 134);

System.out.println(user);

}

查询多列多行,每行结果为一个Map

Api

List<Map<String, Object>> queryForList(String sql);

List<Map<String, Object>> queryForList(String sql, Object… args);

每行结果为一个Map,key为列名小写,value为列对应的值。

案例

@Test

public void test11() {

DataSource dataSource = DataSourceUtils.getDataSource();

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

String sql = “select id,name from t_user where id>?”;

List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql, 130);

System.out.println(maps);

}

输出

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

面试前的“练手”还是很重要的,所以开始面试之前一定要准备好啊,不然也是耽搁面试官和自己的时间。

我自己是刷了不少面试题的,所以在面试过程中才能够做到心中有数,基本上会清楚面试过程中会问到哪些知识点,高频题又有哪些,所以刷题是面试前期准备过程中非常重要的一点。

面试题及解析总结

三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经

大厂面试场景

三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经

知识点总结

三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-BmTEO54s-1713339003023)]

[外链图片转存中…(img-vJbkmxl3-1713339003023)]

[外链图片转存中…(img-ysPavFWq-1713339003024)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

面试前的“练手”还是很重要的,所以开始面试之前一定要准备好啊,不然也是耽搁面试官和自己的时间。

我自己是刷了不少面试题的,所以在面试过程中才能够做到心中有数,基本上会清楚面试过程中会问到哪些知识点,高频题又有哪些,所以刷题是面试前期准备过程中非常重要的一点。

面试题及解析总结

[外链图片转存中…(img-NbljaiVH-1713339003024)]

大厂面试场景

[外链图片转存中…(img-E0pBT1i0-1713339003025)]

知识点总结

[外链图片转存中…(img-82Oh4VeC-1713339003025)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值