从零开始 Spring Boot 3:数据库

从零开始 Spring Boot 3:数据库

spring boot

图源:简书 (jianshu.com)

上篇文章从零开始 Spring Boot 2:处理请求 - 魔芋红茶’s blog (icexmoon.cn)介绍了如何接收和处理HTTP请求,这篇文章将介绍如何连接数据库,并通过数据库来存储和读取数据。

准备工作

在介绍使用Spring Boot框架使用数据库前,需要先有一个数据库才行,这里推荐使用MySQL。其安装方式是多种多样的,我是通过XAMPP安装的,相关内容可以阅读PHP开发环境(XAMPP+XDebug+VSCode)搭建 - 魔芋红茶’s blog (icexmoon.cn)。

还推荐安装一个数据库客户端,这样操作和查看数据库更方便,对于MySQL,我一直使用的是SQLyog。可以通过下边的连接下载安装一个:

  • tools/我的软件列表_image.md at main · icexmoon/tools (github.com)

下面示例会使用一个user表,这里给出DDL语句:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(10) NOT NULL COMMENT '姓名',
  `age` int(11) NOT NULL COMMENT '年龄',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1

数据库名称我使用的是test

下面我们将一步步在上篇文章那个简单Web应用的基础上添加上对数据库的支持。

可以从learn_spring_boot获取上篇文章的Web应用示例代码。

数据库配置

首先我们需要在Maven配置中添加对JDBC和MySQL的支持。其中JDBC是一个在数据库驱动之上的抽象层,Java可以通过JDBC来统一地访问各种类型的数据库。因此无论是使用何种数据库,都应当添加对JDBC的支持。

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-jdbcartifactId>
        dependency>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>

要连接数据库,还需要在Spring Boot的配置文件application.properties中添加数据库IP、帐号密码等相关信息:

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

我这里的密码是空,因为本地测试库没有设置密码。

Service

为了让代码更灵活,这里我们需要在实体层和Controller之间创建一个“中间层”Service,用于对Controller提供基础的数据读写功能。

一些结构简单的语言,如PHP,其实会将Service层的代码写入Model层。

下面是UserService的完整代码:

package cn.icexmoon.my_first_app.service;

import cn.icexmoon.my_first_app.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Service;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

@Service
public class UserService {
    @Autowired
    JdbcTemplate jdbcTemplate;
    public long addUser(User user){
        String sql = "INSERT INTO `user` (`name`, `age`) VALUES (?, ?)";
        PreparedStatementCreator preparedStatementCreator = new PreparedStatementCreator() {
            @Override
            public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
                PreparedStatement ps = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
                ps.setString(1,user.getName());
                ps.setInt(2, user.getAge());
                return ps;
            }
        };
        KeyHolder keyHolder = new GeneratedKeyHolder();
        jdbcTemplate.update(preparedStatementCreator, keyHolder);
        return keyHolder.getKey().longValue();
    }

    public void deleteUser(long id) {
        jdbcTemplate.update("delete from user where id=?", id);
    }

    public List<User> getUsers() {
        List<User> users = jdbcTemplate.query("SELECT `id`,`name`,`age` FROM USER", new BeanPropertyRowMapper<>(User.class));
        return users;
    }

    public User getUser(long id) {
        String sql = String.format("select `id`,`name`,`age` from user where id=%d",id);
        User user;
        try{
            user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class));
        }
        catch (EmptyResultDataAccessException e){
            return null;
        }
        return user;
    }

    public void updateUser(User user){
        String sql = String.format("UPDATE `user` SET`name`='%s',`age`='%d' WHERE id=%d",user.getName(),user.getAge(),user.getId());
        jdbcTemplate.update(sql);
    }
}

Spring Boot的Service层类使用@Service注解。这里使用了一个基础的JDBC连接类JdbcTemplate,它可以提供基础的数据库操作。

Spring Boot最优秀的地方在于,我们不需要编写数据库连接和断开的相关处理代码,只需要为JdbcTemplate添加一个@Autowired注解,框架就会对其正确初始化,并在需要时连接数据库,在不需要时断开数据库。

JdbcTemplate提供这么几种基本方法对数据库进行操作:

  • JdbcTemplate.update,执行数据变更SQL,如updatedelete等。
  • JdbcTemplate.query,执行数据查询SQL,即select
  • JdbcTemplate.exec,执行DDL语句,如create table

具体的实现这里就不细说了,比较简单,看示例即可。值得一说的有:

  • 为了实现添加数据后返回自增主键,这里使用了一个PreparedStatementCreator匿名类,并用它返回一个可以处理SQL语句的PreparedStatement对象。最后再使用一个KeyHolder对象来保存生成的自增主键值。
  • queryForObject可以查询单条数据,并以实体类的方式返回,但在查询不到结果时会抛出一个EmptyResultDataAccessException异常,这里对其进行捕获,并返回null

Controller

剩余的工作相对简单,只要在UserController中去除内存中Map及相关代码,然后改为通过UserService获取数据并返回即可:

package cn.icexmoon.my_first_app.controller;

import cn.icexmoon.my_first_app.model.Result;
import cn.icexmoon.my_first_app.model.User;
import cn.icexmoon.my_first_app.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    UserService userService;

    @PostMapping("")
    public String addUser(@RequestBody User user) {
        long newId = userService.addUser(user);
        Result result = new Result();
        result.setData(newId);
        return result.toString();
    }

    @DeleteMapping("/{id}")
    public Result deleteUser(@PathVariable long id) {
        Result result = new Result();
        User user = userService.getUser(id);
        if (user == null) {
            result.setSuccess(false);
            result.setMsg("no this person.");
            return result;
        }
        userService.deleteUser(id);
        result.setMsg("delete success.");
        return result;
    }

    @PutMapping("/{id}")
    public Result updateUser(@PathVariable long id, @RequestBody User user) {
        Result result = new Result();
        User u = userService.getUser(id);
        if (u == null) {
            result.setSuccess(false);
            result.setMsg("no this person.");
            return result;
        }
        user.setId(id);
        userService.updateUser(user);
        return result;
    }

    @GetMapping("/{id}")
    public Result getUser(@PathVariable long id) {
        Result result = new Result();
        User user = userService.getUser(id);
        if (user == null) {
            result.setSuccess(false);
            result.setMsg("no this person.");
            return result;
        }
        result.setData(user);
        return result;
    }

    @GetMapping("")
    public String getUsers() {
        Result result = new Result();
        result.setData(userService.getUsers());
        return result.toString();
    }
}

这里同样以@Autowired注解的方式引入UserService,并不需要我们自行对其初始化。

好了,现在再试试通过HTTP客户端模拟访问,即使应用重启数据也依然存在。

谢谢阅读。

本篇文章的最终代码可以从learn_spring_boot(github.com)获取。

你可能感兴趣的:(JAVA,spring,boot,java,开发语言)