商易通项目总结(一)(一款包含Spring+SpringBoot+SpringCloud+Mysql+Mybatis-plus+RabbitMq+Redis的医院挂号系统)

文章目录

  • 1.商易通架构图与业务流程图
  • 2.Mybatis-plus入门
    • 2.1 初始化工程
    • 2.2 引入依赖
    • 2.3 idea中安装lombok插件
    • 2.4编写代码
  • 3.主键策略
    • 3.1插入操作
    • 3.2Auto自增策略
  • 4.自动填充和乐观锁
    • 4.1更新操作
    • 4.2自动填充
  • 5.乐观锁
    • 5.1场景
    • 5.2乐观锁实现流程
  • 6.查询
    • 6.1通过多个Id批量查询
    • 6.2简单的条件查询
  • 7.分页
    • 7.1分页插件
    • 7.1.1添加分页插件
    • 7.1.2测试selectPage分页
    • 7.2测试selectMapsPage分页
  • 8.逻辑与逻辑删除
    • 8.1删除
    • 8.1.1根据id删除记录
    • 8.1.2批量删除
    • 8.1.3简单条件删除
    • 8.1.4物理删除和逻辑删除
    • 逻辑删除实现流程
    • 数据库修改
    • 实体类修改
    • 配置(可选)
    • 测试
    • 测试逻辑删除后的查询
  • 9.条件构造器
    • 9.1Wrapper介绍
    • 9.2查询方式
  • 10.重难点分析(包含项目中遇到的困难和问题都在里面)
  • 11.总结

1.商易通架构图与业务流程图

首先,我们需要明白这是个什么项目,它做的是一个医院挂号系统,所以在这个时候你需要做的就是先做到后台系统,也就是这个项目包含的是后台管理系统和用户系统,后台系统包含医院设置、数据字典、会员设置、订单管理、统计管理,然后前台用户系统分为:医院详情、用户登陆、就诊人管理、预约挂号、就医提醒模块。
商易通项目总结(一)(一款包含Spring+SpringBoot+SpringCloud+Mysql+Mybatis-plus+RabbitMq+Redis的医院挂号系统)_第1张图片
商易通项目总结(一)(一款包含Spring+SpringBoot+SpringCloud+Mysql+Mybatis-plus+RabbitMq+Redis的医院挂号系统)_第2张图片
下面是我作为面试者来书写的对应的简历,大家可以参考一下:
商易通项目总结(一)(一款包含Spring+SpringBoot+SpringCloud+Mysql+Mybatis-plus+RabbitMq+Redis的医院挂号系统)_第3张图片
当然了,对应的技术肯定远远不止这些,接下来我们来慢慢介绍:
首先我第一步介绍的技术就是Mybatis-plus,它是mybatis的增强,如果单纯使用mybatis的话,就会出现复杂的xml文件的配置,而且即便是很简单的增删查改都需要在xml中书写sql语句,在我看来还是很麻烦的,毕竟这个项目也不需要太多人来做,不用考虑耦合度,也就是自己看得懂还是建议使用mp好一些,因为mybatis其实它的优点就是方便语句的修改和管理,而mybatis如果在service中继承了IService之后,那么如果碰到分页查询,或者说一些复杂的查询的时候,就需要自己书写特定的接口来进行实现(当然,这里如果你听不懂的话没关系,我们先来学学Mybatis-plus)。

2.Mybatis-plus入门

2.1 初始化工程

使用 Spring Initializr 快速初始化一个 Spring Boot 工程
Group:com.atguigu
Artifact:mybatis_plus
版本:2.2.1.RELEASE

2.2 引入依赖

注意:引入 MyBatis-Plus 之后请不要再次引入 MyBatis,以避免因版本差异导致的问题。

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>

<!--mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok用来简化实体类-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

2.3 idea中安装lombok插件

2.3.1 idea2019版本
商易通项目总结(一)(一款包含Spring+SpringBoot+SpringCloud+Mysql+Mybatis-plus+RabbitMq+Redis的医院挂号系统)_第4张图片

2.3.2 idea2018版本
商易通项目总结(一)(一款包含Spring+SpringBoot+SpringCloud+Mysql+Mybatis-plus+RabbitMq+Redis的医院挂号系统)_第5张图片

2.4编写代码

2.4.1配置
接下来就是在application.propertites当中连接对应的数据源
在 application.properties 配置文件中添加 MySQL 数据库的相关配置:
spring boot 2.0(内置jdbc5驱动)
#mysql数据库连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root

spring boot 2.1及以上(内置jdbc8驱动)
注意:driver和url的变化
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root

注意:

1、这里的 url 使用了 ?serverTimezone=GMT%2B8 后缀,因为8.0版本的jdbc驱动需要添加这个后缀,否则运行测试用例报告如下错误:
java.sql.SQLException: The server time zone value ‘Öйú±ê׼ʱ¼ä’ is unrecognized or represents more
2、这里的 driver-class-name 使用了 com.mysql.cj.jdbc.Driver ,在 jdbc 8 中 建议使用这个驱动,否则运行测试用例的时候会有 WARN 信息
2.4.1启动类
首先在启动类上面,我们只需要加上MapperScan这个注解,看你的mapper在哪个包下面,你就进行那个对应的扫描,我的扫描是这样的:

@SpringBootApplication
@MapperScan("com.atguigu.demomptest.mapper")
public class DemomptestApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemomptestApplication.class, args);
    }

}

2.4.2添加实体
创建包 entity 编写实体类 User.java(此处使用了 Lombok 简化代码)

@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

2.4.3添加Mapper
添加Mapper首先需要做的就是建立一个对应的接口,在这里面进行的就是extends BaseMapper<实体名>:

@Repository
public interface UserMapper extends BaseMapper<User> {
}

2.4.4进行测试

@SpringBootTest
class DemomptestApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void findAll() {
        List<User> users = userMapper.selectList(null);
        System.out.println(users);
    }
}

这上面的代码应该可以很好地看懂了吧,也就是通过@Autowired注入对应的实例,然后在对应的里面进行的就是userMapper.selectList(null)就是的是查询,然后返回对应的users。
IDEA在 userMapper 处报错,因为找不到注入的对象,因为类是动态创建的,但是程序可以正确的执行。
为了避免报错,可以在 dao 层 的接口上添加 @Repository 注
通过以上几个简单的步骤,我们就实现了 User 表的 CRUD 功能,甚至连 XML 文件都不用编写!
查看控制台输出:
商易通项目总结(一)(一款包含Spring+SpringBoot+SpringCloud+Mysql+Mybatis-plus+RabbitMq+Redis的医院挂号系统)_第6张图片
2.4.4查看sql输出日志
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

3.主键策略

我们在对数据进行增添的时候,需要做的就是设置相应的编号,但是如果不加入注解的话,就会出现对应的

3.1插入操作

//添加

@Test
public void testAdd() {
    User user = new User();
    user.setName("lucy");
    user.setAge(20);
    user.setEmail("[email protected]");
    int insert = userMapper.insert(user);
    System.out.println(insert);
}

商易通项目总结(一)(一款包含Spring+SpringBoot+SpringCloud+Mysql+Mybatis-plus+RabbitMq+Redis的医院挂号系统)_第7张图片
我们会发现,当插入一个数据之后,发现id成了这样,这是因为我们没有在id这个栏上面加上对应的注解,也就是默认情况下使用的是雪花算法,下面我们来介绍一下什么是雪花算法:
MyBatis-Plus默认的主键策略是:ASSIGN_ID (使用了雪花算法)
@TableId(type = IdType.ASSIGN_ID)
private String id;
雪花算法:分布式ID生成器
雪花算法是由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键的有序性。
核心思想:
长度共64bit(一个long型)。
首先是一个符号位,1bit标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0。
41bit时间截(毫秒级),存储的是时间截的差值(当前时间截 - 开始时间截),结果约等于69.73年。
10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID,可以部署在1024个节点)。
12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID)。
商易通项目总结(一)(一款包含Spring+SpringBoot+SpringCloud+Mysql+Mybatis-plus+RabbitMq+Redis的医院挂号系统)_第8张图片
优点:整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率较高。

3.2Auto自增策略

需要在创建数据表的时候设置主键自增
实体字段中配置 @TableId(type = IdType.AUTO)
@TableId(type = IdType.AUTO)
private Long id;

要想影响所有实体的配置,可以设置全局主键配置
#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto

4.自动填充和乐观锁

4.1更新操作

在这个里面,我们需要理解的就是如何进行更新,首先是设置对应的数据,然后通过updateById来进行更新

//修改
@Test
public void testUpdate() {
    User user = new User();
    user.setId(1340868235401764865L);
    user.setName("lucymary");
    int count = userMapper.updateById(user);
    System.out.println(count);
}

4.2自动填充

需求描述:
项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。
我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作
4.2.1数据库修改
在User表中添加datetime类型的新的字段 create_time、update_time
4.2.2实体类修改
实体上增加字段并添加自动填充注解

@TableField(fill = FieldFill.INSERT)
private Date createTime;  //create_time

@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime; //update_time

4.2.3实现元对象处理器接口
注意:不要忘记添加 @Component 注解

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    //mp执行添加操作,这个方法执行
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }

    //mp执行修改操作,这个方法执行
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

5.乐观锁

5.1场景

主要适用场景:当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新
乐观锁实现方式:
取出记录时,获取当前version
更新时,带上这个version
执行更新时, set version = newVersion where version = oldVersion
如果version不对,就更新失败
接下来介绍如何在Mybatis-Plus项目中,使用乐观锁:

5.2乐观锁实现流程

5.2.1修改实体类
@Version
private Integer version;
5.2.2创建配置文件
4.2创建配置文件
创建包config,创建文件MybatisPlusConfig.java
此时可以删除主类中的 @MapperScan 扫描注解
@Configuration
@MapperScan(“com.atguigu.demomptest.mapper”)
public class MpConfig {
/**
* 乐观锁插件
/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
5.2.3注册乐观锁插件
在 MybatisPlusConfig 中注册 Bean
/
*

  • 乐观锁插件
    */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    return new OptimisticLockerInterceptor();
    }

6.查询

6.1通过多个Id批量查询

完成了动态sql的foreach功能

//多个id批量查询
@Test
public void testSelect1() {
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    System.out.println(users);
}

6.2简单的条件查询

通过map封装查询条件
注意:map中的key对应数据库中的列名。如:数据库user_id,实体类是userId,这时map的key需要填写user_id
//简单条件查询

@Test
public void testSelect2() {
    Map<String, Object> columnMap = new HashMap<>();
    columnMap.put("name","Jack");
    columnMap.put("age",20);
    List<User> users = userMapper.selectByMap(columnMap);
    System.out.println(users);
}

7.分页

7.1分页插件

MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能

7.1.1添加分页插件

配置类中添加@Bean配置
/**

  • 分页插件
    */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
    }

7.1.2测试selectPage分页

测试:最终通过page对象获取相关数据
//分页查询
@Test
public void testSelectPage() {
Page page = new Page(1,3);
Page userPage = userMapper.selectPage(page, null);
//返回对象得到分页所有数据
long pages = userPage.getPages(); //总页数
long current = userPage.getCurrent(); //当前页
List records = userPage.getRecords(); //查询数据集合
long total = userPage.getTotal(); //总记录数
boolean hasNext = userPage.hasNext(); //下一页
boolean hasPrevious = userPage.hasPrevious(); //上一页

System.out.println(pages);
System.out.println(current);
System.out.println(records);
System.out.println(total);
System.out.println(hasNext);
System.out.println(hasPrevious);

}

7.2测试selectMapsPage分页

当指定了特定的查询列时,希望分页结果列表只返回被查询的列,而不是很多null值
测试selectMapsPage分页:结果集是Map
@Test
public void testSelectMapsPage() {
//Page不需要泛型
Page> page = newPage<>(1, 5);
Page> pageParam = userMapper.selectMapsPage(page, null);
List> records = pageParam.getRecords();
records.forEach(System.out::println);
System.out.println(pageParam.getCurrent());
System.out.println(pageParam.getPages());
System.out.println(pageParam.getSize());
System.out.println(pageParam.getTotal());
System.out.println(pageParam.hasNext());
System.out.println(pageParam.hasPrevious());
}

8.逻辑与逻辑删除

8.1删除

8.1.1根据id删除记录

@Test
public void testDeleteById(){
int result = userMapper.deleteById(5L);
system.out.println(result);
}

8.1.2批量删除

@Test
public void testDeleteBatchIds() {
int result = userMapper.deleteBatchIds(Arrays.asList(8, 9, 10));
system.out.println(result);
}

8.1.3简单条件删除

@Test
public void testDeleteByMap() {
HashMap<String, Object> map = new HashMap<>();
map.put("name", "Helen");
map.put("age", 18);
    int result = userMapper.deleteByMap(map);
system.out.println(result);
}

接下来我们要将一个重点,那就是逻辑删除,也就是并非使用到的是物理删除,它删除之后只是改变了对应的delete的编号,只是从0变成了1

8.1.4物理删除和逻辑删除

物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据
逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录

逻辑删除的使用场景:
可以进行数据恢复
有关联数据,不便删除

逻辑删除实现流程

数据库修改

添加 deleted字段
ALTERTABLE user ADD COLUMN deleted boolean DEFAULT false

实体类修改

添加deleted 字段,并加上 @TableLogic 注解
@TableLogic
private Integer deleted;

配置(可选)

application.properties 加入以下配置,此为默认值,如果你的默认值和mp默认的一样,该配置可无

mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

测试

测试后发现,数据并没有被删除,deleted字段的值由0变成了1
测试后分析打印的sql语句,是一条update
注意:被删除前,数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作

@Test
public void testLogicDelete() {
    int result = userMapper.deleteById(1L);
system.out.println(result);
}

测试逻辑删除后的查询

MyBatis Plus中查询操作也会自动添加逻辑删除字段的判断

@Test
public void testLogicDeleteSelect() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}

9.条件构造器

接下来,我们来到文章的末尾了,也是比较重要的地方,那就是条件构造器,当我们遇到mp中没有配置的方法(这里可能有点口误,就是假如你要删除一个东西,但是这个东西在mp当中没有设置对应的参数来来对应这个方法的时候,那么你就需要用到它

9.1Wrapper介绍

商易通项目总结(一)(一款包含Spring+SpringBoot+SpringCloud+Mysql+Mybatis-plus+RabbitMq+Redis的医院挂号系统)_第9张图片
Wrapper : 条件构造抽象类,最顶端父类
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
QueryWrapper : 查询条件封装
UpdateWrapper : Update 条件封装
AbstractLambdaWrapper : 使用Lambda 语法
LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapper : Lambda 更新封装Wrapper

@SpringBootTest
publicclassQueryWrapperTests {

@Autowired
privateUserMapperuserMapper;
}

2、测试用例
2.1 ge、gt、le、lt、isNull、isNotNull

@Test
public void testQuery() {
QueryWrapper<User>queryWrapper = newQueryWrapper<>();
queryWrapper
        .isNull("name")
        .ge("age", 12)
        .isNotNull("email");
    int result = userMapper.delete(queryWrapper);
System.out.println("delete return count = " + result);
}

2.2 eq、ne
注意:seletOne()返回的是一条实体记录,当出现多条时会报错

@Test
public void testSelectOne() {
QueryWrapper<User>queryWrapper = newQueryWrapper<>();
queryWrapper.eq("name", "Tom");
Useruser = userMapper.selectOne(queryWrapper);//只能返回一条记录,多余一条则抛出异常
System.out.println(user);
}

2.3 between、notBetween
包含大小边界

@Test
public void testSelectCount() {
QueryWrapper<User>queryWrapper = newQueryWrapper<>();
queryWrapper.between("age", 20, 30);
    Integer count = userMapper.selectCount(queryWrapper); //返回数据数量
System.out.println(count);
}

2.4 like、notLike、likeLeft、likeRight

selectMaps()返回Map集合列表,通常配合select()使用
@Test
public void testSelectMaps() {
QueryWrapper<User>queryWrapper = newQueryWrapper<>();
queryWrapper
        .select("name", "age")
        .like("name", "e")
        .likeRight("email", "5");
List<Map<String, Object>>maps = userMapper.selectMaps(queryWrapper);//返回值是Map列表
maps.forEach(System.out::println);
}

2.5 orderBy、orderByDesc、orderByAsc

@Test
public void testSelectListOrderBy() {
QueryWrapper<User>queryWrapper = newQueryWrapper<>();
queryWrapper.orderByDesc("age", "id");
List<User>users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}

9.2查询方式

商易通项目总结(一)(一款包含Spring+SpringBoot+SpringCloud+Mysql+Mybatis-plus+RabbitMq+Redis的医院挂号系统)_第10张图片
商易通项目总结(一)(一款包含Spring+SpringBoot+SpringCloud+Mysql+Mybatis-plus+RabbitMq+Redis的医院挂号系统)_第11张图片
商易通项目总结(一)(一款包含Spring+SpringBoot+SpringCloud+Mysql+Mybatis-plus+RabbitMq+Redis的医院挂号系统)_第12张图片

10.重难点分析(包含项目中遇到的困难和问题都在里面)

  1. 在mybatis当中,首先需要对应的就是mapper、service接口以及ServiceImpl中对应的实现类该进行的是什么。
  2. 对应的分页查询,在mp当中有固定的插件,你需要进行的就是selectPage这些方法的明白
  3. 接下来就是对应的主键策略,首先默认的就是雪花算法,那么在这里如果我们想要让每次插入之后的数据都达到一个自增的状态,那么就需要在id这个字段上面添加auto的注解
  4. 在逻辑删除这个过程当中,假如我们真的想要永远删除一个数据的时候,那么这个时候就可以用到的就是物理删除,但是如果我们还想要在每次删除之后做到一个特定的备份,那么这个时候我们就可以使用@Logic那样的注解来进行每次的逻辑删除。
  5. 还有就是接下来要讲得mybatis和mybatis-plus对应的矛盾问题,那就是当我们要查询或者删除某些特定的数据的时候,这个时候直接用mp提供的方法是不能达到目标的,那么这个时候就需要用到自己特定接口,然后再实现类中进行Wrapper的使用。
    6.mp当中的语句也要不断地练习,例如多个id进行查询和删除这些简单的语句。

11.总结

这是第一篇关于项目的文章,如果有哪些地方写的不够好,还请大家见谅,明怀我下次一定注意,好啦,我们下期见。

你可能感兴趣的:(我的面试,spring,redis,spring,boot)