辅助 | 描述 |
---|---|
Mybatis Plus Generator | 代码生成器 |
MybatisX | 主要用于XML代码生成 |
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.1version>
dependency>
spring:
datasource:
username: root
password: 13106777006
url: jdbc:mysql://localhost:3306/demosql?useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
# sql日志配置,目的:发送的sql在终端显示
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 关系映射文件扫描
mapper-locations: classpath*:mybatis/mapper/*.xml
# 对象别名设置
type-aliases-package: com.beholder1234.springbootproject1.pojo
@Mapper
@Repository
// BaseMapper 实现有一些基础的sql方法,返回Goods类
public interface GoodsMapper extends BaseMapper<Goods> {
}
@SpringBootTest
class Springbootproject1ApplicationTests {
@Autowired
GoodsMapper goodsMapper;
@Test
void contextLoads() throws MessagingException {
List list = goodsMapper.selectList(null);
list.forEach(System.out::println);
}
}
只记录个人常用的
@TableName("sys_user")
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
@TableName("sys_user")
public class User {
@TableId
private Long id;
private String name;
private Integer age;
private String email;
}
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | “” | 主键字段名 |
type | Enum | 否 | IdType.NONE | 指定主键类型 |
值 | 描述 |
---|---|
AUTO | 数据库 ID 自增 |
NONE | 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT) |
INPUT | 自己注册自动填充插件进行填充 |
ASSIGN_ID | 分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator 的方法nextId (默认实现类为DefaultIdentifierGenerator 雪花算法) |
注意:@Version自动更新,仅支持updateById(id)
与 update(entity, wrapper)
方法
描述:版本注解,用于实体类版本属性上,在数据更新时,实体类版本字段值自动更新
实体类版本字段支持的类型:int,Integer,long,Long,Date,Timestamp,LocalDateTime
newVersion = oldVersion + 1
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | “”,默认值为0 | 逻辑未删除值 |
delval | String | 否 | “”,默认值为1 | 逻辑删除值 |
说明:
Wrapper
对象:条件构造器,用于封装SQL条件,支持链式编程;详情(官方文档)泛型
T
:为任意实体对象泛型
E
:为任意Mapper对象
Serializable
参数:为任意类型主键
IPage
接口:为分页接口,其实现类为Page
Page
类:为分页实现类,封装有本页的size
,record
数据,total
,current
当前页数等
Batch
单词:批量处理
BaseMapper
接口,内提供许多通用CRUD操作方法,由Mapper接口extends
继承便可使用BaseMapper
公共方法前缀:select
,update
,delete
,insert
BaseMapper
实现有与分页查询相关的方法<!-- 相关方法 -->
// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
<!-- 示例 -->
EntityWrapper<Employee> ew = new EntityWrapper<Employee>();
List<Employee> result = employeeMapper.selectPage(new Page<>(1, 2),
ew.between("id",1,20).eq("gender","F"));
ServiceImpl
类,是对CRUD操作的进一步封装的,由pojo的ServiceImpl类extends
继承。同时提供IService
接口,是ServiceImpl
的基类,由pojo的Service
接口接口继承。ServiceImpl
公共方法前缀get
,update
,save
<!-- goods服务接口-->
public interface GoodsService extends IService<Goods> {
}
<!-- goods服务实现类-->
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods>
implements GoodsService{
}
注意:实体类的mapper类要继承BaseMapper
活性记录模式:让pojo对象活化,可自己进行数据持久化操作(说白了,就是让pojo继承许多CRUD操作方法。从而让pojo对象可以自己持久化自己)
说明:提供Model
类,内提供部分CRUD操作方法,由POJO类继承便可使用
select
查找和update
更新,追加where
条件,过滤已逻辑删除的元素;delete
删除,改为update
操作,修改逻辑删除字段的值;insert
插入,不做任何修改insert
问题:因为insert
操作不会给逻辑删除字段自动赋予初值,所以需要我们自己设值
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
@TableLogic
private Integer deleted;
说明:对于CRUD操作通用枚举属性,mybatisplus将枚举属性中标记属性的值,存于数据库(或赋予pojo属性)
注意:以上CURD操作来自自动注入的Sql(即自己在xml关系映射文件编写的sql不行)
通用枚举序列化问题:
import lombok.Getter;
@Getter
public enum GenderEnum {
MALE("0","男"),
FEMALE("1","女");
GenderEnum(String value, String desc) {
this.value = value;
this.desc = desc;
}
@EnumValue
private final String value;
private final String desc;
}
mybatis-plus:
# 通用枚举包扫描
type-enums-package: com/springbootproject/enum
public class User {
/**
* 名字
* 数据库字段: name varchar(20)
*/
private String name;
/**
* 年龄,IEnum接口的枚举处理
* 数据库字段:sex INT(1)
*/
private GenderEnum sex;
public class User {
// 注意!这里需要标记为填充字段
/**
* FieldFill.DEFAULT 默认不处理
* FieldFill.INSERT 插入时填充字段
* FieldFill.UPDATE 更新时填充字段
* FieldFill.INSERT_UPDATE 插入和更新时填充字段
**/
@TableField(.. fill = FieldFill.INSERT)
private String fillField;
....
}
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
// 或者
this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
// 或者
this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)
// 或者
this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
// 或者
this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
}
}
乐观锁:顾名思义十分乐观,他总是认为不会出现问题,无论干什么都不去上锁!如果出现了问题,再次更新值测试
悲观锁:与乐观锁相反
当项目并发更新时,存在对同一数据进行更新;
乐观锁方式:A线程条件更新执行到一半被B线程抢占,先更新了该数据,导致A线程条件更新的条件不满足了,那么A线程更新操作直接失败
悲观锁方式:A线程更新会对该数据上锁,更新完才解锁
version:是数据表中一个被加上
@version
注解的记录数据当前版本的字段
set version = newVersion where version = oldVersion
@Version
private Integer version;
注意:因@Version
注解,仅支持 updateById(id)
与 update(entity, wrapper)
方法。所以拦截器也只能使用
// Spring Boot 方式
@Configuration
@MapperScan("按需修改") // 扫描需要配置乐观锁的pojo的mapper,根本作用是给扫描到的mapper的更新操作追加版本判断where条件;
public class MybatisPlusConfig {
/**
* 旧版
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
/**
* 新版
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
@Test
public void test10(){
User user1 = userMapper.selectById(1);
user1.setUsername("kk");
user1.setAddress("address1");
// 抢占更新
User user2 = userMapper.selectById(1);
user2.setUsername("Mike");
user2.setAddress("address2");
userMapper.updateById(user2);
// 根据返回的结果判断是否更新成功; 0:失败,1:成功
int result = userMapper.updateById(user1);
if (result == 0){
// 重新获取,更新
user1 = userMapper.selectById(1);
user1.setUsername("kk");
user1.setAddress("address1");
userMapper.updateById(user1);
}
}
雪花算法是Twitter开源的分布式ID生成算法.
主要是由64bit的long型生成的全局ID,引入了时间戳和ID保持自增的属性.
64bit分为四个部分:
第一个部分是1bit, 这不 使用,没有意义;
第二个部分是41bit, 组成时间戳;
第三个部分是10bit, 工作机器ID,里面分为两个部分,5个bit是的是机房号,代表最多有25即32个机房,5个bit是指机器的ID,代表最多有25个机器,即32个机器 .
第四部分是12bit, 代表是同一个毫秒类产生不同的ID,区分同一个毫秒内产生的ID.
总的来说就是一个机房,一台机器,在同一号毫秒时产生的ID,可能在同一秒钟产生不同的ID,最后12bit序列号可以区分在同一秒钟的不同ID.