主键和分页和ActiveRecord和SimpleQuery
标签: 主键和分页和ActiveRecord和SimpleQuery Java博客 51CTO博客
2023-07-29 18:24:05 367浏览
1. 主键策略 76
1.1 主键生成策略介绍 76
首先大家先要知道什么是主键,主键的作用就是唯一标识,我们可以通过这个唯一标识来定位到这条数据。
当然对于表数据中的主键,我们可以自己设计生成规则,生成主键。但是在更多的场景中,没有特殊要求的话,我们每次自己手动生成的比较麻烦,我们可以借助框架提供好的主键生成策略,来生成主键。这样比较方便快捷
在MybatisPlus中提供了一个注解,是@TableId,该注解提供了各种的主键生成策略,我们可以通过使用该注解来对于新增的数据指定主键生成策略。那么在以后新增数据的时候,数据就会按照我们指定的主键生成策略来生成对应的主键。
1.2 AUTO策略 76
该策略为跟随数据库表的主键递增策略,前提是数据库表的主键要设置为自增
此处要设置好下次递增的数字
实体类添加注解,指定主键生成策略
package com.powernode.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
//数据库对应的实体类user 4
@Data //生成set get方法
@NoArgsConstructor //无参构造
@AllArgsConstructor //有参构造
//@TableName("powershop_user") //指定数据库中的powershop_user表和这个User实体类映射 30
public class User {
@TableId(type = IdType.AUTO) //指定id的自增策略 (跟随我们数据库的主键自增策略来的) 77
private Long id;
// @TableField("username") //指定表中的字段名和属性对应 32
private String name;
// @TableField(select = false)//时age字段失效查询不到 34
private Integer age;
private String email;
// @TableField("`desc`") //将desc字段变成普通字段 33
// private String desc;
//online属性在表中没有,但是我们有需要这个属性进行展示,所以使用TableField注解, 35
// 去掉这个字段,不让他作为查询字段。
// @TableField(exist = false)
// private Integer online; //用户在线或不在线
}
PrimaryKeyTest
// 77
@Test
void primary(){
User user = new User();
user.setName("Mary");
user.setAge(35);
user.setEmail("mary@powernode.com");
userMapper.insert(user);
}
拼接的SQL语句如下
1.3 INPUT策略 78
该策略表示,必须由我们手动的插入id,否则无法添加数据
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type = IdType.NONE)
private Long id;
private String name;
private Integer age;
private String email;
}
由于我们不使用AUTO了,所以把自动递增去掉
这里如果我们省略不写id,会发现,无法插入数据
PrimaryKeyTest
@Test
void primary2(){
User user = new User();
user.setName("Mary");
user.setAge(35);
user.setEmail("mary@powernode.com");
userMapper.insert(user);
}
但是我们自己指定了id,发现可以添加成功
PrimaryKeyTest
//78
@Test
void primary2(){
User user = new User();
user.setId(8L);
user.setName("Mary");
user.setAge(35);
user.setEmail("mary@powernode.com");
userMapper.insert(user);
}
1.4 ASSIGN_ID策略 79
我们来思考一下,像之前这种自动递增的方式,有什么问题?
如果我们将来一张表的数据量很大,我们需要进行分表。
常见的分表策略有两种:
【1】水平拆分 79
水平拆分就是将一个大的表按照数据量进行拆分
【2】垂直拆分 79
垂直拆分就是将一个大的表按照字段进行拆分
其实我们对于拆分后的数据,有三点需求,就拿水平拆分来说:
【1】之前的表的主键是有序的,拆分后还是有序的
【2】虽然做了表的拆分,但是每条数据还需要保证主键的唯一性
【3】主键最好不要直接暴露数据的数量,这样容易被外界知道关键信息
那就需要有一种算法,能够实现这三个需求,这个算法就是雪花算法
雪花算法 80
雪花算法是由一个64位的二进制组成的,最终就是一个Long类型的数值。
主要分为四部分存储
【1】1位的符号位,固定值为0
【2】41位的时间戳
【3】10位的机器码,包含5位机器id和5位服务id
【4】12位的序列号
使用雪花算法可以实现有序、唯一、且不直接暴露排序的数字。
测试雪花算法 81
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
private Integer age;
private String email;
}
PrimaryKeyTest
// 测试雪花算法 81
@Test
void primary3(){
User user = new User();
user.setName("Mary");
user.setAge(35);
user.setEmail("mary@powernode.com");
userMapper.insert(user);
}
我们可以在插入后发现一个19位长度的id,该id就是雪花算法生成的id,这是二级制的十进制表示形式
1.5 NONE策略 82
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type = IdType.NONE)
private Long id;
private String name;
private Integer age;
private String email;
}
NONE策略表示不指定主键生成策略,当我们没有指定主键生成策略或者主键策略为NONE的时候,他跟随的是全局策略,那我们来看一下他的全局策略默认是什么
全局配置中 id-type是用于配置主键生成策略的,我们可以看一下id-type的默认值
通过查看源码发现,id-type的默认值就是雪花算法
PrimaryKeyTest
// 测试全局默认策略是不是雪花算法 82
@Test
void primary4(){
User user = new User();
user.setName("Mary");
user.setAge(35);
user.setEmail("mary@powernode.com");
userMapper.insert(user);
}
1.6 ASSIGN_UUID策略 83
UUID(Universally Unique Identifier)全局唯一标识符,定义为一个字符串主键,采用32位数字组成,编码采用16进制,定义了在时间和空间都完全唯一的系统信息。
UUID的编码规则:
【1】1~8位采用系统时间,在系统时间上精确到毫秒级保证时间上的唯一性;
【2】9~16位采用底层的IP地址,在服务器集群中的唯一性;
【3】17~24位采用当前对象的HashCode值,在一个内部对象上的唯一性;
【4】25~32位采用调用方法的一个随机数,在一个对象内的毫秒级的唯一性。
通过以上4种策略可以保证唯一性。在系统中需要用到随机数的地方都可以考虑采用UUID算法。
我们想要演示UUID的效果,需要改变一下表的字段类型和实体类的属性类型
将数据库表的字段类型改为varchar(50)
将实体类的属性类型改为String,并指定主键生成策略为IdType.ASSIGN_UUID
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String name;
private Integer age;
private String email;
}
完成数据的添加
PrimaryKeyTest
//测试UUID 83
@Test
void primary5(){
User user = new User();
user.setName("Mary");
user.setAge(35);
user.setEmail("mary@powernode.com");
userMapper.insert(user);
}
我们会发现,成功添加了一条数据,id为uuid类型
1.7 小结 83
本章节讲解了主键生成策略,我们可以通过指定主键生成策略来生成不同的主键id,从而达到对于数据进行唯一标识的作用。
2. 分页 84
分页操作在实际开发中非常的常见,我们在各种平台和网站中都可以看到分页的效果。
例如:京东商城的分页效果
在MybatisPlus中我们如何配置分页呢?这里我们思考一下
在MybatisPlus中的查询语句是怎么实现的,我们可以通过两种方式实现查询语句
【1】通过MybatisPlus提供的方法来实现条件查询
【2】通过自定义SQL语句的方式来实现查询
接下来我们就来演示这两种分页方式如何实现
2.1 分页插件 84
在大部分场景下,如果我们的SQL没有这么复杂,是可以直接通过MybatisPlus提供的方法来实现查询的,在这种情况下,我们可以通过配置分页插件来实现分页效果
分页的本质就是需要设置一个拦截器,通过拦截器拦截了SQL,通过在SQL语句的结尾添加limit关键字,来实现分页的效果
接下来看一下配置的步骤
【1】通过配置类来指定一个具体数据库的分页插件,因为不同的数据库的方言不同,具体生成的分页语句也会不同,这里我们指定数据库为Mysql数据库
MybatisPlusConfig
package com.powernode.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//配置类 85
//这里我们配置分页插件 85
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
【2】实现分页查询效果
PageTest
package com.powernode;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.powernode.domain.User;
import com.powernode.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
//测试分页效果 85
@SpringBootTest
public class PageTest {
@Autowired
private UserMapper userMapper;
@Test
void selectPage(){
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//指定分页对象,分页对象包含分页信息 IPage
IPage<User> userPage = new Page<>(1, 3);//参数1 当前页,参数2一页显示几条
//执行查询
userMapper.selectPage(userPage,lambdaQueryWrapper);
//获取分页查询的信息
System.out.println("当前页:" + userPage.getCurrent());
System.out.println("每页显示条数:" + userPage.getSize());
System.out.println("总页数:" + userPage.getPages());
System.out.println("总条数:" + userPage.getTotal());
System.out.println("分页数据:" + userPage.getRecords());
}
}
2.2 自定义分页插件 86
在某些场景下,我们需要自定义SQL语句来进行查询。接下来我们来演示一下自定义SQL的分页操作
【1】在UserMapper.xml映射配置文件中提供查询语句
UserMapper.xml
<!--自定义分页查询 86-->
<select id="selectByName" resultType="com.powernode.domain.User">
select * from powershop_user where name = #{name}
</select>
【2】在Mapper接口中提供对应的方法,方法中将IPage对象作为参数传入
UserMapper
//自定义分页查询 86
IPage<User> selectByName(IPage<User> page,String name);
【3】表数据为
【4】实现分页查询效果
PageTest
//自定义分页查询 86
@Test
void selectPage2(){
IPage<User> userPage = new Page<>(1, 2);
userMapper.selectByName(userPage,"Mary");
System.out.println("当前页:" + userPage.getCurrent());
System.out.println("每页显示条数:" + userPage.getSize());
System.out.println("总页数:" + userPage.getPages());
System.out.println("总条数:" + userPage.getTotal());
System.out.println("分页数据:" + userPage.getRecords());
}
2.3 小结 86
这里我们学习了两种分页的配置方法,将来以后我们在进行条件查询的时候,可以使用分页的配置进行配置。
3. ActiveRecord模式 87
3.1 ActiveRecord介绍
ActiveRecord(活动记录,简称AR),是一种领域模型模式,特点是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录。ActiveRecord 一直广受解释型动态语言( PHP 、 Ruby 等)的喜爱,通过围绕一个数据对象进行CRUD操作。而 Java 作为准静态(编译型)语言,对于 ActiveRecord 往往只能感叹其优雅,所以 MP 也在 AR 道路上进行了一定的探索,仅仅需要让实体类继承 Model 类且实现主键指定方法,即可开启 AR 之旅。
3.2 ActiveRecord实现 87
接下来我们来看一下ActiveRecord的实现步骤
【1】让实体类继承Model<User>类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User extends Model<User> {
private Long id;
private String name;
private Integer age;
private String email;
}
我们可以看到,Model类中提供了一些增删改查方法,这样的话我们就可以直接使用实体类对象调用这些增删改查方法了,简化了操作的语法,但是他的底层依然是需要UserMapper的,所以持久层接口并不能省略
【2】测试ActiveRecord模式的增删改查
添加数据
ActiveRecordTest
//添加数据 87
@Test
void activeRecordAdd(){
User user = new User();
user.setName("zhang");
user.setAge(35);
user.setEmail("zhang@powernode.com");
user.insert();
}
删除数据
ActiveRecordTest
//删除操作 87
@Test
void activeRecordDelete(){
User user = new User();
user.setId(1682300098762629121L);
user.deleteById();
}
修改数据
ActiveRecordTest
//修改操作 87
@Test
void activeRecordUpdate(){
User user = new User();
user.setId(7L);
user.setAge(50);
user.updateById();
}
查询数据
ActiveRecordTest
//查询操作 87
@Test
void activeRecordSelect(){
User user = new User();
user.setId(7L);
User result = user.selectById();
System.out.println(result);
}
4. SimpleQuery工具类 88
4.1 SimpleQuery介绍 88
SimpleQuery可以对selectList查询后的结果用Stream流进行了一些封装,使其可以返回一些指定结果,简洁了api的调用
4.2 list
演示基于字段封装集合
ActiveRecordTest
//SimpleQuery工具类 对selectList查询后的结果用Stream流进行了一些封装 88
@Test
void testList(){
List<Long> list = SimpleQuery
.list(new LambdaQueryWrapper<User>().eq(User::getName, "Mary")
, User::getId);
System.out.println(list);
}
演示对于封装后的字段进行lambda操作 89
ActiveRecordTest
// 对于封装后的字段进行lambda操作 89
@Test
void testList2(){
List<String> list = SimpleQuery
.list(new LambdaQueryWrapper<User>().eq(User::getName, "Mary")
, User::getName
, user -> Optional.of(user.getName())//得到字段
.map(String::toLowerCase)//转为小写
.ifPresent(user::setName));//将转为小写后的字段重新设置进list
System.out.println(list);
}
4.3 map 90
演示将所有的对象以id,实体的方式封装为Map集合
//SimpleQuery工具类 的map操作 90
@Test
void testMap(){
Map<Long, User> map = SimpleQuery
.keyMap(new LambdaQueryWrapper<User>(), User::getId);
System.out.println(map);
}
演示将单个对象以id,实体的方式封装为Map集合 91
//演示将单个对象以id,实体的方式封装为Map集合 91
@Test
void testMap2(){
Map<Long, User> map = SimpleQuery
.keyMap(new LambdaQueryWrapper<User>().eq(User::getId, 1L)
, User::getId);
System.out.println(map);
}
演示只想要id和name组成的map 92
//演示只想要id和name组成的map 92
@Test
void testMap3(){
Map<Long, String> map = SimpleQuery
.map(new LambdaQueryWrapper<User>(), User::getId, User::getName);
System.out.println(map);
}
4.4 Group 93
演示分组效果
//SimpleQuery工具类 的group操作 90
@Test
void testGroup(){
Map<String, List<User>> map = SimpleQuery
.group(new LambdaQueryWrapper<User>(), User::getName);
System.out.println(map);
}
4.5 小结 93
在这一小节,我们演示了SimpleQuery提供的Stream流式操作的方法,通过这些操作继续为我们提供了查询方面简化的功能
好博客就要一起分享哦!分享海报
此处可发布评论
评论(0)展开评论
展开评论
您可能感兴趣的博客