Sharding-JDBC只分表不分库
1.pom
<!-- Sharding-JDBC 依赖 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.2</version>
</dependency>
2.yml
1.这里的分片算法是HASH_MOD,
2.这里总共配置了四个数据库的表,collection_library_0、collection_library_1、collection_library_2、collection_library_3 。配置里ds0.collection_library_$->{0...3}这个意思就是从collection_library_0开始总共到3
3.数据库只要创建这四个0123表即可,不需要创建collection_library表,但是pojo实体类里面配置的时候用collection_library,即@Table(name="collection_library"),不需要加0123
4.你配置了shardingsphere的数据源,如果你的数据库有其他的表,但是其他表不需要分表,这个shardingsphere的数据源也可以用,不需要再配置一边数据源
server:
port: 8774
spring:
application:
name: zzzz
shardingsphere:
datasource:
names: ds0
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/xhstable?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
username: root
password: root
rules:
sharding:
tables:
collection_library:
actual-data-nodes: ds0.collection_library_$->{0..3}
table-strategy:
standard:
sharding-column: id
sharding-algorithm-name: collection-library-hash-mod
sharding-algorithms:
collection-library-hash-mod:
type: HASH_MOD
props:
sharding-count: 4
key-generators:
snowflake:
type: SNOWFLAKE
props:
worker-id: 123
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: Asia/Shanghai
servlet:
multipart:
max-file-size: 20MB
max-request-size: 20MB
# ==================== 新增:Redis配置 ====================
redis:
host: localhost # Redis服务器地址,生产环境请修改
port: 6379 # Redis端口
password: root # Redis密码,如果没有留空
database: 0 # 数据库索引
timeout: 3000ms # 连接超时时间
lettuce:
pool:
max-active: 8 # 最大连接数
max-idle: 8 # 最大空闲连接
min-idle: 0 # 最小空闲连接
max-wait: -1ms # 最大等待时间
quartz:
job-store-type: jdbc # Job 存储器类型。默认为 memory,表示内存,jdbc 表示使用数据库
scheduler-name: scheduler
wait-for-jobs-to-complete-on-shutdown: true # 应用关闭时,是否等待定时任务执行完成。默认为 false,建议设置为 true
overwrite-existing-jobs: true # 是否覆盖已有 Job 的配置
jdbc:
initialize-schema: never # 数据库初始化方式,默认为 never,表示不初始化(前面已经手动初始化了)
properties: # 添加 Quartz Scheduler 附加属性
org:
quartz:
scheduler:
instanceName: scheduler
instanceId: AUTO
# 数据源配置
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
tablePrefix: QRTZ_
isClustered: false
clusterCheckinInterval: 10000
useProperties: false
dataSource: quartzDs
# 线程池配置
threadPool:
class: org.quartz.simpl.SimpleThreadPool
threadCount: 10
threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8763/eureka
instance:
prefer-ip-address: true
feign:
hystrix:
enabled: true
3.数据库
数据库设计时,只需要id的类型是bigint,然后再数据库里面id不能设置为自增,主要是因为要用yml配置的雪花算法生成的id,所有的字段一模一样
1.collection_library_0
CREATE TABLE `collection_library_0` (
`id` bigint NOT NULL,
`title` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`cover_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`original_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`content_body` text COLLATE utf8mb4_unicode_ci,
`topic_tags` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`image_url` text COLLATE utf8mb4_unicode_ci,
`video_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`content_type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`blogger_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`like_count` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`collect_count` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`comment_count` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`blogger_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`publish_time` datetime DEFAULT NULL,
`add_to_imitation` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`collection_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.collection_library_1
CREATE TABLE `collection_library_1` (
`id` bigint NOT NULL,
`title` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`cover_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`original_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`content_body` text COLLATE utf8mb4_unicode_ci,
`topic_tags` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`image_url` text COLLATE utf8mb4_unicode_ci,
`video_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`content_type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`blogger_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`like_count` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`collect_count` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`comment_count` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`blogger_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`publish_time` datetime DEFAULT NULL,
`add_to_imitation` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`collection_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
3.collection_library_2
CREATE TABLE `collection_library_2` (
`id` bigint NOT NULL,
`title` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`cover_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`original_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`content_body` text COLLATE utf8mb4_unicode_ci,
`topic_tags` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`image_url` text COLLATE utf8mb4_unicode_ci,
`video_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`content_type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`blogger_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`like_count` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`collect_count` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`comment_count` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`blogger_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`publish_time` datetime DEFAULT NULL,
`add_to_imitation` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`collection_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
4.collection_library_3
CREATE TABLE `collection_library_3` (
`id` bigint NOT NULL,
`title` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`cover_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`original_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`content_body` text COLLATE utf8mb4_unicode_ci,
`topic_tags` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`image_url` text COLLATE utf8mb4_unicode_ci,
`video_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`content_type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`blogger_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`like_count` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`collect_count` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`comment_count` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`blogger_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`publish_time` datetime DEFAULT NULL,
`add_to_imitation` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`collection_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
4.实体类
主要是配置时用@Table(name="collection_library"),然后实体类的id是Long类型
package com.microservices.user.pojo;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
import java.lang.String;
import java.lang.Integer;
/****
* @Author:shenkunlin
* @Description:CollectionLibrary构建
* @Date 2019/6/14 19:13
*****/
@Table(name="collection_library")
public class CollectionLibrary implements Serializable{
@Id
@Column(name = "id")
private Long id;//自增主键
@Column(name = "title")
private String title;//标题
@Column(name = "cover_url")
private String coverUrl;//封面链接
@Column(name = "original_url")
private String originalUrl;//原文链接
@Column(name = "content_body")
private String contentBody;//正文
@Column(name = "topic_tags")
private String topicTags;//话题标签
@Column(name = "image_url")
private String imageUrl;//图片链接
@Column(name = "video_url")
private String videoUrl;//视频链接
@Column(name = "content_type")
private String contentType;//类型(视频、图片)
@Column(name = "blogger_name")
private String bloggerName;//博主
@Column(name = "like_count")
private String likeCount;//点赞数
@Column(name = "collect_count")
private String collectCount;//收藏数
@Column(name = "comment_count")
private String commentCount;//评论数
@Column(name = "blogger_url")
private String bloggerUrl;//博主链接
@Column(name = "publish_time")
private Date publishTime;//发布时间
@Column(name = "add_to_imitation")
private String addToImitation;//加入仿写
@Column(name = "collection_time")
private Date collectionTime;//采集时间
//get方法
public Long getId() {
return id;
}
//set方法
public void setId(Long id) {
this.id = id;
}
//get方法
public String getTitle() {
return title;
}
//set方法
public void setTitle(String title) {
this.title = title;
}
//get方法
public String getCoverUrl() {
return coverUrl;
}
//set方法
public void setCoverUrl(String coverUrl) {
this.coverUrl = coverUrl;
}
//get方法
public String getOriginalUrl() {
return originalUrl;
}
//set方法
public void setOriginalUrl(String originalUrl) {
this.originalUrl = originalUrl;
}
//get方法
public String getContentBody() {
return contentBody;
}
//set方法
public void setContentBody(String contentBody) {
this.contentBody = contentBody;
}
//get方法
public String getTopicTags() {
return topicTags;
}
//set方法
public void setTopicTags(String topicTags) {
this.topicTags = topicTags;
}
//get方法
public String getImageUrl() {
return imageUrl;
}
//set方法
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
//get方法
public String getVideoUrl() {
return videoUrl;
}
//set方法
public void setVideoUrl(String videoUrl) {
this.videoUrl = videoUrl;
}
//get方法
public String getContentType() {
return contentType;
}
//set方法
public void setContentType(String contentType) {
this.contentType = contentType;
}
//get方法
public String getBloggerName() {
return bloggerName;
}
//set方法
public void setBloggerName(String bloggerName) {
this.bloggerName = bloggerName;
}
//get方法
public String getLikeCount() {
return likeCount;
}
//set方法
public void setLikeCount(String likeCount) {
this.likeCount = likeCount;
}
//get方法
public String getCollectCount() {
return collectCount;
}
//set方法
public void setCollectCount(String collectCount) {
this.collectCount = collectCount;
}
//get方法
public String getCommentCount() {
return commentCount;
}
//set方法
public void setCommentCount(String commentCount) {
this.commentCount = commentCount;
}
//get方法
public String getBloggerUrl() {
return bloggerUrl;
}
//set方法
public void setBloggerUrl(String bloggerUrl) {
this.bloggerUrl = bloggerUrl;
}
//get方法
public Date getPublishTime() {
return publishTime;
}
//set方法
public void setPublishTime(Date publishTime) {
this.publishTime = publishTime;
}
//get方法
public String getAddToImitation() {
return addToImitation;
}
//set方法
public void setAddToImitation(String addToImitation) {
this.addToImitation = addToImitation;
}
//get方法
public Date getCollectionTime() {
return collectionTime;
}
//set方法
public void setCollectionTime(Date collectionTime) {
this.collectionTime = collectionTime;
}
}
5.Controller
不需要改
package com.microservices.user.controller;
import com.microservices.user.pojo.CollectionLibrary;
import com.microservices.user.pojo.CopyLibrary;
import com.microservices.user.service.CollectionLibraryService;
import com.github.pagehelper.PageInfo;
import com.microservices.entity.Result;
import com.microservices.entity.StatusCode;
import com.microservices.user.service.CopyLibraryService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/****
* @Author:shenkunlin
* @Description:
* @Date 2019/6/14 0:18
*****/
@RestController
@RequestMapping("/collectionLibrary")
@CrossOrigin
public class CollectionLibraryController {
@Autowired
private CollectionLibraryService collectionLibraryService;
@Autowired
private CopyLibraryService copyLibraryService;
/***
* CollectionLibrary分页条件搜索实现
* @param collectionLibrary
* @param page
* @param size
* @return
*/
@PostMapping(value = "/search/{page}/{size}" )
public Result<PageInfo> findPage(@RequestBody(required = false) CollectionLibrary collectionLibrary, @PathVariable int page, @PathVariable int size){
//调用CollectionLibraryService实现分页条件查询CollectionLibrary
PageInfo<CollectionLibrary> pageInfo = collectionLibraryService.findPage(collectionLibrary, page, size);
return new Result(true,StatusCode.OK,"查询成功",pageInfo);
}
/***
* CollectionLibrary分页搜索实现
* @param page:当前页
* @param size:每页显示多少条
* @return
*/
@GetMapping(value = "/search/{page}/{size}" )
public Result<PageInfo> findPage(@PathVariable int page, @PathVariable int size){
//调用CollectionLibraryService实现分页查询CollectionLibrary
PageInfo<CollectionLibrary> pageInfo = collectionLibraryService.findPage(page, size);
return new Result<PageInfo>(true,StatusCode.OK,"查询成功",pageInfo);
}
/***
* 多条件搜索品牌数据
* @param collectionLibrary
* @return
*/
@PostMapping(value = "/search" )
public Result<List<CollectionLibrary>> findList(@RequestBody(required = false) CollectionLibrary collectionLibrary){
//调用CollectionLibraryService实现条件查询CollectionLibrary
List<CollectionLibrary> list = collectionLibraryService.findList(collectionLibrary);
return new Result<List<CollectionLibrary>>(true,StatusCode.OK,"查询成功",list);
}
/***
* 根据ID删除品牌数据
* @param id
* @return
*/
@DeleteMapping(value = "/{id}" )
public Result delete(@PathVariable Long id){
//调用CollectionLibraryService实现根据主键删除
collectionLibraryService.delete(id);
return new Result(true,StatusCode.OK,"删除成功");
}
/***
* 修改CollectionLibrary数据
* @param collectionLibrary
* @param id
* @return
*/
@PutMapping(value="/{id}")
public Result update(@RequestBody CollectionLibrary collectionLibrary,@PathVariable Long id){
//设置主键值
collectionLibrary.setId(id);
//调用CollectionLibraryService实现修改CollectionLibrary
collectionLibraryService.update(collectionLibrary);
return new Result(true,StatusCode.OK,"修改成功");
}
/***
* 新增CollectionLibrary数据
* @param collectionLibrary
* @return
*/
@PostMapping
public Result add(@RequestBody CollectionLibrary collectionLibrary){
//调用CollectionLibraryService实现添加CollectionLibrary
collectionLibraryService.add(collectionLibrary);
return new Result(true,StatusCode.OK,"添加成功");
}
/***
* 根据ID查询CollectionLibrary数据
* @param id
* @return
*/
@GetMapping("/{id}")
public Result<CollectionLibrary> findById(@PathVariable Long id){
//调用CollectionLibraryService实现根据主键查询CollectionLibrary
CollectionLibrary collectionLibrary = collectionLibraryService.findById(id);
return new Result<CollectionLibrary>(true,StatusCode.OK,"查询成功",collectionLibrary);
}
/***
* 查询CollectionLibrary全部数据
* @return
*/
@GetMapping
public Result<List<CollectionLibrary>> findAll(){
//调用CollectionLibraryService实现查询所有CollectionLibrary
List<CollectionLibrary> list = collectionLibraryService.findAll();
return new Result<List<CollectionLibrary>>(true, StatusCode.OK,"查询成功",list) ;
}
/***
* 加入仿写
* @return
*/
@PutMapping(value="/AddToImitation/{id}")
public Result update(@PathVariable Long id){
CollectionLibrary collectionLibrary = collectionLibraryService.findById(id);
CopyLibrary copyLibrary = new CopyLibrary();
BeanUtils.copyProperties(collectionLibrary, copyLibrary);
copyLibrary.setId(null);
copyLibrary.setAddToImitation("未加入");
copyLibraryService.add(copyLibrary);
collectionLibrary.setAddToImitation("已加入");
collectionLibraryService.update(collectionLibrary);
return new Result(true,StatusCode.OK,"添加仿写成功");
}
}
6.Service
不需要改
package com.microservices.user.service;
import com.github.pagehelper.PageInfo;
import com.microservices.user.pojo.CollectionLibrary;
import java.util.List;
/****
* @Author:shenkunlin
* @Description:CollectionLibrary业务层接口
* @Date 2019/6/14 0:16
*****/
public interface CollectionLibraryService {
/***
* CollectionLibrary多条件分页查询
* @param collectionLibrary
* @param page
* @param size
* @return
*/
PageInfo<CollectionLibrary> findPage(CollectionLibrary collectionLibrary, int page, int size);
/***
* CollectionLibrary分页查询
* @param page
* @param size
* @return
*/
PageInfo<CollectionLibrary> findPage(int page, int size);
/***
* CollectionLibrary多条件搜索方法
* @param collectionLibrary
* @return
*/
List<CollectionLibrary> findList(CollectionLibrary collectionLibrary);
/***
* 删除CollectionLibrary
* @param id
*/
void delete(Long id);
/***
* 修改CollectionLibrary数据
* @param collectionLibrary
*/
void update(CollectionLibrary collectionLibrary);
/***
* 新增CollectionLibrary
* @param collectionLibrary
*/
void add(CollectionLibrary collectionLibrary);
/**
* 根据ID查询CollectionLibrary
* @param id
* @return
*/
CollectionLibrary findById(Long id);
/***
* 查询所有CollectionLibrary
* @return
*/
List<CollectionLibrary> findAll();
}
7.Impl
1.这里的新增需要改一下
因为你在数据库里面设置了id不能自增,所以这里id会为空,所以你得设置一个id,我们使用的时雪花算法
private static final IdWorker ID_WORKER = new IdWorker();
@Override
public void add(CollectionLibrary collectionLibrary){
// ShardingSphere 的分片键是 id;若 id 为空会导致路由失败
if (collectionLibrary.getId() == null) {
collectionLibrary.setId(ID_WORKER.nextId());
}
collectionLibraryMapper.insert(collectionLibrary);
}
2.IdWorker工具
package com.microservices.entity;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
/**
* <p>名称:IdWorker.java</p>
* <p>描述:分布式自增长ID</p>
* <pre>
* Twitter的 Snowflake JAVA实现方案
* </pre>
* 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用---分割开部分的作用:
* 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
* 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
* 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
* 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
* 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
* 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
* <p>
* 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
*
* @author Polim
*/
public class IdWorker {
// 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
private final static long twepoch = 1288834974657L;
// 机器标识位数
private final static long workerIdBits = 5L;
// 数据中心标识位数
private final static long datacenterIdBits = 5L;
// 机器ID最大值
private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
// 数据中心ID最大值
private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
// 毫秒内自增位
private final static long sequenceBits = 12L;
// 机器ID偏左移12位
private final static long workerIdShift = sequenceBits;
// 数据中心ID左移17位
private final static long datacenterIdShift = sequenceBits + workerIdBits;
// 时间毫秒左移22位
private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
/* 上次生产id时间戳 */
private static long lastTimestamp = -1L;
// 0,并发控制
private long sequence = 0L;
private final long workerId;
// 数据标识id部分
private final long datacenterId;
public IdWorker(){
this.datacenterId = getDatacenterId(maxDatacenterId);
this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
}
/**
* @param workerId
* 工作机器ID
* @param datacenterId
* 序列号
*/
public IdWorker(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
/**
* 获取下一个ID
*
* @return
*/
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
// 当前毫秒内,则+1
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
// 当前毫秒内计数满了,则等待下一秒
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
// ID偏移组合生成最终的ID,并返回ID
long nextId = ((timestamp - twepoch) << timestampLeftShift)
| (datacenterId << datacenterIdShift)
| (workerId << workerIdShift) | sequence;
return nextId;
}
private long tilNextMillis(final long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
/**
* <p>
* 获取 maxWorkerId
* </p>
*/
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuffer mpid = new StringBuffer();
mpid.append(datacenterId);
String name = ManagementFactory.getRuntimeMXBean().getName();
if (!name.isEmpty()) {
/*
* GET jvmPid
*/
mpid.append(name.split("@")[0]);
}
/*
* MAC + PID 的 hashcode 获取16个低位
*/
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
}
/**
* <p>
* 数据标识id部分
* </p>
*/
protected static long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
if (network == null) {
id = 1L;
} else {
byte[] mac = network.getHardwareAddress();
id = ((0x000000FF & (long) mac[mac.length - 1])
| (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
id = id % (maxDatacenterId + 1);
}
} catch (Exception e) {
System.out.println(" getDatacenterId: " + e.getMessage());
}
return id;
}
public static void main(String[] args) {
com.microservices.entity.IdWorker idWorker = new com.microservices.entity.IdWorker(0,0);
for (int i = 0; i <10000; i++) {
long nextId=idWorker.nextId();
System.out.println(nextId);
}
}
}
3.全部代码
package com.microservices.user.service.impl;
import com.microservices.user.dao.CollectionLibraryMapper;
import com.microservices.user.pojo.CollectionLibrary;
import com.microservices.user.service.CollectionLibraryService;
import com.microservices.entity.IdWorker;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;
import java.util.List;
import java.util.regex.Pattern;
/****
* @Author:shenkunlin
* @Description:CollectionLibrary业务层接口实现类
* @Date 2019/6/14 0:16
*****/
@Service
public class CollectionLibraryServiceImpl implements CollectionLibraryService {
@Autowired
private CollectionLibraryMapper collectionLibraryMapper;
/**
* CollectionLibrary条件+分页查询
* @param collectionLibrary 查询条件
* @param page 页码
* @param size 页大小
* @return 分页结果
*/
@Override
public PageInfo<CollectionLibrary> findPage(CollectionLibrary collectionLibrary, int page, int size){
//分页
PageHelper.startPage(page,size);
//搜索条件构建
Example example = createExample(collectionLibrary);
//执行搜索
return new PageInfo<CollectionLibrary>(collectionLibraryMapper.selectByExample(example));
}
/**
* CollectionLibrary分页查询
* @param page
* @param size
* @return
*/
@Override
public PageInfo<CollectionLibrary> findPage(int page, int size){
//静态分页
PageHelper.startPage(page,size);
//分页查询
return new PageInfo<CollectionLibrary>(collectionLibraryMapper.selectAll());
}
/**
* CollectionLibrary条件查询
* @param collectionLibrary
* @return
*/
@Override
public List<CollectionLibrary> findList(CollectionLibrary collectionLibrary){
//构建查询条件
Example example = createExample(collectionLibrary);
//根据构建的条件查询数据
return collectionLibraryMapper.selectByExample(example);
}
/**
* CollectionLibrary构建查询对象
* @param collectionLibrary
* @return
*/
public Example createExample(CollectionLibrary collectionLibrary){
Example example=new Example(CollectionLibrary.class);
Example.Criteria criteria = example.createCriteria();
if(collectionLibrary!=null){
// 自增主键
if(!StringUtils.isEmpty(collectionLibrary.getId())){
criteria.andEqualTo("id",collectionLibrary.getId());
}
// 标题
if(!StringUtils.isEmpty(collectionLibrary.getTitle())){
criteria.andLike("title","%"+collectionLibrary.getTitle()+"%");
}
// 封面链接
if(!StringUtils.isEmpty(collectionLibrary.getCoverUrl())){
criteria.andEqualTo("coverUrl",collectionLibrary.getCoverUrl());
}
// 原文链接
if(!StringUtils.isEmpty(collectionLibrary.getOriginalUrl())){
criteria.andEqualTo("originalUrl",collectionLibrary.getOriginalUrl());
}
// 正文
if(!StringUtils.isEmpty(collectionLibrary.getContentBody())){
criteria.andEqualTo("contentBody",collectionLibrary.getContentBody());
}
// 话题标签
if(!StringUtils.isEmpty(collectionLibrary.getTopicTags())){
criteria.andEqualTo("topicTags",collectionLibrary.getTopicTags());
}
// 图片链接
if(!StringUtils.isEmpty(collectionLibrary.getImageUrl())){
criteria.andEqualTo("imageUrl",collectionLibrary.getImageUrl());
}
// 视频链接
if(!StringUtils.isEmpty(collectionLibrary.getVideoUrl())){
criteria.andEqualTo("videoUrl",collectionLibrary.getVideoUrl());
}
// 类型(视频、图片)
if(!StringUtils.isEmpty(collectionLibrary.getContentType())){
criteria.andEqualTo("contentType",collectionLibrary.getContentType());
}
// 博主
if(!StringUtils.isEmpty(collectionLibrary.getBloggerName())){
criteria.andEqualTo("bloggerName",collectionLibrary.getBloggerName());
}
// 点赞数
if(!StringUtils.isEmpty(collectionLibrary.getLikeCount())){
criteria.andEqualTo("likeCount",collectionLibrary.getLikeCount());
}
// 收藏数
if(!StringUtils.isEmpty(collectionLibrary.getCollectCount())){
criteria.andEqualTo("collectCount",collectionLibrary.getCollectCount());
}
// 评论数
if(!StringUtils.isEmpty(collectionLibrary.getCommentCount())){
criteria.andEqualTo("commentCount",collectionLibrary.getCommentCount());
}
// 博主链接
if(!StringUtils.isEmpty(collectionLibrary.getBloggerUrl())){
criteria.andEqualTo("bloggerUrl",collectionLibrary.getBloggerUrl());
}
// 发布时间
if(!StringUtils.isEmpty(collectionLibrary.getPublishTime())){
criteria.andEqualTo("publishTime",collectionLibrary.getPublishTime());
}
// 加入仿写
if(!StringUtils.isEmpty(collectionLibrary.getAddToImitation())){
criteria.andEqualTo("addToImitation",collectionLibrary.getAddToImitation());
}
// 采集时间
if(!StringUtils.isEmpty(collectionLibrary.getCollectionTime())){
criteria.andEqualTo("collectionTime",collectionLibrary.getCollectionTime());
}
}
return example;
}
/**
* 删除
* @param id
*/
@Override
public void delete(Long id){
collectionLibraryMapper.deleteByPrimaryKey(id);
}
/**
* 修改CollectionLibrary
* @param collectionLibrary
*/
@Override
public void update(CollectionLibrary collectionLibrary){
collectionLibraryMapper.updateByPrimaryKey(collectionLibrary);
}
/**
* 增加CollectionLibrary
* @param collectionLibrary
*/
@Override
public void add(CollectionLibrary collectionLibrary){
// ShardingSphere 的分片键是 id;若 id 为空会导致路由失败
if (collectionLibrary.getId() == null) {
collectionLibrary.setId(ID_WORKER.nextId());
}
collectionLibraryMapper.insert(collectionLibrary);
}
/**
* 根据ID查询CollectionLibrary
* @param id
* @return
*/
@Override
public CollectionLibrary findById(Long id){
return collectionLibraryMapper.selectByPrimaryKey(id);
}
/**
* 查询CollectionLibrary全部数据
* @return
*/
@Override
public List<CollectionLibrary> findAll() {
return collectionLibraryMapper.selectAll();
}
// 正则:匹配数字(包括整数、小数)
private static final Pattern NUMERIC_PATTERN = Pattern.compile("^\\d+(\\.\\d+)?$");
/**
* 预处理数值字段,将空值/无效值转为"0"
*/
private void preprocessNumericFields(CollectionLibrary collectionLibrary) {
// 1. 点赞数
collectionLibrary.setLikeCount(convertToValidNumeric(collectionLibrary.getLikeCount()));
// 2. 收藏数
collectionLibrary.setCollectCount(convertToValidNumeric(collectionLibrary.getCollectCount()));
// 3. 评论数
collectionLibrary.setCommentCount(convertToValidNumeric(collectionLibrary.getCommentCount()));
}
/**
* 将字符串转换为有效的数值字符串,空值/无效值返回"0"
*/
private String convertToValidNumeric(String value) {
// 空值处理
if (value == null || value.trim().isEmpty() || "''".equals(value) || "\"\"".equals(value)) {
return "0";
}
String trimmedValue = value.trim();
// 处理带单位的数值(如 1.2万、5k)
if (trimmedValue.contains("万") || trimmedValue.contains("W")) {
try {
String numPart = trimmedValue.replaceAll("[^0-9.]", "");
double num = Double.parseDouble(numPart) * 10000;
return String.valueOf((long) num);
} catch (Exception e) {
return "0";
}
}
if (trimmedValue.contains("千") || trimmedValue.contains("K") || trimmedValue.contains("k")) {
try {
String numPart = trimmedValue.replaceAll("[^0-9.]", "");
double num = Double.parseDouble(numPart) * 1000;
return String.valueOf((long) num);
} catch (Exception e) {
return "0";
}
}
// 验证是否为有效数字
if (NUMERIC_PATTERN.matcher(trimmedValue).matches()) {
return trimmedValue;
}
// 提取数字部分
try {
String numPart = trimmedValue.replaceAll("[^0-9.]", "");
if (numPart.isEmpty()) {
return "0";
}
return numPart;
} catch (Exception e) {
return "0";
}
}
private static final IdWorker ID_WORKER = new IdWorker();
}
8.拦截器JacksonConfig
主要是因为id太长了,前端传给后端的时候会丢失数据,所以这个要做一个处理,在根据id查询,根据id删除时都会用到这个id
创建config包
package com.microservices.user.config;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JacksonConfig {
// 这个是解决id超长的问题,id是雪花算法生成的,id的长度太长,从后端传过来的时候就会丢失数据
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> {
// 把 Long 类型全局序列化为 String
builder.serializerByType(Long.class, ToStringSerializer.instance);
builder.serializerByType(Long.TYPE, ToStringSerializer.instance);
};
}
}