Spring Boot 2.x + myBatis全注解and全xml实现CRUD及自动建表

2,216 阅读5分钟

最近准备学习下后端数据库开发相关,于是便开始了折腾。

本文主要从新手向介绍一个基于Spring Boot2.x,MySQL和myBatis完成简单的用Web操作数据库的demo程序,然后采用两种实现方式:

  1. 全注解实现SQL持久化方式
  2. 全xml实现SQL持久化方式

主要支持以下功能:

  • 数据库自动建表,如本例中的user表。
  • 数据库CRUD(create read update delete)操作。
  • 通过http get操作user表。

1. 环境准备

IntelliJ IDEA Ultimate

这里建议使用专业版的IDEA,因为它自带数据库操作功能(Database),可以连接本地MySQL数据库,通过SQL语句操作数据库以及可视化数据库内容。非常方便,相等于节省了一个MySQL Workbench的安装。由于IntelliJ IDEA Ultimate是付费版,没有license的个人用户可以参考下Jetbrains系列产品2019.2.4最新激活方法[持续更新]。这也是我之前刷沸点看到的,不然我只能在公司里用专业版的IDEA,感谢大神分享。

MySQL

可以通过官方网站下载MySQL Community Downloads,安装过程中的Set Type由于IntelliJ IDEA Ultimate有Database的功能,这里直接选择Server only即可。如果,你想用MySQL Workbench,可以选择Development default,会一并安装MySQL Workbench。

所使用的数据表是类似如下的内容:

CREATE TABLE `user` (
    `id` int(13) NOT NULL AUTO_INCREMENT,
    `name` varchar(33) NOT NULL,
    `age` int(3) NOT NULL,
    `money` double NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

Maven + JDK8

Spring Boot建议JDK 1.8 or later和Maven 3.2+。

2. 项目结构

+---src
|   +---main
|   |   +---java
|   |   |   \---hello
|   |   |       |   MainApplication.java
|   |   |       |   
|   |   |       +---bean
|   |   |       |       User.java
|   |   |       |       
|   |   |       +---controller
|   |   |       |       UserController.java
|   |   |       |       
|   |   |       +---dao
|   |   |       |       UserDao.java
|   |   |       |       
|   |   |       \---service
|   |   |               UserService.java
|   |   |               
|   |   \---resources
|   |           application.properties
|   |           mysql.properties
|   |           \---mapper
|   |                   UserMapper.xml(xml实现特有)         
pom.xml

3. 内容解析

  • pom.xml

pom中需要添加boot-starter-web的依赖,MySQL连接的依赖,myBatis的依赖。

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>
  • properties配置

application.properties,连接本地MySQL数据库相关配置。

server.port=8333
# 数据库为sakila
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/sakila?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

mysql.properties,项目中使用的数据集表名,支持修改。

# 自定义所使用的mysql表的表名配置
mysql.tableName=user
  • 用户类User

用户类(POJO)User,类成员变量对应数据库表中的各个字段。

public class User {

    private int id;

    private String name;

    private int age;

    private double money;
    // Set Get方法省略
}
  • Dao 层

基于全注解实现数据库CRUD操作,UserDao.java。这里要注意mybatis动态调用表名和字段名分别是使用${}和#{},具体的区别可以参考mybatis动态调用表名和字段名

/**
 * 基于注解实现数据库 CRUD(create read update delete)
 */
@Mapper
public interface UserDao {

    /**
     * 创建一个新表,如果表明不存在
     */
    @Update("create table if not exists ${tableName}(\n" +
            "id int(13) not null auto_increment,\n" +
            "`name` varchar(33) not null,\n" +
            "age int(3) not null,\n" +
            "money double not NULL,\n" +
            "PRIMARY KEY (id)\n" +
            ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8")
    void createTable(@Param("tableName")String tableName);

    /**
     * 插入用户信息
     */
    @Insert("INSERT INTO ${tableName}(name, age, money) VALUES(#{name}, #{age}, #{money})")
    void insertUser(@Param("tableName")String tableName, @Param("name") String name, @Param("age") Integer age,
                    @Param("money") Double money);

    /**
     * 通过名字查询用户信息
     */
    @Select("SELECT * FROM ${tableName} WHERE name = #{name}")
    List<User> findUserByName(@Param("tableName")String tableName, @Param("name") String name);

    /**
     * 查询所有用户信息
     */
    @Select("SELECT * FROM ${tableName}")
    List<User> findAllUser(@Param("tableName")String tableName);

    /**
     * 根据 id 更新用户信息
     */
    @Update("UPDATE ${tableName} SET name = #{name},age = #{age},money= #{money} WHERE id = #{id}")
    void updateUser(@Param("tableName")String tableName, @Param("name") String name, @Param("age") Integer age,
                    @Param("money") Double money, @Param("id") int id);

    /**
     * 根据 id 删除用户信息
     */
    @Delete("DELETE from ${tableName} WHERE name = #{name}")
    void deleteUser(@Param("tableName")String tableName, @Param("name") String name);

    /**
     * 删除user表里面的所有数据
     */
    @Delete("DELETE from ${tableName} WHERE 1 = 1")
    void deleteAllUserData(@Param("tableName")String tableName);
}
  • Service层

UserService.java用于链接数据层(DAO),并实现CRUD的业务逻辑。另外这里的自动建表的表名是通过自定义配置文件mysql.properties中配置的。

@Service
@PropertySource({"classpath:mysql.properties"})
public class UserService {
    @Autowired
    private UserDao userDao;

    @Value("${mysql.tableName}")
    private String tableName;

    /**
     * 如果表不存在则创建表
     */
    public void createTable() {
        userDao.createTable(tableName);
    }

    /**
     * 根据名字查找用户
     */
    public List<User> selectUserByName(String name) {
        return userDao.findUserByName(tableName, name);
    }

    /**
     * 查找所有用户
     */
    public List<User> selectAllUser() {
        return userDao.findAllUser(tableName);
    }

    /**
     * 插入两个用户
     */
    public void insertService() {
        userDao.insertUser(tableName, "Ace", 22, 3000.0);
        userDao.insertUser(tableName, "Blink", 19, 3000.0);
    }

    /**
     * 插入某个指定用户
     */
    public void insertOneService(String name, int age, double money) {
        userDao.insertUser(tableName, name, age, money);
    }

    /**
     * 通过名字更新用户信息
     */
    @Transactional
    public void updateService(String name, int age, double money) {
        List<User> users = userDao.findUserByName(tableName, name);
        if (users.isEmpty()) {
            return;
        }
        List<Integer> ids = users.stream().map(User::getId).collect(Collectors.toList());
        ids.forEach(id -> userDao.updateUser(tableName, name, age, money, id));
    }

    /**
     * 根据id 删除用户
     */
    public void deleteService(String name) {
        userDao.deleteUser(tableName, name);
    }

    /**
     * 清除表内所有数据
     */
    public void clearService() {
        userDao.deleteAllUserData(tableName);
    }

    /**
     * 模拟事务。由于加上了 @Transactional注解,如果转账中途出了意外 Ace 和 Blink 的钱都不会改变。
     */
    @Transactional
    public void changemoney() {
        userDao.updateUser(tableName,"Ace", 22, 2000.0, 3);
        // 模拟转账过程中可能遇到的意外状况
        int temp = 1 / 0;
        userDao.updateUser(tableName,"Blink", 19, 4000.0, 4);
    }
}

基于全xml实现只需要修改UserDao.java并添加如下的UserMapper.xml就ok了,其他代码和配置完全和注解版本一致。

UserDao.java

/**
 * 基于xml实现数据库 CRUD(create read update delete)
 */
@Mapper
public interface UserDao {


    /**
     * 创建一个新表,如果表明不存在
     */
    void createTable(@Param("tableName")String tableName);

    /**
     * 插入用户信息
     */
    void insertUser(@Param("tableName")String tableName, String name, Integer age, Double money);

    /**
     * 通过名字查询用户信息
     */
    List<User> findUserByName(@Param("tableName")String tableName, String name);

    /**
     * 查询所有用户信息
     */
    List<User> findAllUser(@Param("tableName")String tableName);

    /**
     * 根据 id 更新用户信息
     */
    void updateUser(@Param("tableName")String tableName, String name, Integer age, Double money, int id);

    /**
     * 根据 id 删除用户信息
     */
    void deleteUser(@Param("tableName")String tableName, String name);

    /**
     * 删除user表里面的所有数据
     */
    void deleteAllUserData(@Param("tableName")String tableName);
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="hello.dao.UserDao">

    <update id="createTable">
        create table if not exists ${tableName}(
        id int(13) not null auto_increment,
        `name` varchar(33) not null,
        age int(3) not null,
        money double not null,
        primary key (id)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
    </update>

<!--这里的name, age 和 money可以自动匹配insertUser(String name, Integer age, Double money)的入参-->
    <insert id="insertUser">
        insert into ${tableName}(name, age, money) values(#{name}, #{age}, #{money})
    </insert>

    <select id="findUserByName" resultType="hello.bean.User">
        SELECT * FROM ${tableName} WHERE name = #{name}
    </select>

    <select id="findAllUser" resultType="hello.bean.User">
        select * from ${tableName}
    </select>

    <update id="updateUser">
        update ${tableName} set name = #{name}, age = #{age}, money = #{money} where id = #{id}
    </update>

    <delete id="deleteUser">
        delete from ${tableName} where name = #{name}
    </delete>

    <delete id="deleteAllUserData">
        delete from ${tableName} where 1 = 1
    </delete>
</mapper>
  • Controller层

实现 CRUD http 请求对应controller接口

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

    // http://localhost:8333/user/insert?name=ace&age=18&money=0
    @GetMapping("/insert")
    public List<User> insert(@RequestParam(value = "name", required = true) String name,
                             @RequestParam(value = "age", required = true) int age,
                             @RequestParam(value = "money", required = true) double money) {
        userService.insertOneService(name, age, money);
        return userService.selectAllUser();
    }

    // http://localhost:8333/user/query?name=ace
    @GetMapping("/query")
    public List<User> queryByName(@RequestParam(value = "name", required = false) String name) {
        if (name == null) {
            return userService.selectAllUser();
        }
        return userService.selectUserByName(name);
    }

    // http://localhost:8333/user/update?name=ace&age=18&money=999
    @GetMapping("/update")
    public List<User> update(@RequestParam(value = "name", required = true) String name,
                             @RequestParam(value = "age", required = true) int age,
                             @RequestParam(value = "money", required = true) double money) {
        userService.updateService(name, age, money);
        return userService.selectUserByName(name);
    }

    // http://localhost:8333/user/delete?name=ace
    @GetMapping("/delete")
    public String delete(@RequestParam(value = "name", required = true) String name) {
        userService.deleteService(name);
        return "OK";
    }

    // http://localhost:8333/user/clear
    @GetMapping("/clear")
    public List<User> testClear() {
        userService.clearService();
        return userService.selectAllUser();
    }

    @GetMapping("/changemoney")
    public List<User> testchangemoney() {
        userService.insertService();
        userService.changemoney();
        return userService.selectAllUser();
    }
}
  • Spring Boot启动类

MainApplication.java通过继承CommandLineRunner在Spring Boot启动的时候,在表自动创建完后会在表中插入一些数据。

@SpringBootApplication
public class MainApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }

    @Autowired
    UserService userService;

    @Override
    public void run(String... args) throws Exception {
        userService.createTable();
        userService.insertService();
    }
}

4. 功能演示

  1. 数据库表自动创建,可以通过专业版IDEA的Database功能看到user表的自动创建。

  2. 查询query,这里如果要显示如图的json格式,需要给Chrome装上JsonViewer插件。

  3. 插入数据insert

4. 更新数据update
5. 删除数据delete

完整代码见 全注解实现 全xml实现

截止目前,一个基于Spring Boot 2.x,MySQL和myBatis完成简单的用Web操作数据库的demo程序就已经完成啦,由于本人处于刚刚学习中的状态,如有bug或错误,欢迎评论指正~