在线教育项目第一天

前置知识

Java基础
MySQL JDBC
JavaWeb servlet jsp cookie session filter listener
SSM Spring SpringMVC mybatis
Java高级 Redis Nginx Maven Git版本控制 Springboot

背景

在线教育是以网络为介质的教育方式
优势:随时随地都可以学习
在很多领域都很流行 母婴 学前教育 少儿教育 中小学生 高校学生 留学 执业考试 职业技能 成人外语 个人兴趣

商业模式

B2C Business Customer
    两个角色 管理员(增删改)和普通用户(查)
    在线教育使用这种模式 核心模块:课程模块
B2B2C
    电商使用这种模式
    京东
        普通用户可以买京东自营或普通商家的东西

功能模块

系统后台 管理员使用

讲师管理模块
课程分类管理模块
    后端 java/python/php...
    前端 JavaScript/vue/react...
课程管理模块
    课程 课程描述 章节 视频
统计分析模块
    统计某门课程的播放量 购买量,用图表展示
订单管理
    订单状态
    订单量
banner管理
    轮播图/幻灯片 从数据库中取出来展示
权限管理
    用户权限

系统前台 普通用户使用

首页数据显示
讲师列表和详情
课程列表和详情
    视频在线播放
    评论
登录注册
    微信扫码登录
微信扫码支付

技术点 前后端分离

后端

spring boot、spring cloud、MybatisPlus、spring security
redis maven easyExcel jwt OAuth2

前端

vue element-ui axios node.js

其它

阿里云oss存储服务、视频点播服务、短信服务
微信登录和支付
docker
git
jenkins

MybatisPlus 操作数据库

Mybatis的增强工具,进一步封装代码,简化开发
官网:http://mp.baomidou.com/ 教程/guide

入门

数据库准备
创建数据库mybatis_plus
创建表并插入数据
    CREATE DATABASE mybatis_plus;
    USE mybatis_plus;
    DROP TABLE IF EXISTS user;
    CREATE TABLE user
    (
        id BIGINT(20) NOT NULL COMMENT '主键ID',
        name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
        age INT(11) NULL DEFAULT NULL COMMENT '年龄',
        email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
        PRIMARY KEY (id)
    );
    DELETE FROM user;
    INSERT INTO user (id, name, age, email) VALUES
    (1, 'Jone', 18, 'test1@baomidou.com'),
    (2, 'Jack', 20, 'test2@baomidou.com'),
    (3, 'Tom', 28, 'test3@baomidou.com'),
    (4, 'Sandy', 21, 'test4@baomidou.com'),
    (5, 'Billie', 24, 'test5@baomidou.com');
创建项目
idea使用Spring Initializr创建一个springboot项目
    可以修改url为https://start.aliyun.com/ 否则可能会连接网络超时
    视频中将pomxml中的springboot的版本改为了2.2.1
引入相关依赖
MybatisPlus的依赖是baomidou的
    <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.0.5</version>
    </dependency>
    <!--mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--lombok用来简化实体类 加了注解不需要手写get和set方法以及有参无参方法-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
安装lombok插件
setting-plugin-搜索lombok
网络不好可以离线安装 在GitHub下载后setting-plugin-install from disk
配置src/main/resources/application.properties
springboot可以使用properties或yml文件作为配置文件
注意springboot版本 2.1之后driver-class-name要加上cj 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
编写代码
创建实体包entity和mapper
创建User类
@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
加上Data注解可以不用写get和set方法以及无参构造方法 可以在idea左下角的Structure中看到
创建UserMapper接口
mybatis中接口对应了一个xml文件,但MybatisPlus进行了封装,不需要自己创建xml文件了,只需要继承接口BaseMapper<T>
继承之后就可以调用已经封装好的增删改查方法
复杂的sql还是需要使用xml文件来实现
在启动类上加上注解MapperScan(“mapper包的地址”)
因为启动时会找接口对应的实现类对象,如果没有实现类就会找不到报错
加上后会扫描mapper包
在test包中的MpdemoApplicationTests进行测试
一般是controller调用service,service调用mapper
所以需要在controller中注入service,service中注入mapper
这里测试直接在类MpdemoApplicationTests中注入mapper
    @Autowired
    private UserMapper userMapper;
    这里会报错,因为UserMapper是一个接口,没有对应的实现类,找不到它的实现类对象
        不解决这个错误也可以运行
        要解决可以在UserMapper上加上任意一个注解Component/Service/Repository都可以
调用userMapper的方法selectList查询User表中的所有数据
    //查询User表所有数据
    @Test
    void testFindAll() {
        List<User> users = userMapper.selectList(null);
        System.out.println(users);
    }
    如果报错Access denied for user 'root'@'localhost'(Using Password YES)是密码错误
查看sql输出日志
    在application.properties中加上
        #mybatis日志
        mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
    就可以在输出窗口中看到调用方法具体的执行过程,包括生成的sql语句,参数以及返回结果
总结
写实体类User和mapper类UserMapper(继承BeanMapper<User>),调用UserMapper封装好的方法
可能遇到的错误:application.properties文件前面的标记不是叶子形状
解决:将文件复制到target/classes下
mp实现添加操作
User user = new User();
//这里不设置id,其是主键,mp会自动生成一个19位的唯一的id
user.setName("张三");
user.setAge(22);
user.setEmail("zhangsan@qq.com");
int insert = userMapper.insert(user);
System.out.println("insert" + insert);//影响的行数
主键生成策略 https://www.cnblogs.com/haoxinyue/p/5208136.html
自动增长 AUTO_INCREMENT
缺点:分表时不方便,需要得到上一张表的最后一个id,将其+1才能生成新表
     分表指的是一张表中数据过于庞大,分成几张表
UUID
生成随机的唯一的一个值
    b0c245ff-f915-4790-8b64-a5b9014bb6bd
缺点:排序不方便
优点:不需要关注上一张表的数据
redis生成id
主要依赖于Redis是单线程的,所以也可以用生成全局唯一的ID。可以用Redis的原子操作 INCR和INCRBY来实现
使用Redis集群来获取更高的吞吐量。假如一个集群中有5台Redis。可以初始化每台Redis的值分别是1,2,3,4,5,然后步长都是5。各个Redis生成的ID为:
    A:1,6,11,16,21
    B:2,7,12,17,22
    C:3,8,13,18,23
    D:4,9,14,19,24
    E:5,10,15,20,25
mp自带策略
使用Twitter的snowflake算法生成19位的唯一的值
使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),
12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0
    数据中心,如北京是001,天津是002
    机器ID,如北京数据中心有100台机器,001-100
配置策略
不配置策略默认mp自带策略,会自动识别属性类型来设置,数字类型默认ID_WORKER,字符串类型默认ID_WORKER_STR
配置策略是在对应属性上加注解@TableId(type = IdType.AUTO)
    idType后可以加
        AUTO自增长
        ID_WORKER mp自带策略 数字类型
        ID_WORKER_STR mp自带策略 字符串类型
        INPUT需要设置值 NONE需要设置值
        UUID
mp实现修改操作
User user = new User();
user.setId(2L);
user.setAge(120);
int i = userMapper.updateById(user);//修改user表中id=2的用户的年龄为100
System.out.println(i);
自动填充
在user表中加上两个字段create_time和update_time,类型都是datetime
在user类中加上两个属性createTime和updateTime,类型都是Date
注意字段和对应属性的命名规范,下划线转驼峰
加上字段和属性之后,再增加和修改记录,如果不设置时间,时间默认是null
自动填充就是不手动设置创建和修改时间,即setCreateTime和setUpdateTime,而是使用mp的方式来设置时间
    在user类中要自动填充的属性上添加注解@TableField(fill=FieldFill.INSERT/UPDATE/INSERT_UPDATE)
        //添加数据时自动填充
        @TableField(fill = FieldFill.INSERT)
        private Date createTime;
        //添加和修改数据时自动填充
        @TableField(fill = FieldFill.INSERT_UPDATE)
    创建类,实现接口MetaObjectHandler,复写方法insertFill和updateFill,
    注意加上注解Component/Service/Repository 表示交给spring进行管理,否则自动填充会失效
        @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);
            }
        }
        其中的metaObject是元数据对象,如表名、表字段
        注意createTime在添加数据时才会填充,所以它的注解是INSERT,且只在insertFill方法中才进行设置
        而updateTime在添加和修改数据时都会填充,所以它的注解是INSERT_UPDATE,且在insertFill和updateFill方法中都进行了设置
乐观锁
概念
主要解决丢失更新问题
事务是一组逻辑操作的基本单元,要么都成功,要么都失败
不考虑事务的隔离性,即并发情况下,会产生脏读、不可重复的、幻读的读问题以及丢失更新的写问题
例子
    张三和李四都去修改id为1的用户的工资,开始是500
    张三和李四都开启事务
    张三将工资改为1000,李四将工资改为300
    事务的提交都先后,张三先提交事务,改为了1000,李四又改为了300
    之后张三查询工资发现是300,这就是丢失更新现象
多个人同时修改同一条记录,后面的会覆盖前面的,即丢失更新
解决
悲观锁
    张三操作数据时,所有人都不能操作,张三操作完后,其他人才可以操作
    串行操作
乐观锁
    在表中加上字段version,默认为1
    张三和李四要操作数据,先获取version,都为1
    张三先提交事务,比较先前获取数据的version和当前数据库中的version是否一样,一样才可以修改,修改后将version+1
    李四再提交事务,发现自己先前获取的version和当前数据库中的version不一样,不能修改
    例子
        抢火车票
        当前打开12306的人都可以看到票只剩了一张,也都可以抢到,但只有一个人支付成功
    使用mp实现乐观锁
        表中加字段version INT
        实体类中加属性Integer version,并给属性加上注解@Version
        创建配置类MybatisPlusConfig,建议将所有配置操作,如关于插件的配置都加在该类中
        配置乐观锁插件
            @EnableTransactionManagement
            @Configuration
            @MapperScan("com.xm.mpdemo.mapper")
            public class MybatisPlusConfig {
                /**
                 * 乐观锁插件
                 */
                @Bean
                public OptimisticLockerInterceptor optimisticLockerInterceptor() {
                    return new OptimisticLockerInterceptor();
                }
            }
            加上注解@Configuration,会在启动springboot的同时加载配置类
            将启动类中的@MapperScan("com.xm.mpdemo.mapper")移到MybatisPlusConfig中
        在实体类的属性version上加上注解@TableField(fill = FieldFill.INSERT),使其在添加数据时被自动填充
        在MyMetaObjectHandler中的fillInsert方法中加上
            this.setFieldValByName("version", 1, metaObject);
        使用MpdemoApplicationTests的testInsert方法添加一条数据王五,默认version为1
        然后创建testOptimisticLocker方法,实现乐观锁,需要注意的是要实现乐观锁,要先查询再修改
            @Test
            void testOptimisticLocker() {
                //需要先查询再修改,才会有效果,version才会+1
                User user = userMapper.selectById(1363859734217646081L);
                user.setAge(120);
                userMapper.updateById(user);
            }
mp实现简单查询操作
selectById 根据id查询
selectBatchIds多个id批量查询
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    System.out.println(users);
selectByMap 简单的条件查询 通过map封装查询条件
mp实现分页查询操作 类似PageHelper
在MybatisPlusConfig中配置分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
创建testSelectPage方法
    new Page对象page,传入当前页码和每页显示记录数
    调用selectPage方法,传入page对象和查询条件wrapper,每页条件写null
    调用mp分页查询的过程中,底层会将所有分页数据封装到page对象中,可以通过遍历page对象获取所有分页数据
        current当前页 records每页list集合 size每页显示的记录数 total表中总记录数 pages总页数
        hasNext是否有下一页 hesPrevious是否有上一页
mp实现逻辑删除操作
逻辑删除指的是没有真正删除,而是加上了标记,查不到了
物理删除就是真正删除
    int i = userMapper.deleteById(1L);
    System.out.println(i);
批量删除
    int i = userMapper.deleteBatchIds(Arrays.asList(2, 3));
    System.out.println(i);
简单条件删除
    HashMap<String, Object> map = new HashMap<>();
    map.put("name", "Sandy");
    map.put("age", 21);
    int result = userMapper.deleteByMap(map);
    System.out.println(result);//1
逻辑删除
    表中加字段deleted tinyint 1
        可以加上Default属性为0
        或使用自动填充@TableField(fill = FieldFill.INSERT)并在fillInsert方法中加上
            this.setFieldValByName("deleted", 0, metaObject);
        两种方式只能使用一种
    实体类加属性Integer deleted,并加上注解@TableLogic
    application.properties加上
        mybatis-plus.global-config.db-config.logic-delete-value=1
        mybatis-plus.global-config.db-config.logic-not-delete-value=0
        默认删除为1,未删除为0,如果不进行修改可以不加这个配置
    MybatisPlusConfig加上逻辑删除插件
        @Bean
        public ISqlInjector sqlInjector() {
            return new LogicSqlInjector();
        }
    测试
        使用testInsert方法加上一条记录赵六,默认deleted为0
        使用testDeleteById方法逻辑删除
    查询时要加上where deleted=0,但使用mp查询会自动加上
    要查询已删除数据需要在mapper包中创建xml文件,在xml文件中使用sql语句进行查询,mp实现不了
性能分析插件配置
可以看到sql语句执行的时间,进而进行优化
MybatisPlusConfig中加上插件配置
    @Bean
    @Profile({"dev", "test"})//设置dev test环境开启,即对开发和测试环境生效
    public PerformanceInterceptor performanceInterceptor() {
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(100);
        performanceInterceptor.setFormat(true);
        return performanceInterceptor;
    }
application.properties
    #环境设置:dev test prod
    spring.profiles.active=dev
显示执行时间
    Time:3 ms - ID:com.xm.mpdemo.mapper.UserMapper.insert
mp实现复杂条件查询操作
一般使用QueryWrapper类构建条件,其继承于Wrapper
创建QueryWrapper类的对象
    QueryWrapper<User> wrapper = new QueryWrapper<User>();
调用QueryWrapper类的方法设置查询条件
    ge大于等于 gt大于 le小于等于 lt小于
        age大于等于30
        wrapper.ge("age", 30);
    eq 等于
        wrapper.eq("name", "王五");
    ne 不等于 <>
        wrapper.ne("name", "王五");
    between 范围
        wrapper.between("age", 20, 30);
    like 模糊查询
        wrapper.like("name", "lie");
    orderBy orderByDesc orderByAsc 排序
        wrapper.orderByDesc("age");
    last 拼接到sql语句最后
        wrapper.last("limit 1");
    指定要查询的列
        wrapper.select("id", "name", "age");
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值