MyBatis 是一款持久层框架,用于简化对数据库的操作。
添加 MyBatis 依赖
可以在创建项目时添加,也可在创建项目后在配置文件 pom.xml 中添加。
创建项目时添加:
在 pom.xml 文件中添加(需要注意版本问题,否则会报错):
<!--我的jdk版本为17,SpringBoot版本为3.2.5,若差不多可直接复制-->
<!--若jdk版本为8,SpringBoot版本为2.x,那MyBatis版本为2.x-->
<!--Mybatis 依赖包-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<!--mysql驱动包-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
数据准备
创建用户表,用于测试 MyBatis,并创建对应的实体类 user:
-- 创建数据库
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:
package com.example.demo.model;
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;
}
此处的 @Data 注解可以帮我们生成 setter 和 getter 等方法,省去我们操作,看上去也简洁,也就是开始创建项目时添加的 Lombok,若没有添加,也可在 pom.xml 中添加:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
配置数据库
在配置文件 application.yml 中添加,新建项目是 application.properties 文件,可重命名为 .yml 文件:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
username: root
password: 666666
driver-class-name: com.mysql.cj.jdbc.Driver
使用注解
编写持久层代码
编写持久层代码 UserInfoMapper,用来操作数据:
@Mapper注解:表示是 MyBatis 中的 Mapper 接口,程序运行时,会自动生成接口的实现类对象交给 Spring 管理。
@Select注解:表示为 select 查询操作。
#{id} :获取方法中的参数。
package com.example.demo.mapper;
import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface UserInfoMapper {
// 查询
@Select("select * from userinfo")
List<UserInfo> queryUserList();
@Select("select * from userinfo where id = #{id}")
UserInfo queryUserInfoById(Integer id);
// 插入
@Insert("insert into userinfo(username,password,age,gender,phone) values" +
" (#{username},#{password},#{age},#{gender},#{phone})")
Integer insertUserInfo(UserInfo userInfo);
// 删除
@Delete("delete from userinfo where id = #{id}")
Integer deleteUserInfo(Integer id);
// 更新
@Update("update userinfo set username = #{username}")
void updateUserInfo(UserInfo userInfo);
}
测试代码:
可以自动生成测试类,在需要测试的 mapper 接口中,右键 -> Generate -> Test,勾选要测试的方法:
package com.example.demo.mapper;
import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
// 测试环境
@SpringBootTest
class UserInfoMapperTest {
@Autowired
private UserInfoMapper userInfoMapper;
@Test
void queryUserList() {
System.out.println(userInfoMapper.queryUserList());
}
@Test
void queryUserInfoById() {
System.out.println(userInfoMapper.queryUserInfoById(1));
}
@Test
void insertUserInfo() {
UserInfo userInfo = new UserInfo();
userInfo.setUsername("zhaoliu");
userInfo.setPassword("zhaoliu");
userInfo.setGender(2);
userInfo.setAge(21);
userInfo.setPhone("18612340005");
userInfoMapper.insertUserInfo(userInfo);
}
@Test
void deleteUserInfo() {
userInfoMapper.deleteUserInfo(3);
}
@Test
void updateUserInfo() {
UserInfo userInfo = new UserInfo();
userInfo.setUsername("zu");
userInfo.setPassword("zu");
userInfo.setGender(1);
userInfoMapper.updateUserInfo(userInfo);
}
}
当测试查询操作时会发现有些字段数据为 null:
解决办法:
1. 起别名:
@Select(“select username, delete_flag as deleteFlag from userinfo”)
2. 结果映射:
其他地方使用:
3. 开启驼峰命名:
数据库中一般使用下划线将两个单词分隔来完成命名,而 java 使用小驼峰方式完成命名,所以在配置文件中设置好就可以完成两个不同别名之间的映射。
完成此配置,其他地方就不用起别名或者映射就可以正常拿到数据库里的字段数据了。
使用 xml
上面是使用注解方式,也可以将 SQL 语句写入 xml 文件中,同样需要先到 application.yml 配置文件中完成相应的配置:
# 告诉 spring 到哪里去找 xml 文件
mapper-locations: classpath:mapper/**Mapper.xml
要注意 mybatis: 前没有空格,configuration 前有两个空格,log-iml 前有四个空格,冒号后有空格,yml
文件对格式要求严格。
添加 mapper 接口,数据持久层接口定义:
package com.example.demo.mapper;
import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserInfoXmlMapper {
List<UserInfo> queryUserList();
}
添加 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="com.example.demo.mapper.UserInfoXmlMapper">
<select id="queryUserList" resultType="com.example.demo.model.UserInfo">
select * from userinfo
</select>
</mapper>
其他对数据库的操作也类似:
#{} 和 ${}
先看参数为 integer 的类型,使用 #{} :
使用 ${}:
都能正常查询,再看参数为 String 的类型,使用 #{}:
使用 ${}:
我们使用引号将 ${usename} 引起来:
从上面例子可以看出,使用 #{},会自动根据参数类型补全引号,而 ${} 不会。
再看安全问题,使用 ${}:
使用 #{} 则查询不到,更安全:
在有些场景时,却不需要加引号,例如排序:
使用 ${},不会加引号:
若使用 #{},则会自动加引号,导致错误:
还有模糊查询,若使用 ${},会存在不安全的问题,此时就可以用 #{} 搭配 MySQL 的函数一起使用:
#{} 和 ${} :
#{} 预编译处理,会根据参数类型自动加引号,${} 则直接替换参数。
使用 #{} 如果能解决问题就使用 #{},可以防止 SQL注入 风险。