Spring Boot集成SQL数据库1

从银行的交易数据到打车订单,衣食住行,都离不开数据库的存储。

在接下来的两个小节中,我们将通过3种不同的技术,在Spring Boot中集成MySQL数据库。

  • JDBC

  • MyBatis

  • JPA (Hibernate)

本节的前半部分,我们将通过Docker快速搭建MySQL的环境,随后介绍JDBC的集成方式。

搭建MySQL实验环境

本书的重点是讨论微服务实战,我们直接使用Docker的方式,快速搭建实验环境。

如果你想部署在生产环境,请参考官方部署文档

首先,请确认已经成功安装了Docker:

  1. docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

若尚未安装Docker,可以参考官方文档)。

MySQL的Docker运行脚本如下:

  1. #!/bin/bash
  2. NAME="mysql"
  3. PUID="1000"
  4. PGID="1000"
  5. VOLUME="$HOME/docker_data/mysql"
  6. MYSQL_ROOT_PASS="123456"
  7. mkdir -p $VOLUME
  8. docker ps -q -a --filter "name=$NAME" | xargs -I {} docker rm -f {}
  9. docker run \
  10. --hostname $NAME \
  11. --name $NAME \
  12. --volume "$VOLUME":/var/lib/mysql \
  13. --env MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASS \
  14. --env PUID=$PUID \
  15. --env PGID=$PGID \
  16. -p 3306:3306 \
  17. --detach \
  18. --restart always \
  19. mysql:8.0

如脚本所述:

  • 使用官方的8.0镜像启动Docker

  • 退出后自动重启

  • 暴露3306端口到本机

  • 设置Volume盘到~/docker_data/mysql路径下

  • root密码123456(请务必更改为安全密码)

执行后的效果:

  1. docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. feb2838197a6 mysql:8.0 "docker-entrypoint.s…" 46 hours ago Up 7 hours 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql

启动成功后,我们尝试连接数据库,新建库并授权给用户:

  1. mysql -h 127.0.0.1 -u root -p
  2. > CREATE DATABASE homs_demo;
  3. > CREATE USER 'HomsDemo'@'%' identified by '123456';
  4. > GRANT ALL PRIVILEGES ON homs_demo.* TO 'HomsDemo'@'%';

尝试用新用户登录:

  1. mysql -h 127.0.0.1 -u HomsDemo -p homs_demo

若能成功登录,我们创建本书实验所需的表:

  1. CREATE TABLE `users` (
  2. `id` bigint NOT NULL AUTO_INCREMENT,
  3. `name` varchar(64) NOT NULL,
  4. PRIMARY KEY (`id`)
  5. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

这里我们创建了表users,有两个列:id和name。

温馨提示:我们使用utf8mb4字符集,如果用utf8是会有坑,可以参考这篇文章)。强烈推荐你对所有的数据表,都设置为utf8mb4。

Spring Boot 集成 JDBC操作MySQL

我们先通过集成jdbc的方式操作MySQL数据库。

首先在server项目的build.gradle中添加依赖

  1. implementation 'org.springframework.boot:spring-boot-starter-jdbc'
  2. implementation 'mysql:mysql-connector-java:8.0.20'

上述依赖中:

  • spring-boot-starter-jdbc是集成jdbc的starter依赖包

  • mysql-connector-java是集成MySQL的驱动

接着,我们配置下数据源:

  1. spring.datasource:
  2. url: jdbc:mysql://127.0.0.1:3306/homs_demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false
  3. username: HomsDemo
  4. password: 123456
  5. hikari:
  6. minimumIdle: 10
  7. maximumPoolSize: 100

上述配置分为两部分:

  • spring.datasource.url / username / password定义了MySQL的访问链接

  • hikari是数据库连接池的配置。

Hikari是Spring Boot 2默认的链接池,官方性能评测优秀。这里我们配置了minimumIdle(最小连接数)和maximumPoolSize(最大连接数)两个选项。更多配置参数可以参考官方文档)。

经过上述的组合配置后,对应DataSource对应的Configuration会自动激活,并注册一系列的关联Bean。

下面让我们使用它访问MySQL数据库:

  1. @Repository
  2. public class UserRepository1Impl implements UserRepository {
  3. @Autowired
  4. protected NamedParameterJdbcTemplate db;
  5. private static RowMapper<User> ROW_MAPPER = new BeanPropertyRowMapper<>(User.class);
  6. @Override
  7. public Optional<Long> create(User user) {
  8. String sql = "INSERT INTO `users`(`name`) VALUES(:name)";
  9. SqlParameterSource param = new MapSqlParameterSource("name", user.getName());
  10. KeyHolder holder = new GeneratedKeyHolder();
  11. if (db.update(sql, param, holder) > 0) {
  12. return Optional.ofNullable(holder.getKey().longValue());
  13. } else {
  14. return Optional.empty();
  15. }
  16. }
  17. @Override
  18. public Optional<User> getUser(long id) {
  19. String sql = "SELECT * FROM `users` WHERE `id` = :id";
  20. SqlParameterSource param = new MapSqlParameterSource("id", id);
  21. try {
  22. return Optional.ofNullable(db.queryForObject(sql, param, ROW_MAPPER));
  23. } catch (EmptyResultDataAccessException e) {
  24. return Optional.empty();
  25. }
  26. }
  27. @Override
  28. public Optional<User> getUserByName(String name) {
  29. String sql = "SELECT * FROM `users` WHERE `name` = :name";
  30. SqlParameterSource param = new MapSqlParameterSource("name", name);
  31. try {
  32. return Optional.ofNullable(db.queryForObject(sql, param, ROW_MAPPER));
  33. } catch (EmptyResultDataAccessException e) {
  34. return Optional.empty();
  35. }
  36. }
  37. }

在上面的代码中,我们自动装配了”NamedParameterJdbcTemplate”,然后用它访问MySQL数据库:

  • 读请求使用db.query,配合RowMapper做类型转化

  • 写请求使用db.update,配合KeyHolder获取自增主键

使用JDBC访问MySQL的方式,优点和缺点是完全一样的:使用显示的SQL语句操作数据库。

优点:直接、方便代码Review和性能检查

缺点:SQL编写过程繁琐、易错,特别是对于CRUD请求,效率较低