【图书管理系统】基于Spring全家桶的图书管理系统(上)


🎬 那我掉的头发算什么个人主页
🔥 个人专栏 : 《javaSE》《数据结构》《数据库》《javaEE》

⛺️待到苦尽甘来日


引言

在前面做mvc小项目时,我们曾做过一个图书管理系统的项目。先不说里面的数据是mock的而非数据库提取的,就连接口都没实现几个。现在我们学习了很多新的知识,有足够的能力将原来那个项目做的更好。下面跟我一起完整的实现图书管理系统项目吧!

文章目录

准备工作

做任何项目,准备工作都是必不可少的,尤其是后端项目,准备工作做扎实了,后面写代码的时候才能少踩坑、少返工。图书管理系统的准备工作不算复杂,主要就是数据库表设计、引入相关依赖、配置文件编写、实体类创建和代码分层这几块,每一步都很基础,但也很关键,新手小伙伴一定要跟着一步步来,不要跳步,不然很容易出现各种奇奇怪怪的问题,到时候排查起来就麻烦了。

数据库表设计

数据库表是应用程序开发中的一个重要环节,数据库表的设计往往会决定我们的应用需求是否能顺利实现,甚至决定我们的实现方式。如何设计表以及这些表有哪些字段,这些表存在哪些关系 也是非常重要的.

数据库表设计是依据业务需求来设计的。如何设计出优秀的数据库表,与经验有很大关系.

数据库表通常分两种:实体表和关系表.分析我们的需求,图书管理系统相对来说比较简单,只有两个实体:用户和图书,并且用户和图书之间没有关联关系表的具体字段设计,也与需求有关.用户表有用户名和密码即可 (复杂的业务可能还涉及昵称,年龄等资料)图书表有哪些字段,也是参考需求页面 (通常不是一个页面决定的,而是要对整个系统进行全面分析观察后定的)

java 复制代码
-- 创建数据库
DROP DATABASE IF EXISTS book_test;

CREATE DATABASE book_test DEFAULT CHARACTER SET utf8mb4;

-- 用户表
DROP TABLE IF EXISTS user_info;
CREATE TABLE user_info (
        `id` INT NOT NULL AUTO_INCREMENT,
        `user_name` VARCHAR ( 128 ) NOT NULL,
        `password` VARCHAR ( 128 ) NOT NULL,
        `delete_flag` TINYINT ( 4 ) NULL DEFAULT 0,
        `create_time` DATETIME DEFAULT now(),
        `update_time` DATETIME DEFAULT now() ON UPDATE now(),
        PRIMARY KEY ( `id` ),
UNIQUE INDEX `user_name_UNIQUE` ( `user_name` ASC )) ENGINE = INNODB DEFAULT CHARACTER 
SET = utf8mb4 COMMENT = '用户表';

-- 图书表
DROP TABLE IF EXISTS book_info;
CREATE TABLE `book_info` (
        `id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
        `book_name` VARCHAR ( 127 ) NOT NULL,
        `author` VARCHAR ( 127 ) NOT NULL,
        `count` INT ( 11 ) NOT NULL,
        `price` DECIMAL (7,2 ) NOT NULL,
        `publish` VARCHAR ( 256 ) NOT NULL,
        `status` TINYINT ( 4 ) DEFAULT 1 COMMENT '0-无效, 1-正常, 2-不允许借阅',
        `create_time` DATETIME DEFAULT now(),
        `update_time` DATETIME DEFAULT now() ON UPDATE now(),
PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;

-- 初始化数据
INSERT INTO user_info ( user_name, PASSWORD ) VALUES ( "admin", "admin" );
INSERT INTO user_info ( user_name, PASSWORD ) VALUES ( "zhangsan", "123456" );

-- 初始化图书数据
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('活着', '余华', 29, 22.00, '北京文艺出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('平凡的世界', '路遥', 5, 98.56, '北京十月文艺出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('三体', '刘慈欣', 9, 102.67, '重庆出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('金字塔原理', '麦肯锡', 16, 178.00, '民主与建设出版社');

引入Mybatis和Mysql驱动依赖

由于这是老项目,之前项目里面没有加,所以现在加上。当然大家也可以在创建项目时就选上这俩或者用咱们之前用的edit Straters。

java 复制代码
<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>4.0.1</version>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

配置数据库&日志

账号密码是你自己Mysql的账号密码

引入完依赖之后,就需要配置数据库连接信息了,不然项目不知道要连接哪个数据库、用什么账号密码连接。另外,我们还可以配置一下MyBatis的日志和系统日志,方便我们后续调试代码,排查问题。

java 复制代码
# 数据库连接配置
spring:
 datasource:
 url: jdbc:mysql://127.0.0.1:3306/book_test?
characterEncoding=utf8&useSSL=false
 username: root
 password: root
 driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
 configuration:
 map-underscore-to-camel-case: true #配置驼峰⾃动转换
 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印sql语句
# 设置⽇志⽂件的⽂件名
logging:
 file:
 name: spring-book.log

模型创建

配置完数据库和日志之后,我们就需要创建实体类了。实体类是用来映射数据库表的,数据库里面有什么表,我们就创建对应的实体类,表里面有什么字段,实体类里面就有对应的属性,这样我们操作实体类,就相当于操作数据库表里面的数据,非常方便。

这里我们用到了lombok的@Data注解,相信很多小伙伴都用过lombok,它可以帮我们自动生成getter、setter、toString、equals、hashCode等方法,不用我们手动去写,大大减少了代码量,提高了开发效率。如果大家的项目里面没有引入lombok依赖,记得先引入,不然@Data注解会报错哦。

图书类

java 复制代码
package com.hbu.book.model;

import lombok.Data;

import java.math.BigDecimal;
import java.util.Date;

@Data
public class BookInfo {
    //图书ID
    private Integer id;
    //书名
    private String bookName;
    //作者
    private String author;
    //数量
    private Integer count;
    //定价
    private BigDecimal price;
    //出版社
    private String publish;
    //状态 0-⽆效 1-允许借阅 2-不允许借阅
    private Integer status;
    private String statusCN;
    //创建时间
    private Date createTime;
    //更新时间
    private Date updateTime;
}

用户类

java 复制代码
package com.hbu.book.model;

import lombok.Data;

import java.util.Date;

@Data
public class UserInfo {
    private Integer id;
    private String userName;
    private String password;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}

页面请求

java 复制代码
package com.hbu.book.model;

import lombok.Data;

@Data
public class PageRequest {
    private Integer currentPage = 1;
    private Integer pageSize = 10;
    private Integer offset;

    public Integer getOffset(){
        this.offset = (currentPage - 1) * pageSize;
        return offset;
    }
}

页面响应

java 复制代码
package com.hbu.book.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class PageResp<T> {
    private Integer total;
    private List<T> records;
    private PageRequest pageRequest;
}

统一结果

java 复制代码
package com.hbu.book.model;



import com.hbu.book.enums.ResultCodeEnum;
import lombok.Data;

@Data
public class Result<T> {
    private ResultCodeEnum code;  //-1 未登录    200 正常  -2 出错
    private String errMsg;
    private T data;

    public static <T> Result success(T data){
        Result result = new Result();
        result.setCode(ResultCodeEnum.SUCCESS);
        result.setErrMsg("");
        result.setData(data);
        return result;
    }

    public static <T> Result fail(String errMsg){
        Result result = new Result();
        result.setCode(ResultCodeEnum.FAIL);
        result.setErrMsg(errMsg);
        result.setData(null);
        return result;
    }

    public static <T> Result fail(String errMsg, T data){
        Result result = new Result();
        result.setCode(ResultCodeEnum.FAIL);
        result.setErrMsg(errMsg);
        result.setData(data);
        return result;
    }

    public static <T> Result unlogin(){
        Result result = new Result();
        result.setCode(ResultCodeEnum.UNLOGIN);
        result.setErrMsg("用户未登录");
        return result;
    }
}

代码分层

具体内容下面再说,大家先把包分一下层:

实现接口

准备工作都做好之后,我们就可以开始实现接口了。接口分为前端接口和后端接口,这一篇我们先实现前端代码,后端接口我们下一篇再详细讲解。前端代码主要是页面布局和前后端交互的逻辑,比如登录页面、图书列表页面、添加图书页面、修改图书页面,这些页面都是用HTML、CSS和JavaScript编写的,结合了Bootstrap框架,让页面样式更美观、更规范。

前端代码

添加图书:

css 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>添加图书</title>
    <link rel="stylesheet" href="css/bootstrap.min.css">
    <link rel="stylesheet" href="css/add.css">

</head>

<body>

<div class="container">

    <div class="form-inline">
        <h2 style="text-align: left; margin-left: 10px;"><svg xmlns="http://www.w3.org/2000/svg" width="40"
                                                              fill="#17a2b8" class="bi bi-book-half" viewBox="0 0 16 16">
            <path
                    d="M8.5 2.687c.654-.689 1.782-.886 3.112-.752 1.234.124 2.503.523 3.388.893v9.923c-.918-.35-2.107-.692-3.287-.81-1.094-.111-2.278-.039-3.213.492V2.687zM8 1.783C7.015.936 5.587.81 4.287.94c-1.514.153-3.042.672-3.994 1.105A.5.5 0 0 0 0 2.5v11a.5.5 0 0 0 .707.455c.882-.4 2.303-.881 3.68-1.02 1.409-.142 2.59.087 3.223.877a.5.5 0 0 0 .78 0c.633-.79 1.814-1.019 3.222-.877 1.378.139 2.8.62 3.681 1.02A.5.5 0 0 0 16 13.5v-11a.5.5 0 0 0-.293-.455c-.952-.433-2.48-.952-3.994-1.105C10.413.809 8.985.936 8 1.783z" />
        </svg>
            <span>添加图书</span>
        </h2>
    </div>

    <form id="addBook">
        <div class="form-group">
            <label for="bookName">图书名称:</label>
            <input type="text" class="form-control" placeholder="请输入图书名称" id="bookName" name="bookName">
        </div>
        <div class="form-group">
            <label for="bookAuthor">图书作者</label>
            <input type="text" class="form-control" placeholder="请输入图书作者" id="bookAuthor" name="author" />
        </div>
        <div class="form-group">
            <label for="bookStock">图书库存</label>
            <input type="text" class="form-control" placeholder="请输入图书库存" id="bookStock" name="count"/>
        </div>

        <div class="form-group">
            <label for="bookPrice">图书定价:</label>
            <input type="number" class="form-control" placeholder="请输入价格" id="bookPrice" name="price">
        </div>

        <div class="form-group">
            <label for="bookPublisher">出版社</label>
            <input type="text" id="bookPublisher" class="form-control" placeholder="请输入图书出版社" name="publish" />
        </div>
        <div class="form-group">
            <label for="bookStatus">图书状态</label>
            <select class="custom-select" id="bookStatus" name="status">
                <option value="1" selected>可借阅</option>
                <option value="2">不可借阅</option>
            </select>
        </div>

        <div class="form-group" style="text-align: right">
            <button type="button" class="btn btn-info btn-lg" onclick="add()">确定</button>
            <button type="button" class="btn btn-secondary btn-lg" onclick="javascript:history.back()">返回</button>
        </div>
    </form>
</div>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script>
    function add() {
        //前端应该进行参数校验, 此处省略
        //提交请求到后端
        $.ajax({
            type: "post",
            url: "/book/addBook",
            data: $("#addBook").serialize(),
            success: function(result){
                console.log(result);

                if(result.code == "SUCCESS" && result.data == ""){
                    //添加图书成功
                    location.href = "book_list.html";
                }else {
                    //失败
                    alert(result.errMsg);
                }
            },
            error: function(error){
                if(error.status==401){
                    //用户未登录
                    location.href = "login.html";
                }

            }
        });



        // alert("添加成功");
        // location.href = "book_list.html";
    }
</script>
</body>

</html>

图书列表:

css 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图书列表展示</title>
    <link rel="stylesheet" href="css/bootstrap.min.css">

    <link rel="stylesheet" href="css/list.css">
    <script type="text/javascript" src="js/jquery.min.js"></script>
    <script type="text/javascript" src="js/bootstrap.min.js"></script>
    <script src="js/jq-paginator.js"></script>

</head>

<body>
<div class="bookContainer">
    <h2>图书列表展示</h2>
    <div class="navbar-justify-between">
        <div>
            <button class="btn btn-outline-info" type="button" onclick="location.href='book_add.html'">添加图书</button>
            <button class="btn btn-outline-info" type="button" onclick="batchDelete()">批量删除</button>
        </div>
    </div>

    <table>
        <thead>
        <tr>
            <td>选择</td>
            <td class="width100">图书ID</td>
            <td>书名</td>
            <td>作者</td>
            <td>数量</td>
            <td>定价</td>
            <td>出版社</td>
            <td>状态</td>
            <td class="width200">操作</td>
        </tr>
        </thead>
        <tbody>

        </tbody>
    </table>

    <div class="demo">
        <ul id="pageContainer" class="pagination justify-content-center"></ul>
    </div>
    <script>

        getBookList();
        function getBookList() {
            $.ajax({
                type: "get",
                url: "/book/getListByPage" + location.search,
                success: function (result) {

                    if (result == null || result.code =="UNLOGIN") {
                        alert("用户未登录, 请先登录");
                        location.href = "login.html";
                    }
                    //其他情况判断, 此处省略
                    if(result ==null || result.data == null){
                        return;
                    }
                    var data = result.data;

                    var books = data.records;
                    var finalHtml = "";
                    for (var book of books) {
                        finalHtml += '<tr>';
                        finalHtml += '<td><input type="checkbox" name="selectBook" value="' + book.id + '" id="selectBook" class="book-select"></td>';
                        finalHtml += '<td>' + book.id + '</td>';
                        finalHtml += '<td>' + book.bookName + '</td>';
                        finalHtml += '<td>' + book.author + '</td>';
                        finalHtml += '<td>' + book.count + '</td>';
                        finalHtml += '<td>' + book.price + '</td>';
                        finalHtml += '<td>' + book.publish + '</td>';
                        finalHtml += '<td>' + book.statusCN + '</td>';
                        finalHtml += '<td><div class="op">';
                        finalHtml += '<a href="book_update.html?bookId=' + book.id + '">修改</a>';
                        finalHtml += '<a href="javascript:void(0)" onclick="deleteBook(' + book.id + ')">删除</a>';
                        finalHtml += '</div></td></tr>';
                    }
                    $("tbody").html(finalHtml);

                    //翻页信息
                    $("#pageContainer").jqPaginator({
                        totalCounts: data.total, //总记录数
                        pageSize: 10,    //每页的个数
                        visiblePages: 5, //可视页数
                        currentPage: data.pageRequest.currentPage,  //当前页码
                        first: '<li class="page-item"><a class="page-link">首页</a></li>',
                        prev: '<li class="page-item"><a class="page-link" href="javascript:void(0);">上一页<\/a><\/li>',
                        next: '<li class="page-item"><a class="page-link" href="javascript:void(0);">下一页<\/a><\/li>',
                        last: '<li class="page-item"><a class="page-link" href="javascript:void(0);">最后一页<\/a><\/li>',
                        page: '<li class="page-item"><a class="page-link" href="javascript:void(0);">{{page}}<\/a><\/li>',
                        //页面初始化和页码点击时都会执行
                        onPageChange: function (page, type) {
                            if (type == "change") {
                                location.href = "book_list.html?currentPage=" + page;
                            }
                        }
                    });
                },
                error: function(error){
                    if(error.status==401){
                        alert("用户未登录, 请先登录");
                        location.href = "login.html";
                    }

                }
            });
        }


        function deleteBook(id) {
            var isDelete = confirm("确认删除?");
            if (isDelete) {
                $.ajax({
                    type: "post",
                    url: "/book/deleteBook?bookId=" + id,
                    success: function (result) {

                        if (result.code == "SUCCESS" && result.data == "") {
                            location.href = "book_list.html?currentPage=1";
                        } else {
                            alert(result.errMsg);
                        }
                    }
                });
            }
        }
        function batchDelete() {
            var isDelete = confirm("确认批量删除?");
            if (isDelete) {
                //获取复选框的id
                var ids = [];
                $("input:checkbox[name='selectBook']:checked").each(function () {
                    ids.push($(this).val());
                });
                console.log(ids);
                $.ajax({
                    type: "post",
                    url: "/book/batchDelete?ids="+ids,
                    success: function(result){
                        if(result.code == "SUCCESS" && result.data==true){
                            location.href = "book_list.html?currentPage=1";
                        }else{
                            alert("批量删除失败");
                        }
                    }
                });
            }
        }

    </script>
</div>
</body>

</html>

更新图书:

css 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>修改图书</title>
    <link rel="stylesheet" href="css/bootstrap.min.css">
    <link rel="stylesheet" href="css/add.css">
</head>

<body>

<div class="container">
    <div class="form-inline">
        <h2 style="text-align: left; margin-left: 10px;"><svg xmlns="http://www.w3.org/2000/svg" width="40"
                                                              fill="#17a2b8" class="bi bi-book-half" viewBox="0 0 16 16">
            <path
                    d="M8.5 2.687c.654-.689 1.782-.886 3.112-.752 1.234.124 2.503.523 3.388.893v9.923c-.918-.35-2.107-.692-3.287-.81-1.094-.111-2.278-.039-3.213.492V2.687zM8 1.783C7.015.936 5.587.81 4.287.94c-1.514.153-3.042.672-3.994 1.105A.5.5 0 0 0 0 2.5v11a.5.5 0 0 0 .707.455c.882-.4 2.303-.881 3.68-1.02 1.409-.142 2.59.087 3.223.877a.5.5 0 0 0 .78 0c.633-.79 1.814-1.019 3.222-.877 1.378.139 2.8.62 3.681 1.02A.5.5 0 0 0 16 13.5v-11a.5.5 0 0 0-.293-.455c-.952-.433-2.48-.952-3.994-1.105C10.413.809 8.985.936 8 1.783z" />
        </svg>
            <span>修改图书</span>
        </h2>
    </div>

    <form id="updateBook">
        <input type="hidden" class="form-control" id="bookId" name="id">
        <div class="form-group">
            <label for="bookName">图书名称:</label>
            <input type="text" class="form-control" id="bookName" name="bookName">
        </div>
        <div class="form-group">
            <label for="bookAuthor">图书作者</label>
            <input type="text" class="form-control" id="bookAuthor" name="author" />
        </div>
        <div class="form-group">
            <label for="bookStock">图书库存</label>
            <input type="text" class="form-control" id="bookStock" name="count" />
        </div>
        <div class="form-group">
            <label for="bookPrice">图书定价:</label>
            <input type="number" class="form-control" id="bookPrice" name="price">
        </div>
        <div class="form-group">
            <label for="bookPublisher">出版社</label>
            <input type="text" id="bookPublisher" class="form-control" name="publish" />
        </div>
        <div class="form-group">
            <label for="bookStatus">图书状态</label>
            <select class="custom-select" id="bookStatus" name="status">
                <option value="1" selected>可借阅</option>
                <option value="2">不可借阅</option>
            </select>
        </div>
        <div class="form-group" style="text-align: right">
            <button type="button" class="btn btn-info btn-lg" onclick="update()">确定</button>
            <button type="button" class="btn btn-secondary btn-lg" onclick="javascript:history.back()">返回</button>
        </div>
    </form>
</div>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script>
    getBookInfo();
    function getBookInfo() {
        $.ajax({
            type: "get",
            url: "/book/queryBookById" + location.search,
            success: function (result) {
                //TODO 校验非常简陋
                if (result.code == "SUCCESS" && result.data != null) {
                    var bookInfo = result.data;
                    if (bookInfo != null) {
                        $("#bookId").val(bookInfo.id);
                        $("#bookName").val(bookInfo.bookName);
                        $("#bookAuthor").val(bookInfo.author);
                        $("#bookStock").val(bookInfo.count);
                        $("#bookPrice").val(bookInfo.price);
                        $("#bookPublisher").val(bookInfo.publish);
                        $("#bookStatus").val(bookInfo.status);

                    }
                }else{
                    console.log(result);

                }
            },
            error: function(error){
                if(error.status==401){
                    //用户未登录
                    location.href = "login.html";
                }

            }
        });
    }
    function update() {
        $.ajax({
            type: "post",
            url: "/book/updateBook",
            data: $("#updateBook").serialize(),
            success: function (result) {
                if (result.code == "SUCCESS" && result.data == "") {
                    location.href = "book_list.html?currentPage=1";
                } else {
                    alert(result.errMsg);
                }
            }

        });
        // alert("更新成功");
        // location.href = "book_list.html"
    }
</script>
</body>

</html>

登录界面:

css 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="css/bootstrap.min.css">
    <link rel="stylesheet" href="css/login.css">
    <script type="text/javascript" src="js/jquery.min.js"></script>
</head>

<body>
<div class="container-login">
    <div class="container-pic">
        <img src="pic/computer.png" width="350px">
    </div>
    <div class="login-dialog">
        <h3>登陆</h3>
        <div class="row">
            <span>用户名</span>
            <input type="text" name="userName" id="userName" class="form-control">
        </div>
        <div class="row">
            <span>密码</span>
            <input type="password" name="password" id="password" class="form-control">
        </div>
        <div class="row">
            <button type="button" class="btn btn-info btn-lg" onclick="login()">登录</button>
        </div>
    </div>
</div>
<script src="js/jquery.min.js"></script>
<script>
    function login() {
        $.ajax({
            type: "post",
            url: "/user/login",
            data: {
                name: $("#userName").val(),
                password: $("#password").val()
            },
            success: function(result){
                if(result){
                    //账号密码正确
                    location.href = "book_list.html?currentPage=1";
                }else {
                    alert("账号或密码错误");
                }
            }

        });
        // location.href = "book_list.html";
    }
</script>
</body>

</html>

大家可以启动项目自行观察一下前端代码是不是正常显示:

登录:

列表:

添加图书:

修改图书:

小结

由于篇幅有限,本篇博客只讲了完成图书管理系统的基本操作,具体的接口实现大家请移步下一篇博客继续阅读!
以上就是本篇博客全部内容!

相关推荐
廋到被风吹走1 小时前
SOLID原则深度解析:面向对象设计的五大基石
java·log4j
shalou29011 小时前
MySQL数据库的数据文件保存在哪?MySQL数据存在哪里
数据库·mysql
byte轻骑兵1 小时前
大数据场景时序数据库选型指南——Apache IoTDB实践与解析
大数据·数据库·apache·时序数据库·iotdb
数据与人1 小时前
MySQL int(10) 与 int(11) 的区别
数据库·mysql
cjl_8520082 小时前
MS SQL Server 实战 排查多列之间的值是否重复
java
e***8902 小时前
mysql之如何获知版本
数据库·mysql
海兰2 小时前
ES 9.3.0 日志模式分析
java·大数据·elasticsearch
桂花很香,旭很美2 小时前
[7天实战入门Go语言后端] Day 4:Go 数据层入门——database/sql 与简单 CRUD
数据库·sql·golang
lzxdyzx2 小时前
数据库操作与数据管理——Rust 与 SQLite 的集成
数据库·rust·sqlite