首页
学习
活动
专区
圈层
工具
发布
30 篇文章
1
Spring Boot2 系列教程(二)创建 Spring Boot 项目的三种方式
2
Spring Boot2 系列教程(三)理解 spring-boot-starter-parent
3
Spring Boot2 系列教程(五)Spring Boot中的 yaml 配置
4
Spring Boot2 系列教程(六)自定义 Spring Boot 中的 starter
5
Spring Boot2 系列教程(七)理解自动化配置的原理
6
Spring Boot2 系列教程(八)Spring Boot 中配置 Https
7
Spring Boot2 系列教程(九)Spring Boot 整合 Thymeleaf
8
Spring Boot2 系列教程(十九)Spring Boot 整合 JdbcTemplate
9
Spring Boot2 系列教程(十八)Spring Boot 中自定义 SpringMVC 配置
10
Spring Boot2 系列教程(十七)SpringBoot 整合 Swagger2
11
Spring Boot2 系列教程(十六)定时任务的两种实现方式
12
Spring Boot2 系列教程(十五)定义系统启动任务的两种方式
13
Spring Boot2 系列教程(十三)Spring Boot 中的全局异常处理
14
Spring Boot2 系列教程(十一)Spring Boot 中的静态资源配置
15
Spring Boot2 系列教程(十二)@ControllerAdvice 的三种使用场景
16
Spring Boot2 系列教程(十四)CORS 解决跨域问题
17
Spring Boot2 系列教程(十)Spring Boot 整合 Freemarker
18
Spring Boot2 系列教程(二十八)Spring Boot 整合 Session 共享
19
Spring Boot2 系列教程(二十九)Spring Boot 整合 Redis
20
Spring Boot2 系列教程(二十七)Nginx 极简扫盲入门
21
Spring Boot2 系列教程(二十六)Spring Boot 整合 Redis
22
Spring Boot2 系列教程(二十二)整合 MyBatis 多数据源
23
Spring Boot2 系列教程(二十一)整合 MyBatis
24
Spring Boot2 系列教程(二十)Spring Boot 整合JdbcTemplate 多数据源
25
Spring Boot2 系列教程(三十七)Spring Security 整合 JWT
26
Spring Boot2 系列教程(三十六)SpringSecurity 中角色继承的坑
27
Spring Boot2 系列教程(三十五)SpringSecurity 使用 JSON 格式登录
28
Spring Boot2 系列教程(三十四)Spring Security 添加验证码
29
Spring Boot2 系列教程(三十三)整合 Spring Security
30
Spring Boot2 系列教程(三十一)Spring Boot 构建 RESTful 风格应用

Spring Boot2 系列教程(十九)Spring Boot 整合 JdbcTemplate

在 Java 领域,数据持久化有几个常见的方案,有 Spring 自带的 JdbcTemplate 、有 MyBatis,还有 JPA,在这些方案中,最简单的就是 Spring 自带的 JdbcTemplate 了,这个东西虽然没有 MyBatis 那么方便,但是比起最开始的 Jdbc 已经强了很多了,它没有 MyBatis 功能那么强大,当然也意味着它的使用比较简单,事实上,JdbcTemplate 算是最简单的数据持久化方案了,本文就和大伙来说说这个东西的使用。

1. 基本配置

JdbcTemplate 基本用法实际上很简单,开发者在创建一个 SpringBoot 项目时,除了选择基本的 Web 依赖,再记得选上 Jdbc 依赖,以及数据库驱动依赖即可,如下:

项目创建成功之后,记得添加 Druid 数据库连接池依赖(注意这里可以添加专门为 Spring Boot 打造的 druid-spring-boot-starter,而不是我们一般在 SSM 中添加的 Druid),所有添加的依赖如下:

代码语言:javascript
复制
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.27</version>
    <scope>runtime</scope>
</dependency>

项目创建完后,接下来只需要在 application.properties 中提供数据的基本配置即可,如下:

代码语言:javascript
复制
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.username=root
spring.datasource.password=123
spring.datasource.url=jdbc:mysql:///test01?useUnicode=true&characterEncoding=UTF-8

如此之后,所有的配置就算完成了,接下来就可以直接使用 JdbcTemplate 了?咋这么方便呢?其实这就是 SpringBoot 的自动化配置带来的好处,我们先说用法,一会来说原理。

2. 基本用法

首先我们来创建一个 User Bean,如下:

代码语言:javascript
复制
public class User {
    private Long id;
    private String username;
    private String address;
    //省略getter/setter
}

然后来创建一个 UserService 类,在 UserService 类中注入 JdbcTemplate ,如下:

代码语言:javascript
复制
@Service
public class UserService {
    @Autowired
    JdbcTemplate jdbcTemplate;
}

好了,如此之后,准备工作就算完成了。

2.1 增

JdbcTemplate 中,除了查询有几个 API 之外,增删改统一都使用 update 来操作,自己来传入 SQL 即可。例如添加数据,方法如下:

代码语言:javascript
复制
public int addUser(User user) {
    return jdbcTemplate.update("insert into user (username,address) values (?,?);", user.getUsername(), user.getAddress());
}

update 方法的返回值就是 SQL 执行受影响的行数。

这里只需要传入 SQL 即可,如果你的需求比较复杂,例如在数据插入的过程中希望实现主键回填,那么可以使用 PreparedStatementCreator,如下:

代码语言:javascript
复制
public int addUser2(User user) {
    KeyHolder keyHolder = new GeneratedKeyHolder();
    int update = jdbcTemplate.update(new PreparedStatementCreator() {
        @Override
        public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
            PreparedStatement ps = connection.prepareStatement("insert into user (username,address) values (?,?);", Statement.RETURN_GENERATED_KEYS);
            ps.setString(1, user.getUsername());
            ps.setString(2, user.getAddress());
            return ps;
        }
    }, keyHolder);
    user.setId(keyHolder.getKey().longValue());
    System.out.println(user);
    return update;
}

实际上这里就相当于完全使用了 JDBC 中的解决方案了,首先在构建 PreparedStatement 时传入 Statement.RETURN_GENERATED_KEYS,然后传入 KeyHolder,最终从 KeyHolder 中获取刚刚插入数据的 id 保存到 user 对象的 id 属性中去。

你能想到的 JDBC 的用法,在这里都能实现,Spring 提供的 JdbcTemplate 虽然不如 MyBatis,但是比起 Jdbc 还是要方便很多的。

2.2 删

删除也是使用 update API,传入你的 SQL 即可:

代码语言:javascript
复制
public int deleteUserById(Long id) {
    return jdbcTemplate.update("delete from user where id=?", id);
}

当然你也可以使用 PreparedStatementCreator。

2.3 改

代码语言:javascript
复制
public int updateUserById(User user) {
    return jdbcTemplate.update("update user set username=?,address=? where id=?", user.getUsername(), user.getAddress(),user.getId());
}

当然你也可以使用 PreparedStatementCreator。

2.4 查

查询的话,稍微有点变化,这里主要向大伙介绍 query 方法,例如查询所有用户:

代码语言:javascript
复制
public List<User> getAllUsers() {
    return jdbcTemplate.query("select * from user", new RowMapper<User>() {
        @Override
        public User mapRow(ResultSet resultSet, int i) throws SQLException {
            String username = resultSet.getString("username");
            String address = resultSet.getString("address");
            long id = resultSet.getLong("id");
            User user = new User();
            user.setAddress(address);
            user.setUsername(username);
            user.setId(id);
            return user;
        }
    });
}

查询的时候需要提供一个 RowMapper,就是需要自己手动映射,将数据库中的字段和对象的属性一一对应起来,这样。。。。嗯看起来有点麻烦,实际上,如果数据库中的字段和对象属性的名字一模一样的话,有另外一个简单的方案,如下:

代码语言:javascript
复制
public List<User> getAllUsers2() {
    return jdbcTemplate.query("select * from user", new BeanPropertyRowMapper<>(User.class));
}

至于查询时候传参也是使用占位符,这个和前文的一致,这里不再赘述。

2.5 其他

除了这些基本用法之外,JdbcTemplate 也支持其他用法,例如调用存储过程等,这些都比较容易,而且和 Jdbc 本身都比较相似,这里也就不做介绍了,有兴趣可以留言讨论。

3. 原理分析

那么在 SpringBoot 中,配置完数据库基本信息之后,就有了一个 JdbcTemplate 了,这个东西是从哪里来的呢?源码在 org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration 类中,该类源码如下:

代码语言:javascript
复制
@Configuration
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(JdbcProperties.class)
public class JdbcTemplateAutoConfiguration {
	@Configuration
	static class JdbcTemplateConfiguration {
		private final DataSource dataSource;
		private final JdbcProperties properties;
		JdbcTemplateConfiguration(DataSource dataSource, JdbcProperties properties) {
			this.dataSource = dataSource;
			this.properties = properties;
		}
		@Bean
		@Primary
		@ConditionalOnMissingBean(JdbcOperations.class)
		public JdbcTemplate jdbcTemplate() {
			JdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSource);
			JdbcProperties.Template template = this.properties.getTemplate();
			jdbcTemplate.setFetchSize(template.getFetchSize());
			jdbcTemplate.setMaxRows(template.getMaxRows());
			if (template.getQueryTimeout() != null) {
				jdbcTemplate
						.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
			}
			return jdbcTemplate;
		}
	}
	@Configuration
	@Import(JdbcTemplateConfiguration.class)
	static class NamedParameterJdbcTemplateConfiguration {
		@Bean
		@Primary
		@ConditionalOnSingleCandidate(JdbcTemplate.class)
		@ConditionalOnMissingBean(NamedParameterJdbcOperations.class)
		public NamedParameterJdbcTemplate namedParameterJdbcTemplate(
				JdbcTemplate jdbcTemplate) {
			return new NamedParameterJdbcTemplate(jdbcTemplate);
		}
	}
}

从这个类中,大致可以看出,当当前类路径下存在 DataSource 和 JdbcTemplate 时,该类就会被自动配置,jdbcTemplate 方法则表示,如果开发者没有自己提供一个 JdbcOperations 的实例的话,系统就自动配置一个 JdbcTemplate Bean(JdbcTemplate 是 JdbcOperations 接口的一个实现)。好了,不知道大伙有没有收获呢?

下一篇
举报
领券