Spring - 8 ( 10000 字 Spring 入门级教程 )

一: MyBatis

1.1 引入 MyBatis

我们学习 MySQL 数据库时,已经学习了 JDBC 来操作数据库, 但是 JDBC 操作太复杂了.

我们先来回顾⼀下 JDBC 的操作流程:

  1. 创建数据库连接池 DataSource
  2. 通过 DataSource 获取数据库连接 Connection
  3. 编写要执行带 ? 占位符的 SQL 语句
  4. 通过 Connection 及 SQL 创建操作命令对象 Statement
  5. 替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值
  6. 使用 Statement 执行 SQL 语句
  7. 查询操作:返回结果集 ResultSet,更新操作:返回更新的数量
  8. 处理结果集
  9. 释放资源

对于 JDBC 来说,整个操作非常的繁琐,我们不但要拼接每⼀个参数,而且还要按照模板代码方式,⼀步步的操作数据库,并且在每次操作完,还要手动关闭连接等,而所有的这些操作步骤都需要在每个方法中重复书写. 那有没有⼀种方法,可以更单、更方便的操作数据库呢?

这就是我们要学习 MyBatis 的真正原因,它可以帮助我们更方便、更快速的操作数据
库.

1.2 什么是 MyBatis

MyBatis 是⼀款优秀的持久层框架,⽤于简化 JDBC 的开发。

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

在这里插入图片描述

二: MyBatis 入门

Mybatis操作数据库的步骤:

  1. 准备工作 (创建 springboot 工程、数据库表准备、实体类)
  2. 引入 Mybatis 的相关依赖,配置 Mybatis (数据库连接信息)
  3. 编写 SQL 语句 (注解 / XML)
  4. 测试

2.1 创建工程

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

在这里插入图片描述

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

  1. 项目工程创建完成后自动在 pom.xml ⽂件中,导入 Mybatis 依赖和 MySQL 驱动依赖
<!--Mybatis 依赖包-->
<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>2.3.1</version>
</dependency>

<!--mysql驱动包-->
<dependency>
	<groupId>com.mysql</groupId>
	<artifactId>mysql-connector-j</artifactId>
	<scope>runtime</scope>
</dependency>

2.2 数据准备

  1. 创建用户表, 并创建对应的实体类 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');
  1. 创建对应的实体类 UserInfo
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.3 配置数据库连接字符串

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

  • MySQL驱动类
  • 登录名
  • 密码
  • 数据库连接字符串
  1. application.yml 文件
# 数据库连接配置
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
  1. application.properties 文件
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#数据库连接的url
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false

#连接数据库的⽤⼾名
spring.datasource.username=root

#连接数据库的密码
spring.datasource.password=root

2.4 写持久层代码

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

在这里插入图片描述

import com.example.demo.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();
}
  • @Mapper注解:这个注解标识了这个接口是一个 MyBatis 的 Mapper 接口,它告诉MyBatis框架要为这个接口创建一个实现类,并且这个实现类会自映射SQL语句的方法。
  • @Select注解:这个注解标识了 queryAllUser() 方法使用的查询语句,当需要执行数据库操作时,应用程序会调用 UserInfoMapper 接口中的 queryAllUser() 方法。

注意:Mybatis 的持久层接口规范⼀般都叫 XxxMapper

2.5 单元测试

2.5.1 使用 test 测试类

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

import com.example.demo.mapper.UserInfoMapper;
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;

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    private UserInfoMapper userInfoMapper;
    
    @Test 
    void contextLoads() {
        List<UserInfo> userInfoList = userInfoMapper.queryAllUser();
        System.out.println(userInfoList);
    }
}
  • @SpringBootTest 用于指示该类是一个 Spring Boot 应用程序的集成测试类。这个注解告诉测试运行器去加载整个 Spring 应用程序上下文,包括所有的 bean,并为测试提供一个实例化的应程序环境。
  • @Test 注解用于标识一个测试方法。当运行测试类时,它会搜索类中带有 @Test 注解的方法,并执行这些方法。

运行结果如下:

在这里插入图片描述

返回结果中, 可以看到, 只有 SQL 语句中查询的列对应的属性才有赋值

2.5.2 使用 Idea 自动生成测试类

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

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

在这里插入图片描述
2. 选择要测试的方法, 点击 OK

在这里插入图片描述

  1. 书写测试代码
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;

@SpringBootTest
class UserInfoMapperTest {

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

记得加 @SpringBootTest 注解, 加载 Spring 行环境

运行结果:

在这里插入图片描述

三: MyBatis 的基础操作

上面我们学习了 Mybatis 的查询操作, 接下来我们学习 MyBatis 的增, 删, 改操作,在学习这些操作之前, 我们先来学习 MyBatis 日志打印

3.1 打印日志

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

  1. yml 配置
mybatis:
	configuration: # 配置打印 MyBatis⽇志
		log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  1. properties 配置
#指定mybatis输出⽇志的位置, 输出控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

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

在这里插入图片描述

  • ①: 查询语句
  • ②: 传递参数及类型
  • ③: SQL执行结果

3.2 参数传递

@Select("select username, `password`, age, gender, phone from userinfo where id= 4 ")
UserInfo queryById();

这条语句只能查找 id=4 的数据,有时候我们需要 id 的数值是动态的,我们该怎么做呢

解决方案:

  1. 在 queryById 方法中添加⼀个参数 (id),将方法中的参数,传给 SQL 语句
  2. 然后使用 #{} 的方式获取方法中的参数
@Select("select username, `password`, age, gender, phone from userinfo where id= #{id} ")
UserInfo queryById(Integer id);

如果 mapper 接口方法形参只有⼀个普通类型的参数,#{…} 里面属性名可以随便写,但如果有多个参数的话,建议和参数名保持⼀致

  1. 测试用例
@Test
void queryById() {
        UserInfo userInfo = userInfoMapper.queryById(4);
        System.out.println(userInfo);
}
  1. 运行结果

在这里插入图片描述

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

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

3.3 增 (Insert)

  1. SQL 语句:
insert into userinfo (username, `password`, age, gender, phone) values ("zhaoliu","zhaoliu",19,1,"18700001234")
  1. 把 SQL 中的常量替换为动态的参数,用 Mapper 接口:
@Insert("insert into userinfo (username, `password`, age, gender, phone) values (#{username},#{password},#{age},#{gender},#{phone})")
Integer insert(UserInfo userInfo);
  1. 测试代码:
@Test
void insert() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("zhaoliu");
        userInfo.setPassword("zhaoliu");
        userInfo.setGender(2);
        userInfo.setAge(21);
        userInfo.setPhone("18612340005");
        userInfoMapper.insert(userInfo);
}
  1. 如果设置了 @Param 属性, #{…} 需要使用参数.属性来获取
@Insert("insert into userinfo (username, `password`, age, gender, phone) values (#{userinfo.username},#{userinfo.password},#{userinfo.age},#{userinfo.gender},#{userinfo.phone})")
Integer insert(@Param("userinfo") UserInfo userInfo);

3.3.1 返回主键

Insert 语句默认返回的是受影响的行数,但有些情况下我们需要获取到新插入数据的 id ,如果想要拿到自增 id, 需要在 Mapper 接口的方法上添加⼀个 Options 的注解

@Options(useGeneratedKeys = true, keyProperty = "id")
@Insert("insert into userinfo (username, age, gender, phone) values (#{userinfo.username},#{userinfo.age},#{userinfo.gender},#{userinfo.phone})")
Integer insert(@Param("userinfo") UserInfo userInfo);
  • @Options: 这是 Myatis 中的一个注解,用于配置一些选项以影响 SQL 语句的执行方式。
  • useGeneratedKeys = true 这个选项告诉 MyBatis 使用数据库自动生成的主键。
  • Property = “id”: 这个选项指定了用来接收生成的主键值的属性名。这个例子中,自动生成的主键值将会被赋给 UserInfo 对象中名为 id 的属性。

测试数据:

@Test
void insert() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("zhaoliu");
        userInfo.setPassword("zhaoliu");
        userInfo.setGender(2);
        userInfo.setAge(21);
        userInfo.setPhone("18612340005");
        Integer count = userInfoMapper.insert(userInfo);
        System.out.println("添加数据条数:" +count +", 数据ID:" + userInfo.getId());
}

运行结果:

在这里插入图片描述

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

3.4 删(Delete)

SQL 语句:

delete from userinfo where id=6

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

@Delete("delete from userinfo where id = #{id}")
void delete(Integer id);

3.5 改(Update)

SQL 语句:

update userinfo set username="zhaoliu" where id=5

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

@Update("update userinfo set username=#{username} where id=#{id}")
void update(UserInfo userInfo);

3.6 查(Select)

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

@Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time from userinfo")
List<UserInfo> queryAllUser();
  1. 查询结果:

在这里插入图片描述

从运行结果上可以看到, 我们 SQL 语句中, 查询了 delete_flag, create_time, update_time, 但是这几个属性却没有赋值.

  1. 原因分析:

当自动映射查询结果时,MyBatis 会获取结果中返回的列名并在 Java 类中查找相同名字的属性(忽略大小写)。 这意味着如果发现了 ID 列和 id 属性,MyBatis 会将列 ID 的值赋给 id 属性,但如果名字不一样就无法进行赋值了。

在这里插入图片描述

解决办法:

  1. 起别名
  2. 结果映射
  3. 开启驼峰命名

注意:MyBatis 会根据方法的返回结果进行赋值.

  • 方法用对象 UserInfo 接收返回结果, MySQL 查询出来数据为⼀条, 就会自动赋值给对象.
  • 方法用 List< UserInfo > 接收返回结果, MySQL 查询出来数据为⼀条或多条时, 也会自动赋值给 List.
  • 但如果 MySQL 查询返回多条, 但是方法使用 UserInfo 接收, MyBatis 执行就会报错.

3.6.1 起别名

在 SQL 语句中,给列名起别名,保持别名和实体类属性名⼀样

@Select("select id, username, `password`, age, gender, phone, delete_flag as deleteFlag, " + "create_time as createTime, update_time as updateTime from userinfo")
public List<UserInfo> queryAllUser();

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

3.6.2 结果映射

@Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time from userinfo")
@Results({
	@Result(column = "delete_flag",property = "deleteFlag"),
	@Result(column = "create_time",property = "createTime"),
	@Result(column = "update_time",property = "updateTime")
})
List<UserInfo> queryAllUser();

如果其他 SQL, 也希望可以复用这个映射关系, 可以给这个 Results 定义⼀个名称

@Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time from userinfo")
@Results(id = "resultMap",value = {
	@Result(column = "delete_flag",property = "deleteFlag"),
	@Result(column = "create_time",property = "createTime"),
	@Result(column = "update_time",property = "updateTime")
})
List<UserInfo> queryAllUser();

@Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time " + "from userinfo where id= #{userid} ")

@ResultMap(value = "resultMap")
UserInfo queryById(@Param("userid") Integer id);

使用 id 属性给该 Results 定义别名, 使用 @ResultMap 注解来复用其他定义的 ResultMap

在这里插入图片描述

3.6.3 开启驼峰命名 (推荐)

通常数据库列使用蛇形命名法进行命名,而 Java 属性⼀般遵循驼峰命名法约定,为了在这两种命名方式之间启用自动映射,需要将 mapUnderscoreToCamelCase 设置为 true。

mybatis:
	configuration:
		map-underscore-to-camel-case: true #配置驼峰⾃动转换

Java 代码不做任何处理

@Select("select id, username, `password`, age, gender, phone, delete_flag as deleteFlag, " + "create_time as createTime, update_time as updateTime from userinfo")
public List<UserInfo> queryAllUser();

添加上述配置, 运行代码:

在这里插入图片描述

字段全部进行正确赋值.

  • 18
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
spring-boot-starter-data-jpa 是 Spring Boot 提供的一个快速开发 JPA 应用的起步依赖。它提供了一系列默认的配置和依赖,方便我们快速地使用 JPA 进行开发。 以下是入门步骤: 1. 添加依赖:在 pom.xml 文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> ``` 2. 配置数据源:在 application.properties 或 application.yml 文件中配置数据库连接信息,例如: ```properties spring.datasource.url=jdbc:mysql://localhost:3306/mydb spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.jdbc.Driver ``` 3. 创建实体类:创建一个用于映射数据库表的实体类,例如: ```java @Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private Integer age; // 省略 getter 和 setter 方法 } ``` 4. 创建 Repository 接口:创建一个继承 JpaRepository 接口的 Repository 接口,例如: ```java public interface UserRepository extends JpaRepository<User, Long> { } ``` 5. 使用 Repository:在业务逻辑中使用 UserRepository 进行增删改查操作,例如: ```java @Service public class UserService { @Autowired private UserRepository userRepository; public User save(User user) { return userRepository.save(user); } public User findById(Long id) { return userRepository.findById(id).orElse(null); } public List<User> findAll() { return userRepository.findAll(); } public void deleteById(Long id) { userRepository.deleteById(id); } } ``` 以上就是使用 spring-boot-starter-data-jpa 开发 JPA 应用的基本步骤。需要注意的是,该起步依赖默认使用 Hibernate 作为 JPA 的实现,因此需要添加 Hibernate 的相关依赖。同时,也可以根据需要进行自定义配置,例如配置 JPA 的缓存、事务管理等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ice___Cpu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值