void insert(){
User user = new User();
user.setName(“Lucy”);
user.setAge(20);
user.setEmail(“12345@qq.com”);
int insert = userMapper.insert(user);
System.out.println(insert);
}
}
3.6.3、修改数据
4、要想在控制台看到sql输出日志,需要在application.properties配置文件中添加以下代码
=====================================================================================================================
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
=======================================================================
-
auto-increment
-
uuid:每次随机生成唯一值,排序不方便
-
redis
-
mybatis-plus (使用了snowplake算法)
https://www.cnblogs.com/haoxinyue/p/5208136.html
mybatis-plus默认只用自己自带的主键生成策略,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)。
- 雪花算法优点:
整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率较高。
可以自己设置要使用的主键生成策略,使用如下注解@TableId
- @TableId(type = IdType.ID_WORKER)
mybatis-plus自带的策略,生成19位值,当属性类型类数字类型时使用该策略,比如Long
- @TableId(type = IdType.ID_WORKER_STR)
mybatis-plus自带的策略,生成19位值,当属性类型类字符串类型时使用该策略,比如String
- @TableId(type = IdType.UUID)
随机生成唯一值
- @TableId(type = IdType.AUTO)
数据库ID自增
- @TableId(type = IdType.INPUT)
用户输入ID, 该类型可以通过自己注册自动填充插件进行填充
- @TableId(type = IdType.NONE)
没有策略
在需要设置主键的实体类属性上使用该注解,可以设置主键策略,主要有以下几种策略。
要想影响所有实体的配置,可以设置全局主键配置
#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto
================================================================================
需求描述:
项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。
我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作
在User表中添加datetime类型的新的字段 create_time、update_time
在实体类里需要自动填充的属性上面添加注解
如在下面User实体类的createTime和updateTime属性上添加注解
创建类,实现MetaObjectHandler接口,实现接口里的方法
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import java.util.Date;
/**
-
@Description :
-
@Author :lenovo
-
@Date :2021/2/20 21:34
*/
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
//用mybatis-plus实现添加操作时,在这个方法会执行
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName(“createTime”,new Date(),metaObject);
this.setFieldValByName(“updateTime”,new Date(),metaObject);
}
//用mybatis-plus实现修改操作时,在这个方法会执行
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName(“updateTime”,new Date(),metaObject);
}
}
=====================================================================
什么是丢失更新:
多个人同时需改一条记录,最后提交的会把之前提交的数据覆盖更新。
7.1.1 、悲观锁(表级锁):串行操作。
举例1:如上图修改数据,Lucy修改money数据时,别人都不能进行操作,只有lucy操作完成后,其他人才能操作。
举例2:又比如当一个人上网浏览新闻时,别人不能浏览,只有当这个人浏览完成后,别人才能浏览,如果这个人浏览一百年,其他所有人就要等一百年,这就是悲观锁。
7.1.2、 乐观锁
-
主要适用场景:当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新
-
使用版本号进行并发的控制。比如多个人修改数据时,只有一个人才能修改成功,其他人不能同时修改。
乐观锁的实现原理:
乐观锁的具体实现:
mybatis-plus实现乐观锁官方步骤:https://mp.baomidou.com/guide/interceptor-optimistic-locker.html#optimisticlockerinnerinterceptor
- 1、表中添加字段,作为乐观锁版本号。
- 2、对应实体类添加版本号属性。
@TableField(fill = FieldFill.INSERT): 插入数据时自动填充数据
@version注解所在的包:
- 3、插件配置
spring工程:在spring.xml配置文件中
spring-boot项目:新建一个存放配置类的包,在该包下新建个配置类:编写乐观锁插件
package com.nonglin.mpdemo.config;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan(“com.nonglin.mpdemo”)
public class Mpconfig {
//乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
- 4、在测试类中测试乐观锁:
//测试乐观锁
@Test
public void testOptimisticLocker(){
User user = userMapper.selectById(1363307390618947585L);
user.setAge(1);
int row = userMapper.updateById(user);
System.out.println(“修改”+row+“条数据”);
}
=================================================================================
Zero date value prohibited解决方法
//多个id批量查询
@Test
public void findByBatchIds(){
List users = userMapper.selectBatchIds(Arrays.asList(1L,2L,3L));
for(User user:users){
System.out.println(user);
}
}
控制台输出:
JDBC Connection [HikariProxyConnection@1171672359 wrapping com.mysql.cj.jdbc.ConnectionImpl@34fe326d] will not be managed by Spring
==> Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user WHERE id IN ( ? , ? , ? )
==> Parameters: 1(Long), 2(Long), 3(Long)
<== Columns: id, name, age, email, create_time, update_time, version
<== Row: 1, Jone, 18, test1@baomidou.com, null, null, null
<== Row: 2, Jack, 120, test2@baomidou.com, null, null, null
<== Row: 3, Tom, 28, test3@baomidou.com, null, null, null
<== Total: 3
打印输出:
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@65eabaab]
User(id=1, name=Jone, age=18, email=test1@baomidou.com, createTime=null, updateTime=null, version=null)
User(id=2, name=Jack, age=120, email=test2@baomidou.com, createTime=null, updateTime=null, version=null)
User(id=3, name=Tom, age=28, email=test3@baomidou.com, createTime=null, updateTime=null, version=null)
//简单条件查询
@Test
public void testSelectByMap(){
HashMap<String,Object> map = new HashMap<>();
map.put(“name”,“Lucy”);
map.put(“age”,18);
List users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
控制台输出:
JDBC Connection [HikariProxyConnection@774095232 wrapping com.mysql.cj.jdbc.ConnectionImpl@499683c4] will not be managed by Spring
==> Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user WHERE name = ? AND age = ?
==> Parameters: Lucy(String), 18(Integer)
<== Columns: id, name, age, email, create_time, update_time, version
<== Row: 1363104207493660674, Lucy, 18, Lucy@qq.com, null, null, null
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2b917fb0]
User(id=1363104207493660674, name=Lucy, age=18, email=Lucy@qq.com, createTime=null, updateTime=null, version=null)
===============================================================================
MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能
(1)创建配置类
在配置类中添加插件
//分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
(2)测试selectPage分页
测试:最终通过page对象获取相关数据
@Test
void textPage(){
Page page = new Page(1,3);
Page userPage = userMapper.selectPage(page, null);
//返回的对象得到分页的所有数据
long current = userPage.getCurrent();//当前显示的页码
long size = userPage.getSize();//每页显示记录数
List records = userPage.getRecords();//当前页数据的集合
long pages = userPage.getPages();//表中数据的总页数
long total = userPage.getTotal();//数据库表中的总记录数
boolean hasPrevious = userPage.hasPrevious();//是否有上一页
boolean hasNext = userPage.hasNext();//是否有下一页
//通过page对象获取分页数据
System.out.println(“当前页:”+current);//当前页
System.out.println(“每页显示记录数:”+size);//每页显示记录数
System.out.println(“当前页数据的集合:”+records);//当前页数据的list集合
System.out.println(“数据库表中数据总页数:”+pages);//总页数
System.out.println(“数据库表中的总记录数:”+total);//总记录数
System.out.println(“是否有上一页:”+hasPrevious);//是否有上一页
System.out.println(“是否有下一页:”+hasNext);//是否有下一页
}
控制台输出:
===============================================================================
真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据。
//根据id删除
@Test
public void deleteById(){
int result = userMapper.deleteById(1363126056508198913L);
System.out.println(result);
}
//批量删除
@Test
public void testDeleteBatchIds(){
int result = userMapper.deleteBatchIds(Arrays.asList(1L,2L,3L));
System.out.println(result);
}
//根据条件删除
@Test
void testDelete(){
HashMap map = new HashMap();
map.put(“name”,“LucyTest”);
map.put(“age”,23);
int i = userMapper.deleteByMap(map);
System.out.println(“成功删除了”+i+“条数据”);
}
假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录。
逻辑删除的使用场景:
-
可以进行数据恢复
-
有关联数据,不便删除
9.2.1、表添加逻辑删除字段,对应实体类添加属性,属性添加注解。
9.2.2、在自动填充中给删除加个初始值:
9.2.3、在项目的配置类中配置逻辑删除插件
(mp3.3版本之后不需要引入该插件页可以实现功能)
//逻辑删除插件
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
9.2.4、application.properties 加入配置
#逻辑删除配置
mybatis-plus.global-config.db-config.logic-not-delete-value=0
mybatis-plus.global-config.db-config.logic-delete-value=1
9.2.5、测试逻辑删除
/**
- 测试 逻辑删除
*/
@Test
public void testLogicDelete() {
int result = userMapper.deleteById(1L);
System.out.println(result);
}
- 测试后发现,数据并没有被删除,deleted字段的值由0变成了1
- 测试后分析打印的sql语句,是一条update
- 注意:被删除数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作
==================================================================================
性能分析拦截器,用于输出每条 SQL 语句及其执行时间
SQL 性能执行分析,开发环境使用,超过指定时间,停止运行。有助于发现问题。
(1)参数说明
-
参数:maxTime: SQL 执行最大时长,超过自动停止运行,有助于发现问题。
-
参数:format: SQL是否格式化,默认false。
(2)在 MybatisPlusConfig 中配置插件
注意:该插件在3.2.0以上版本移除,推荐使用使用第三方拓展执行SQL分析(需在pom.xml导入p6spy 依赖)打印功能
/**
-
SQL 执行性能分析插件
-
开发环境使用,线上不推荐。 maxTime 指的是 sql 最大执行时长
*/
@Bean
@Profile({“dev”,“test”})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(100);//ms,超过此处设置的ms则sql不执行
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
(3)Spring Boot 中设置dev环境,在springboot配置文件中设置
#环境设置:dev、test、prod
spring.profiles.active=dev
/**
- 测试 性能分析插件
*/
@Test
public void testPerformance() {
User user = new User();
user.setName(“我是Helen”);
user.setEmail(“helen@sina.com”);
user.setAge(18);
userMapper.insert(user);
}
======================================================================================
Wrapper : 条件构造抽象类,最顶端父类
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
QueryWrapper : 查询条件封装
UpdateWrapper : Update 条件封装
AbstractLambdaWrapper : 使用Lambda 语法
总结一下
面试前要精心做好准备,简历上写的知识点和原理都需要准备好,项目上多想想难点和亮点,这是面试时能和别人不一样的地方。
还有就是表现出自己的谦虚好学,以及对于未来持续进阶的规划,企业招人更偏爱稳定的人。
万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。
为了帮助大家更好更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。
前端面试题汇总