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);
相关推荐
梦想平凡1 小时前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
TianyaOAO1 小时前
mysql的事务控制和数据库的备份和恢复
数据库·mysql
Ewen Seong1 小时前
mysql系列5—Innodb的缓存
数据库·mysql·缓存
码农老起2 小时前
企业如何通过TDSQL实现高效数据库迁移与性能优化
数据库·性能优化
夏木~3 小时前
Oracle 中什么情况下 可以使用 EXISTS 替代 IN 提高查询效率
数据库·oracle
W21553 小时前
Liunx下MySQL:表的约束
数据库·mysql
黄名富3 小时前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua
言、雲3 小时前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
一个程序员_zhangzhen4 小时前
sqlserver新建用户并分配对视图的只读权限
数据库·sqlserver
zfj3214 小时前
学技术学英文:代码中的锁:悲观锁和乐观锁
数据库·乐观锁··悲观锁·竞态条件