文章目录
根据 尚硅谷 的谷粒学院项目所做笔记 仅供参考
概述
1.介绍项目的背景
这是一个在线教育系统,项目背景 找度娘
2.介绍项目采用的商业模式
B2C模式(Business To Customer 会员模式):
两个角色: 管理员 和 普通用户
管理员: 添加 修改 删除
普通用户: 查询
在线教育系统使用这种模式,核型模块-> 课程模块
B2B2C
例如 京东: 普通用户 可以买到 自营, 也可以买到 普通商家
3.介绍项目实现的功能模块
B2C模式:
系统后台: 管理员使用
- 讲师管理模块
- 课程分类管理模块
- 课程管理模块
- 视频
- 统计分析模块
- 订单管理
- banner管理
- 权限管理
系统前台 : 普通用户使用
- 首页数据展示
- 讲师列表和详情
- 课程列表和课程详情
- 视频在线播放
- 登录和注册功能
- 微信扫描登录
- 微信扫描支付
4.介绍项目使用的技术
项目使用 前后端分离开发
后端技术:
springboot springcloud MybatisPlus spring security
redis maven easyExcel jwt OAuth2
前端技术:
vue + element-ui + axios + node.js
其他技术:
阿里云oss 阿里云视频点播服务 阿里云短信服务
微信支付 docker git jenkins
5.学习技术-MybatisPlus
Mybatis-Plus 牛刀小试
(1)创建一个springboot项目(这个会的都会)
最重要的一步,配置properties配置文件
# 配置数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=UTF8
spring.datasource.username=root
spring.datasource.password=034312
# mybatis 输出日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
(2)导包:主要是 mybatis-plus-boot-starter 和 velocity-engine-core
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<!-- 插件管理 -->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
</plugin>
</plugins>
<!-- 资源管理 -->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.conf</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.conf</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
(3)创建domain
@Data
public class Student {
private Integer sid;
private String name;
private String age;
}
(4)创建mapper
@Repository
public interface StudentMapper extends BaseMapper<Student> {
}
记得在启动类上加上 @MapperScan 注解 哦
@SpringBootApplication
@MapperScan("com.zhj.mapper")
public class MpPracticeApplication {
public static void main(String[] args) {
SpringApplication.run(MpPracticeApplication.class, args);
}
}
(5)测试
在生成springboot项目时 会生成一个测试类 做一下简单测试
@SpringBootTest
class MpPracticeApplicationTests {
@Autowired
private StudentMapper studentMapper;
@Test
void contextLoads() {
List<Student> students = studentMapper.selectList(null);
System.out.println(students);
}
}
Mybatis-Plus 之insert
@Test
void add(){
Student student = new Student();
student.setName("mmm");
student.setAge(13);
int insert = studentMapper.insert(student);
System.out.println(insert); // 返回影响的行数
}
默认主键策略 采用的使用 Mybatis-Plus 自带的增长策略
几种常见的主键策略:
- 自动增长策略(msql中设置auto_increment,但是不利于分库分表)
- UUID(生成 32 唯一标识,但是无法排序)
- redis
- mp自带策略(根据snowflake算法,生成一串 19位数字)
可以在实体类中进行配置,例如
@Data
public class Student {
@TableId(type = IdType.AUTO)
private Long sid;
private String name;
private Integer age;
}
IdType.AUTO:自动增长
IdType.ID_WORKER: mp自带 ,Long类型
IdType.ID_WORKER_STR: mp自带,String类型
IdType.INPUT:手动输入
IdType.NONE:手动输入
IdType.UUID :随机唯一
Mybatis-Plus insert and update --> 自动填充功能
例如:domain
Data
public class User {
@TableId(type = IdType.ID_WORKER)
private Long id;
private String name;
private int age;
private Date createTime; // 这里使用驼峰式 对应表中应该使用 下划线(create_time)的形式
private Date updateTime;
}
中间细节如上
@Test
void addUser(){
User user = new User();
user.setName("lisi");
user.setAge(14);
user.setCreateTime(new Date());
user.setUpdateTime(new Date());
userMapper.insert(user);
}
每次增加,都需要自己setCreateTime setUpdateTime一个时间
解决方法:使用Mybatis-Plus 自动填充功能
-
1.在实体类中添加注解
@Data public class User { @TableId(type = IdType.ID_WORKER) private Long id; private String name; private int age; @TableField(fill= FieldFill.INSERT) private Date createTime; // 这里使用驼峰式 对应表中应该使用 下划线(create_time)的形式 @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; }
-
2.创建一个类,实现MetaObjectHandler,重写两个方法,注意 加上@Component 注解
@Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { // 属性 , 创建时间 , 数据源对象(就是字段名) this.setFieldValByName("createTime",new Date(),metaObject); this.setFieldValByName("updateTime",new Date(),metaObject); } @Override public void updateFill(MetaObject metaObject) { this.setFieldValByName("updateTime",new Date(),metaObject); } }
-
3.测试
@Test void updateUser(){ User user = new User(); user.setId(1449526992241463297L); user.setName("李四"); user.setAge(14); userMapper.updateById(user); }
乐观锁
乐观锁: 解决问题
主要解决 丢失更新问题
如果不考虑事务隔离性,产生读的问题?
脏读 不可重复读 幻读
写问题: 丢失更新问题
多人同时修改同一条数据,最后提交的(一个人)把之前的提交数据覆盖
乐观锁主要使用场景:当要更行一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新
乐观锁的实现原理:
- 取出记录时,获取当前versioin
- 更新时,带上这个version
- 执行更新时,set version = newVersion where version = oldVersion
- 如果version 不对,就更新失败
Mybatis-Plus实现方式
-
数据库中添加version字段
alter table user add column version int
-
实体类添加versioin字段
并添加@Version注解
@Version @TableField(fill=FieldFill.Insert) private Integer version;
-
元对象处理器接口添加version的insert默认值
@Override public void insertFill(MetaObject metaObject) { ...... // 创建一个对象默认 version = 1 this.setFieldValByName("version",1,metaObject); }
注意:这里支持的数据类型只有 int Integer long Long Date Timestamp LocalDateTime
-
配置MybatisPlus配置类,配置乐观锁插件
@Configuration @MapperScan("com.zhj.mapper") @EnableTransactionManagement public class MybatisPlusConfig { /* 乐观锁插件 */ @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor (){ return new OptimisticLockerInterceptor(); } }
-
测试:先查询 在修改
/* 乐观锁测试 */ @Test void updateUserByOptimistic(){ // 先查询 User user = userMapper.selectById(1449526992241463297L); // 在修改 user.setAge(120); int i = userMapper.updateById(user); System.out.println(i); // 才能看到结果 测试 version 是否变化 }
Mybatis-Plus 查询
-
简单 id 查询
T selectById(Serializable id);
-
多个id批量查询
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
-
条件查询
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
-
分页查询
实现:
-
配置分页插件
/* 分页插件 */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2)); return interceptor; }
-
测试
/* 分页插件测试 */ @Test void pageHelperTest(){ // 1 创建page 对象 Page<User> page = new Page<>(0,1); // 2 把分页所有数据封装到 page 中 userMapper.selectPage(page,null); // 3 通过page 获取当前数据 System.out.println("当前页:"+page.getCurrent()); System.out.println("每页数据的list集合:"+page.getRecords()); System.out.println("每页显示的记录数:"+page.getSize()); System.out.println("总记录数:"+page.getTotal()); System.out.println("总页数:"+page.getPages()); System.out.println("是否有上一页:"+page.hasPrevious()); System.out.println("是否有下一页:"+page.hasNext()); }
-
Mybatis-Plus 之删除操作
物理删除: 真是删除,将对应数据从数据库中删除,之后查询不到此条被删除数据
逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后再数据库中仍旧能看到此条数据记录
-
物理 删除一条数据:
int deleteById(Serializable id);
-
物理删除 批量数据:
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
-
物理删除 条件:
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
-
逻辑删除
第一步:添加逻辑删除字段,对应实体添加属性,属性添加@TabledLogic 注解
@TableLogic @TableField(fill= FieldFill.INSERT) private Integer deleted;
第二步:配置逻辑删除插件
mybatis plus高版本不需要配置注入逻辑删除 ,不需要配置逻辑删除插件
/* 逻辑删除插件 */ @Bean public ISqlInjector sqlInjector() { return new LogicSqlInjector(); }
第三步(可以省略):
此为默认值,如果你的默认值和 mp 默认的一样 , 该配置可无
mybatis-plus.global-config.db-config.logic-delete-value=1 mybatis-plus.global-config.db-config.logic-not-delete-value=0
第四步:使用 同物理删除同样的方法 进行测试
@Test void deleteByLogic(){ int i = userMapper.deleteById(5L); System.out.println(i); }
如果是高版本的 ,只需要配置 第一、四步
Mybatis-Plus默认为物理删除,通过配置 @TableLogic 之后 就会变为逻辑删除
性能分析
性能分析拦截器,用于输出每条SQL语句及其执行时间
SQL性能执行分析,开发环境使用,超过指定时间 ,停止运行,有助于发现问题
插件功能:该功能依赖
p6spy
组件,完美的输出打印 SQL 及执行时长,3.1.0
以上版本支持
添加依赖:
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>3.9.1</version>
</dependency>
配置:
-
修改配置:application.properties在MybatisPlusConfig中配置
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #spring.datasource.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=UTF8 #spring.datasource.username=root #spring.datasource.password=034312 spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver spring.datasource.url=jdbc:p6spy:mysql://localhost:3306/ssm?characterEncoding=UTF8 spring.datasource.username=root spring.datasource.password=034312
-
创建properties文件配置:spy.properties
# 3.2.1以上使用 modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory # 自定义日志打印 logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger # 日志输出到控制台 appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger # 使用日志系统记录 sql #appender=com.p6spy.engine.spy.appender.Slf4JLogger # 设置 p6spy driver 代理 deregisterdrivers=true # 取消JDBC URL前缀 useprefix=true # 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset. excludecategories=info,debug,result,commit,resultset # 日期格式 dateformat=yyyy-MM-dd HH:mm:ss # 实际驱动可多个 driverlist=com.mysql.jdbc.Driver # 是否开启慢SQL记录 outagedetection=true # 慢SQL记录标准 2 秒 outagedetectioninterval=2
注意问题:
- driver-class-name 为 p6spy 提供的驱动类
- url 前缀为 jdbc:p6spy 跟着冒号为对应数据库连接地址
- 打印出sql为null,在excludecategories增加commit
- 批量操作不打印sql,去除excludecategories中的batch
- 批量操作打印重复的问题请使用MybatisPlusLogFactory (3.2.1新增)
- 该插件有性能损耗,不建议生产环境使用
-
然后就可以 查看到 输出 sql 执行时间里哦
复杂查询操作
通过创建QueryWrapper 对象操作
主要操作有 : ge ,gt,le,lt,eq,ne,between,like,orderByDesc,last,指定查询的列
例如:
@Test
void selectUser(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.select("name").eq("age",15);
List<User> userList = userMapper.selectList(wrapper);
userList.forEach(System.out::println);
}
详情: https://caochenlei.blog.csdn.net/article/details/108809902