Java EE进阶8:MyBatis 操作数据库(入门)

1.什么是MyBatis?

MyBatis是⼀款优秀的持久层框架,用于简化JDBC的开发 ,它可以帮助我们更方便、更快速的操作数据库。

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

工作流程

三要素

2.MyBatis入门

2.1 准备工作

(1)创建工程

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

手动添加Mybatis(后续在已有项目中添加可以用此方法)

(2)数据准备

创建用户表

sql 复制代码
-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;

CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;

-- 使用数据数据
USE mybatis_test;

-- 创建表[用户表]
DROP TABLE IF EXISTS user_info;
CREATE TABLE `user_info` (
        `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() ON UPDATE now(),
        PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; 

-- 添加用户信息
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.user_info( 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;
    
}

2.2 配置数据库连接字符串

Mybatis中要连接 数据库,需要数据库 相关参数配置:MySQL驱动类、登录名、密码、数据库连接字符串

如果是application.yml 文件,配置内容如下: (复制粘贴即可)

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

2.3 @Mapper @Select写持久层代码

在项目中,创建持久层接口 UserInfoMapper

写出SQL语句,通过MyBatis实现此语句

java 复制代码
@Mapper
public interface UserInfoMapper {

    @Select("SELECT * FROM `user_info`")
    public List<UserInfo> selectList();
}

返回类型 :List<UserInfo> 返回一个 UserInfo 对象组成的列表 ,每个UserInfo 对象对应数据库中的一行数据.

2.4 单元测试

(1)方法1

先使用http请求调用方法看是否成功,先补全 controllerservice层代码。

浏览器发起请求,先请求Controller ,Controller接收到请求之后,调用Service 进行业务逻辑处理,Service再调用Dao ,再从数据库中读取。

(2)方法2

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

测试类上添加了注解**@SpringBootTest** ,该测试类在运行时,就会自动加载Spring的运行环境

我们通过**@Autowired** 这个注解,注入我们要测试的类,就可以开始进行测试了。

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

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

也可以同时加几个方法,可以一次测试一个,也可以同时测试。

(3)方法3

使用Idea自动生成测试类

在执行测试方法前后 若有需要统一进行处理 的东西可以放在Before和After中,不需要可以不选

书写测试代码,记得加**@SpringBootTest 注解**,加载Spring运行环境。

java 复制代码
import com.example.mybatis.demo.model.UserInfo;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
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;

    @BeforeEach
    void setUp() {
        System.out.println("BeforeEach......");
    }

    @AfterEach
    void tearDown() {
        System.out.println("AfterEach......");
    }

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

也可以同时加几个方法,可以一次测试一个,也可以同时测试。

3.MyBatis的基础操作

3.1 打印日志

java 复制代码
mybatis:
  configuration: # 配置打印 MyBatis⽇志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

重新运行程序,可以看到SQL执行内容、传递参数、执行结果。

3.2 查 @Select

我们在上面查询时发现,有几个字段是没有赋值 的,只有Java对象属性数据库字段一模一样 时,才会进行赋值

输出null是因为名称不匹配

解决办法

(1)起别名

SQL语句 中,给列名起别名 ,保持别名实体类属性名一样。

java 复制代码
    @Select("SELECT id, username, `password`, age, gender, phone, delete_flag AS deleteFlag, " +
            "create_time AS createTime, update_time AS updateTime FROM `user_info`")
    public List<UserInfo> selectList2();

SQL语句太长时,使用加号 + 进行字符串拼接。

测试一下

(2)结果映射@Results

@Results 注解--MyBatis 注解方式 中用于字段映射配置 的注解,它告诉 MyBatis 如何将数据库查询结果的列(column)映射到 Java 实体类的属性(property)

@Results 注解包含一个或多个@Results 注解,每个 @Results注解对应一个字段的映射。

java 复制代码
    @Select("SELECT * FROM `user_info`")
    @Results({
            @Result(column = "delete_flag",property = "deleteFlag"),
            @Result(column = "create_time",property = "createTime"),
            @Result(column = "update_time",property = "updateTime")
    })
    List<UserInfo> selectList3();

测试一下

(3)开启驼峰命名(最推荐)

通常数据库列 使用蛇形命名法 进行命名(下划线 分割各个单词),而Java属性 ⼀般遵循驼峰命名法约定。

为了在这两种命名方式之间启用自动映射,需要将 mapUnderscoreToCamelCase 设置为 true

java 复制代码
mybatis:
  configuration:
    map-underscore-to-camel-case: true #配置驼峰⾃动转换

Java代码 做任何处理,添加上述配置,运行代码。

注:为规避Windows(不区分大小写)Linux(区分大小写) 之间的差异,数据库表名和字段名统一使用小写命名(确保在不同操作系统间的兼容性,避免因大小写不一致导致的查询错误)

3.3 参数传递 #{}

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

返回类型为 List<UserInfo> 是为了返回一个 UserInfo 对象组成的列表 ,每个UserInfo 对象对应数据库 中的一行数据,现在只有一行 数据,直接用UserInfo即可。

java 复制代码
@Select("SELECT * FROM `user_info` WHERE id = 3")
UserInfo selectById();

测试一下

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

解决方案:在 selectById 方法中添加一个参数(id),将方法中的参数,传给SQL语句 使用 #{}的方式获取方法中的参数。

java 复制代码
@Select("SELECT * FROM `user_info` WHERE id = #{id}")
UserInfo selectById2(Integer id);

测试一下

再写一个俩参数 的,此时返回多个结果仍需要List。

java 复制代码
@Select("SELECT * FROM `user_info` WHERE age = #{age} and gender = #{gender}")
List<UserInfo> selectByAgeAndGender(Integer age, Integer gender);

测试一下

注意:

3.4 增 @Insert

可以使用UserInfo对象获取参数 ,返回类型为修改的行数。

java 复制代码
@Insert("insert into user_info (username, `password`, age) " +
    "VALUE(#{username}, #{password}, #{age})")
Integer insertUser(UserInfo userInfo);

刷新一下

返回主键

3.5 删 @Delete

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

刷新一下

3.6 改 @Update

可以使用UserInfo对象获取参数

java 复制代码
@Update("update user_info set gender = #{gender}, delete_flag = #{deleteFlag} where id = #{id}")
Integer updateUser(UserInfo userInfo);

**@NoArgsConstructor 注解说明:**它会生成一个无参数的构造函数。

测试用例

刷新一下

4.MyBatis XML配置文件

关于开发中使用哪种模式这个问题,没有明确答案,自己随意,在公司跟内部用一样的。

4.1 配置连接字符串和MyBatis

此步骤需要进行两项 设置,数据库连接字符串 设置和 MyBatis 的 XML 文件配置。

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

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

# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件
mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml

classpath就表示resources目录

路径可以修改 ,如把mapper改成mybatis ,自己在resources 中建一个mybatis包即可。

4.2 写持久层代码

持久层代码分 部分:方法定义Interface、方法实现XXX.xml

(1)**方法定义:**添加mapper接口

数据持久层的接口定义

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

import java.util.List;

@Mapper
public interface UserInfoMapperXML {
    
    List<UserInfo> selectList();
}

(2)**方法实现:**添加 UserInfoXMLMapper.xml

数据持久成的实现 ,MyBatis的固定xml格式

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.UserInfoMapper">
 
</mapper>

创建UserInfoXMLMapper.xml ,路径参考yml中的配置

namespace表示要实现哪个接口, 根据自己的项目进行修改,可以按住类名 Ctrl+点击进去查看对不对。

安装一个插件 MybatisX ,可以方便生成一些代码

或者也可以直接 Alt+Enter 快捷键生成

还需要自己补上XML 文件中缺少的SQL 语句

sql 复制代码
select * from user_info

(3)单元测试

4.3 查(Select)

同样的,使用XML的方式进行查询,也存在数据封装 的问题;只有Java对象属性数据库字段一模一样 时,才会进行赋值

解决办法和注解 类似:起别名、结果映射、开启驼峰命名

其中13的解决办法和注解一样,不再多说,接下来看下xml如果来写结果映射

测试一下,可以先把配置文件中的驼峰配置自动转换代码删掉,测试完再加回去。

4.4 增(Insert)

与注解一样 ,可以使用UserInfo对象获取参数 ,返回类型为修改的行数。

方法定义:

java 复制代码
Integer insertUser(UserInfo userInfo);

方法实现:

XML 复制代码
    <insert id="insertUser">
        insert into user_info (username, `password`, age)
            VALUE(#{username}, #{password}, #{age})
    </insert>

测试一下



4.5 删(Delete)

方法定义:

java 复制代码
Integer deleteUserById(Integer id);        

方法实现:

XML 复制代码
    <delete id="deleteUserById">
        delete from user_info where id = #{id}
    </delete>

4.6 改(Update)

方法定义:

java 复制代码
Integer updateUser(UserInfo userInfo);  

方法实现:

XML 复制代码
    <update id="updateUser">
        update user_info set gender = #{gender}, delete_flag = #{deleteFlag} where id = #{id}
    </update>

5.其他查询操作

5.1 多表查询

(1)数据准备

上面建了⼀张用户表 ,我们再来建一张文章表 ,进行多表关联查询

文章表uid 对应用户表id

sql 复制代码
-- 创建文章表
DROP TABLE IF EXISTS article_info;
        
CREATE TABLE article_info (
        id INT PRIMARY KEY auto_increment,
        title VARCHAR ( 100 ) NOT NULL,
        content TEXT NOT NULL,
        uid INT NOT NULL,
        delete_flag TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',
        create_time DATETIME DEFAULT now(),
        update_time DATETIME DEFAULT now() 
) DEFAULT charset 'utf8mb4';

-- 插入测试数据
INSERT INTO article_info ( title, content, uid ) VALUES ( 'Java', 'Java正文', 1 );

创建实体类

先试试文章表可不可用

(2)数据查询

需求:根据uid查询作者的名称等相关信息

SQL语句

sql 复制代码
SELECT ta.*, tb.username, tb.age FROM `article_info` ta
left join user_info tb on ta.uid = tb.id
where ta.id = 1  

接口定义:要注意sql语句的空格 ,还有**参数#{}**修改。

java 复制代码
import com.example.mybatis.demo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface ArticleInfoMapper {

    @Select("SELECT ta.*, tb.username, tb.age FROM `article_info` ta " +
            "left join user_info tb on ta.uid = tb.id " +
            "where ta.id = #{id}")
    ArticleInfo queryArticleInfo(Integer id);
}

补充实体类

测试用例

5.2 #{}预编译SQL、${}即时SQL(面试题)

(1)#{}和${}的使用

Interger 和 String类型的参数

使用Idea自动生成测试类

观察打印的日志


(2)#{}和${}的区别

${}即时SQL--存在SQL注入的问题



5.3 排序功能


5.4 like查询


6.数据库连接池

6.1 介绍


6.2 使用

Hikari: SpringBoot 默认使用的数据库连接池。

Druid阿里巴巴 开源的数据库连接池项目,功能强大,性能优秀,是Java语言最好的数据库连接池之一。

官方地址:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter

学习文档:https://github.com/alibaba/druid/wiki/%E9%A6%96%E9%A1%B5

如果我们想把默认的数据库连接池切换为Druid数据库连接池, 只需要引入相关依赖即可。

XML 复制代码
<dependency>
 <groupId>com.alibaba</groupId>
 <artifactId>druid-spring-boot-3-starter</artifactId>
 <version>1.2.21</version>
</dependency>

如果SpringBoot版本为2.X,使用druid-spring-boot-starter依赖。

XML 复制代码
<dependency>
 <groupId>com.alibaba</groupId>
 <artifactId>druid-spring-boot-starter</artifactId>
 <version>1.1.17</version>
</dependency>

7.总结

7.1 MySQL开发企业规范

7.2 #{}和${}区别(面试题)

相关推荐
8 小时前
java关于内部类
java·开发语言
好好沉淀8 小时前
Java 项目中的 .idea 与 target 文件夹
java·开发语言·intellij-idea
gusijin8 小时前
解决idea启动报错java: OutOfMemoryError: insufficient memory
java·ide·intellij-idea
To Be Clean Coder8 小时前
【Spring源码】createBean如何寻找构造器(二)——单参数构造器的场景
java·后端·spring
吨~吨~吨~8 小时前
解决 IntelliJ IDEA 运行时“命令行过长”问题:使用 JAR
java·ide·intellij-idea
你才是臭弟弟8 小时前
SpringBoot 集成MinIo(根据上传文件.后缀自动归类)
java·spring boot·后端
短剑重铸之日8 小时前
《设计模式》第二篇:单例模式
java·单例模式·设计模式·懒汉式·恶汉式
码农水水8 小时前
得物Java面试被问:消息队列的死信队列和重试机制
java·开发语言·jvm·数据结构·机器学习·面试·职场和发展
summer_du8 小时前
IDEA插件下载缓慢,如何解决?
java·ide·intellij-idea
东东5168 小时前
高校智能排课系统 (ssm+vue)
java·开发语言