-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
259 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
# ✈️ 更多的主键 ID 生成策略 | ||
|
||
## 🆔 一、简介 | ||
|
||
Fenix 从 `2.4.0` 版本开始新增了三种主键 `ID` 的生产策略类供你选择和使用,同时也支持你通过 Java API 去调用生成 `ID`: | ||
|
||
- **❄️ 雪花算法 ID** (`Long` 长整型) | ||
- **☃️ 62 进制雪花算法 ID** (`String` 字符串型) | ||
- **🌟 62 进制 UUID** (`String` 字符串型) | ||
|
||
## ❄️ 二、雪花算法的 ID 生成策略 | ||
|
||
雪花算法 (`snowflake`) 已经是现在使用比较广泛的 ID 生成算法,其避免了 `UUID` 的冗长无序的缺点,生成的 ID 是**整体有序**的**长整型**数据,Fenix 中也默认做了集成和支持。 | ||
|
||
雪花算法生成的 ID 示例:`2458424618421248`。 | ||
|
||
在 JPA 中要使用自定义的 `ID` 生成策略,需要在你的实体类的 ID 字段中标注 `@GeneratedValue` 和 `@GenericGenerator` 两个注解,并保证 `@GeneratedValue` 注解中的 `generator` 属性和 `@GenericGenerator` 注解中的 `name` 属性值相同。且 `@GenericGenerator` 注解中的 `strategy` 属性值为:`com.blinkfox.fenix.id.SnowflakeIdGenerator`。 | ||
|
||
使用方式示例如下: | ||
|
||
```java | ||
import javax.persistence.Column; | ||
import javax.persistence.Entity; | ||
import javax.persistence.GeneratedValue; | ||
import javax.persistence.Id; | ||
import javax.persistence.Table; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
import org.hibernate.annotations.GenericGenerator; | ||
|
||
@Getter | ||
@Setter | ||
@Entity | ||
@Table(name = "t_my_entity") | ||
public class MyEntity { | ||
|
||
/** | ||
* 使用 Fenix 中的雪花算法 ID 生成策略. | ||
*/ | ||
@Id | ||
@Column(name = "c_id") | ||
@GeneratedValue(generator = "snowflake") | ||
@GenericGenerator(name = "snowflake", strategy = "com.blinkfox.fenix.id.SnowflakeIdGenerator") | ||
private Long id; | ||
|
||
/** | ||
* 名称. | ||
*/ | ||
@Column(name = "c_name") | ||
private String name; | ||
|
||
// 下面省略了其它字段. | ||
|
||
} | ||
``` | ||
|
||
## ☃️ 三、62 进制雪花算法的 ID 生成策略 | ||
|
||
如果你的 ID 不是长整型(`Long`)的,是字符串类型(`String`)的,为了能缩短雪花算法 ID 字符串的长度,可以将原来长度为 `16` 位的雪花算法 ID 的转换为 `62` 进制,能大幅度缩短 `ID` 的长度为 `9` 位,且依然能保证**唯一性**和**整体有序性**。 | ||
|
||
62 进制雪花算法生成的字符串型 ID 示例:`BG5skT7pI`。 | ||
|
||
`@GenericGenerator` 注解中的 `strategy` 属性值为:`com.blinkfox.fenix.id.Snowflake62RadixIdGenerator`。 | ||
|
||
使用方式示例如下: | ||
|
||
```java | ||
import javax.persistence.Column; | ||
import javax.persistence.Entity; | ||
import javax.persistence.GeneratedValue; | ||
import javax.persistence.Id; | ||
import javax.persistence.Table; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
import org.hibernate.annotations.GenericGenerator; | ||
|
||
@Getter | ||
@Setter | ||
@Entity | ||
@Table(name = "t_my_entity") | ||
public class MyEntity { | ||
|
||
/** | ||
* 使用 Fenix 中的雪花算法 ID 生成策略. | ||
*/ | ||
@Id | ||
@Column(name = "c_id") | ||
@GeneratedValue(generator = "snowflake62Radix") | ||
@GenericGenerator(name = "snowflake62Radix", strategy = "com.blinkfox.fenix.id.Snowflake62RadixIdGenerator") | ||
private String id; | ||
|
||
/** | ||
* 名称. | ||
*/ | ||
@Column(name = "c_name") | ||
private String name; | ||
|
||
// 下面省略了其它字段. | ||
|
||
} | ||
``` | ||
|
||
在 Fenix 中,你也可以通过 Java API 调用生成 `UUID` 和 62 进制的 `UUID`,API 示例如下: | ||
|
||
```java | ||
// 使用 IdWorker 来静态方法调用获取通常的 UUID,示例:'73b037d12c894a8ebe673fb6b1caecac'. | ||
String uuid = IdWorker.getUuid(); | ||
|
||
// 使用 IdWorker 来静态方法调用获取 62 进制的简短 UUID,示例:'FXOedrCvouduYPlYgul'. | ||
String uuid2 = IdWorker.get62RadixUuid(); | ||
``` | ||
|
||
## 🌟 四、62 进制 UUID 生成策略 | ||
|
||
鉴于 `UUID` 本质上是 `16` 进制的字符串,字符串长度为 `32` 位,依然可以通过进制转换,将其转换为 `62` 进制,能大幅度缩短 `UUID` 的字符串长度为 `19` 位,且依然能保证**唯一性**和**无序性**。 | ||
|
||
假如原 16 进制的 UUID 为:`73b037d12c894a8ebe673fb6b1caecac`,那么转换后的 62 进制 `UUID` 的字符串示例为:`FXOedrCvouduYPlYgul`。 | ||
|
||
`@GenericGenerator` 注解中的 `strategy` 属性值为:`com.blinkfox.fenix.id.Uuid62RadixIdGenerator`。 | ||
|
||
使用方式示例如下: | ||
|
||
```java | ||
import javax.persistence.Column; | ||
import javax.persistence.Entity; | ||
import javax.persistence.GeneratedValue; | ||
import javax.persistence.Id; | ||
import javax.persistence.Table; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
import org.hibernate.annotations.GenericGenerator; | ||
|
||
@Getter | ||
@Setter | ||
@Entity | ||
@Table(name = "t_my_entity") | ||
public class MyEntity { | ||
|
||
/** | ||
* 使用 Fenix 中的雪花算法 ID 生成策略. | ||
*/ | ||
@Id | ||
@Column(name = "c_id") | ||
@GeneratedValue(generator = "uuid62Radix") | ||
@GenericGenerator(name = "uuid62Radix", strategy = "com.blinkfox.fenix.id.Uuid62RadixIdGenerator") | ||
private String id; | ||
|
||
/** | ||
* 名称. | ||
*/ | ||
@Column(name = "c_name") | ||
private String name; | ||
|
||
// 下面省略了其它字段. | ||
|
||
} | ||
``` | ||
|
||
## ☕ 五、通过 Java API 获取 ID | ||
|
||
在 Fenix 中,你也可以通过 Java API 调用生成雪花算法的 ID 或 `UUID`。 | ||
|
||
以下是生成雪花算法 ID 的 API 方法: | ||
|
||
```java | ||
private static final IdWorker idWorker = new IdWorker(); | ||
|
||
// 获取 10 进制长整型的雪花算法 ID(仅由数字组成). | ||
long id = idWorker.getId(); | ||
|
||
// 获取 36 进制字符串型的雪花算法 ID(由数字 + 26 位小写字母组成). | ||
String id2 = idWorker.get36RadixId(); | ||
|
||
// 获取 62 进制字符串型的雪花算法 ID(由数字 + 26 位小写字母 + 26 位大写字母组成). | ||
String id3 = idWorker.get62RadixId(); | ||
``` | ||
|
||
以下是通过 Java 静态方法去生成通常的 `UUID` 和 62 进制 `UUID` 的方法: | ||
|
||
```java | ||
// 使用 IdWorker 来静态方法调用获取通常的 UUID,示例:'73b037d12c894a8ebe673fb6b1caecac'. | ||
String uuid = IdWorker.getUuid(); | ||
|
||
// 使用 IdWorker 来静态方法调用获取 62 进制的简短 UUID,示例:'FXOedrCvouduYPlYgul'. | ||
String uuid2 = IdWorker.get62RadixUuid(); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# 🚁 非【null】属性的增量更新 | ||
|
||
## 🍀 一、初衷 | ||
|
||
在实际业务场景中,更新数据时,从前端得到的对象实体信息数据的参数中,部分信息是不为空,而我们业务上也只想更新这些不为空的字段到数据库中,而不是将空的数据也一起覆盖保存到数据库中,否则就会造成部分字段数据丢失的问题。 | ||
|
||
Fenix 在 `2.4.0` 版本中增加了这种常见业务操作的功能处理。 | ||
|
||
## 🍁 二、如何使用 | ||
|
||
首先,你须要让你业务功能的 `Repository` 接口继承自 `FenixJpaRepository` 接口。由于 `FenixJpaRepository` 接口继承自 `JpaRepository` 接口,所以 `FenixJpaRepository` 接口的功能完全兼容你以前所使用的 `JpaRepository` 的接口。 | ||
|
||
使用示例如下: | ||
|
||
```java | ||
/** | ||
* 学校(School)相关操作的 Repository 接口. | ||
* | ||
* @author blinkfox on 2020-12-05. | ||
* @since v2.4.0 | ||
*/ | ||
@Repository | ||
public interface SchoolRepository extends FenixJpaRepository<School, String> { | ||
|
||
} | ||
``` | ||
|
||
### 🍂 三、方法介绍 | ||
|
||
**非 `null` 属性的增量更新**有两个方法: | ||
|
||
- `S saveOrUpdateByNotNullProperties(S entity)`: 新增实体或更新实体类中非 `null` 属性的字段值。本方法保存每条数据时会先查询判断是否存在,再进行插入或者更新。 | ||
- `void saveOrUpdateAllByNotNullProperties(Iterable<S> entities)`: 新增或更新所有实体类中非 `null` 属性的字段值,本方法仅仅是上面方法的 `for` 循环版本,提供了循环处理的功能。 | ||
|
||
> **💡 注**: | ||
> 1. 上面两个方法的主要判断处理逻辑为:如果传入的实体主键 `ID` 为空,说明是新增的情况,就插入一条新的数据;如果实体的主键 `ID` 不为空,会先判断是否存在该 `ID` 的数据,如果不存在,也会新增插入一条数据;否则说明是更新的情况,会仅更新保存实体类属性中不为 `null` 值的属性字段到数据库中; | ||
> 2. 由于实际场景中难以区分空和 `null` 的关系,为了统一处理以及不和一些业务场景产生冲突,Fenix 中约定仅更新字段值不为 `null` 的值,如果实体对象中的属性值是空字符串`""`或者 `0` 等等,那么也认为是不为 `null` 的,视为业务上就是要保存空字符串值或者 `0`。所以,Fenix 中也会将该空字符串的值更新到数据库中。所以,**建议你的实体类中所有属性的类型都是对象包装类型,不要用 Java 中的 8 种原生基础类型**。 | ||
简单的使用示例如下: | ||
|
||
```java | ||
@Autowired | ||
private SchoolRepository schoolRepository; | ||
|
||
/** | ||
* 测试 saveBatch 方法. | ||
*/ | ||
@Transactional(rollbackFor = RuntimeException.class) | ||
public void testSaveBatch() { | ||
// 构造要更新的数据,这里表示只更新 id 为 '123' 的数据的 name 值为 '北京大学'. | ||
List<School> schools = new School() | ||
.setId("123") | ||
.setName("北京大学"); | ||
|
||
// 增量更新数据. | ||
fenixSchoolRepository.saveOrUpdateByNotNullProperties(school); | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters