MyBatis操作数据库(1)

前言

在应用分层的学习时, 我们了解到web应用程序一般分为三层,即Controller, Service, Dao.

之前的案例中, 请求流程如下: 浏览器发起请求, 先请求Controller, Controller接受到请求后,调用Service进行业务逻辑处理, Service再调用Dao, 但是Dao层的数据是Mock的, 真实的数据是从数据库中读取.

我们学习MySQL数据库时, 已经学习了用JDBC操作数据库, 但是JDBC过于复杂. 因此我们可以使用MyBatis以更方便, 更快速的操作数据库.

什么是MyBatis

MyBatis 是一款优秀的持久层框架, 用于简化JDBC的开发.

持久层: 指的就是持久化操作的层, 通常指数据访问层(dao), 是用来操作数据库的.

MyBatis入门

MyBatis操作数据库的步骤:

1.准备工作(创建Springboot工程, 数据库表准备, 实体类)

2.引入MyBatis相关依赖.

3.编写SQL语句(注解/XML).

4.测试

准备工作

创建工程

创建springboot工程, 并导入mybatis的起步依赖, mysql的驱动包

Mybatis是一个持久层框架, 具体的数据存储和数据操作还是在MySQL中操作的, 所以需要添加MySQL驱动.

项目工程创建完成后, 自动在pom.xml文件中, 导入Mybatis依赖和MySQL驱动依赖.

版本会随着SpringBoot版本发生变化, 无需关注.

数据准备

创建用户表, 并创建对应的实体类User.

sql 复制代码
-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;
-- 使⽤数据数据
USE mybatis_test;
-- 创建表[⽤⼾表]
DROP TABLE IF EXISTS userinfo;
CREATE TABLE `userinfo` (
`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
`username` VARCHAR ( 127 ) NOT NULL,
`password` VARCHAR ( 127 ) NOT NULL,
`age` TINYINT ( 4 ) NOT NULL,
`gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-⼥ 0-默认',
`phone` VARCHAR ( 15 ) DEFAULT NULL,
`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',
`create_time` DATETIME DEFAULT now(),
`update_time` DATETIME DEFAULT now(),
PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
-- 添加⽤⼾信息
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );

创建对应的实体类UserInfo

实体类的属性名与表中的字段名一一对应.

java 复制代码
import lombok.Data;

import java.util.Date;

@Data
public class UserInfo {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}

配置数据库连接字符串

Mybatis中要连接数据库, 需要数据库相关参数的配置.

MySQL驱动类

登录名

密码

数据库连接字符串

如果是application.yml文件, 配置内容如下:

java 复制代码
# 数据库连接配置
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    username: root
    password: 550407
    driver-class-name: com.mysql.cj.jdbc.Driver

写持久层代码

按如下格式创建:

java 复制代码
import com.bit.mybatis.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface UserInfoMapper {
    //查询所有用户
    @Select("Select username, password, age, gender, phone from userinfo")
    public List<UserInfo> queryAllUser();
}

MyBatis的持久层接口规范一般都叫XxxMapper

@Mapper注解: 表示的是MyBatis中的Mapper接口

程序运行时, 框架会自动生成接口的实现类对象(代理对象), 并交给Spring的IOC容器管理.

@Select注解: 代表的就是select查询, 也就是注解对应方法的具体实现内容.

单元测试

在创建出来的SpringBoot工程中, 在src的test目录下, 已经自动创建好了测试类, 可直接使用这个测试类来进行测试了.

java 复制代码
@SpringBootTest
class MybatisApplicationTests {
	@Autowired
	private UserInfoMapper userInfoMapper;

	@Test
	void contextLoads() {
		List<UserInfo> userInfoList = userInfoMapper.queryAllUser();
		System.out.println(userInfoList);
	}

}

测试类上添加了注解@SpringBootTest, 该测试类在运行时, 就会自动加载Spring的运行环境. 我们通过@Autowired这个注解, 注入我们要测试的类, 就可以开始进行测试了.

运行结果:

使用idea自动生成测试类

除此之外, 也可以使用idea自动生成测试类.

在需要测试的Mapper接口中, 右键 -> Generate -> Test

MyBatis的基础操作

上面我们学习了MyBatis的查询操作, 接下来我们来学习MyBatis的增删改操作.

在学习这些操作之前, 我们先来学习MyBatis日志的打印.

打印日志

在MyBatis我们可以借助日志, 查看到sql语句的执行, 传递的参数以及执行结果.

在配置文件中进行配置即可.

java 复制代码
mybatis:
  configuration: 
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

重新运行程序, 可以看到SQL的执行内容, 以及传递参数和执行结果.

参数传递

需求: 查找 id = 4的用户, 对应的SQL就是: select * from userinfo where id = 4;

java 复制代码
@Select("select username, password, age, gender, phone from userinfo where id = 4")
UserInfo queryById();

但是这样的话, 只能查找id=4的数据, 所以SQL语句中的id值不能写成固定的数值, 需要转变为动态的数值.

解决方案: 在queryById方法中添加一个参数(id), 将方法中的参数, 传给SQL语句.

使用#{}的方式获取方法中的参数.

java 复制代码
@Select("select username, password, age, gender, phone from userinfo where id = #{id}")
UserInfo queryById(Integer id);

如果mapper的接口方法形参只有一个普通类型的参数, #{...}里面的属性名可以随便写, 如:#{id}, #{value}. 建议和参数名保持一致.

添加测试用例:

java 复制代码
    @Test
    void queryById() {
        UserInfo userInfo = userInfoMapper.queryById(4);
        System.out.println(userInfo);
    }

运行结果:

也可以通过@Param, 设置参数的别名, 如果使用@Param设置别名, #{...}里面的属性名必须和@Param设置的一样.

java 复制代码
@Select("select username, password, age, gender, phone from userinfo where id = #{userid}")
UserInfo queryById(@Param("userid") Integer id);

增(Insert)

SQL语句:

sql 复制代码
insert into userinfo (username, `password`, age, gender, phone) values
("zhaoliu","zhaoliu",19,1,"18700001234")

把SQL中的常量转换为动态的参数:

Mapper接口:

java 复制代码
@Insert("insert into userinfo (username, password, age, gender, phone) values (#{username}, #{password}, #{age}, #{gender}, #{phone})")
Integer insert(UserInfo userInfo);

直接使用UserInfo 对象来获取参数.

测试代码:

java 复制代码
    @Test
    void insert() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("zhangsan");
        userInfo.setPassword("123456");
        userInfo.setAge(18);
        userInfo.setGender(1);
        userInfo.setPhone("129830218213");
        userInfoMapper.insert(userInfo);
    }

运行后, 观察数据库执行结果.

返回主键

Insert语句默认返回的是受影响的行数.

但有些情况下, 数据插入之后, 还需要有后续的关联操作, 需要获取到新插入数据的id.

比如订单系统

当我们下完订单以后, 需要通知物流系统, 库存系统, 结算系统等, 这时候就需要拿到订单ID.

要想要拿到自增id, 需要在Mapper接口的方法上添加一个Options的注解.

java 复制代码
@Options(useGeneratedKeys = true, keyProperty = "id")

useGeneratedKey: 这会令MyBatis使用JDBC的getGeneratedKeys方法来取出数据库内部生成的主键(比如: 像MySQL和SQL Server这样的关系型数据库管理系统的自动递增字段), 默认值: false.

keyProperty: 指定能够唯一识别对象的属性, MyBatis会使用getGeneratedKeys的返回值或insert语句的selectKey子元素设置它的值, 默认值: 未设置.

测试数据:

java 复制代码
    @Test
    void insert() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("zhaoliu");
        userInfo.setPassword("3128937");
        userInfo.setAge(22);
        userInfo.setGender(0);
        userInfo.setPhone("323830218213");
        Integer count = userInfoMapper.insert(userInfo);
        System.out.println("添加数据条数:" + count + ", 数据ID" + userInfo.getId());
    }

注意: 设置useGeneratedKeys=true之后, 方法的返回值依然是受影响的行数, 自增id会设置在上述KeyProperty指定的属性中.

删(Delete)

SQL语句:

sql 复制代码
delete from userinfo where id = 6

把SQL中的常量替换成动态的参数

Mapper接口.

java 复制代码
    @Delete("delete from userinfo where id = #{id}")
    void delete(Integer id);

改(Update)

SQL语句:

sql 复制代码
update userinfo set username="zhaoliu" where id = 5

Mapper接口

java 复制代码
    @Update("update userinfo set username = #{username} where id = #{id}")
    void update(UserInfo userInfo);
相关推荐
广州智造41 分钟前
OptiStruct实例:3D实体转子分析
数据库·人工智能·算法·机器学习·数学建模·3d·性能优化
技术宝哥4 小时前
Redis(2):Redis + Lua为什么可以实现原子性
数据库·redis·lua
学地理的小胖砸5 小时前
【Python 操作 MySQL 数据库】
数据库·python·mysql
dddaidai1235 小时前
Redis解析
数据库·redis·缓存
数据库幼崽6 小时前
MySQL 8.0 OCP 1Z0-908 121-130题
数据库·mysql·ocp
Amctwd6 小时前
【SQL】如何在 SQL 中统计结构化字符串的特征频率
数据库·sql
betazhou6 小时前
基于Linux环境实现Oracle goldengate远程抽取MySQL同步数据到MySQL
linux·数据库·mysql·oracle·ogg
lyrhhhhhhhh7 小时前
Spring 框架 JDBC 模板技术详解
java·数据库·spring
喝醉的小喵8 小时前
【mysql】并发 Insert 的死锁问题 第二弹
数据库·后端·mysql·死锁
付出不多9 小时前
Linux——mysql主从复制与读写分离
数据库·mysql