12月21
什么是实时主备?
实时主备由一个主库以及一个或者多个配置了实时(Realtime)归档的备库组成,其主要目的是保障数据库可用性,提高数据安全性。实时主备系统中,主库提供完整的数据库功能,备库提供只读服务。主库修改数据产生的Redo日志,通过实时归档机制,在写入联机Redo日志文件之前发送到备库,实时备库通过重演Redo日志与主库保持数据同步。当主库出现故障时,备库在将所有Redo日志重演结束后,就可以切换为主库对外提供数据库服务
1、环境准备
服务器 主库IP:192.168.90.41 dm8数据库 实例名 :RAC1 端口号:5236
服务器 备库IP:192.168.90.42 dm8数据库 实例名 :RAC2 端口号:5236
# 数据库启动服务命令路径/dm8/bin,实例配置文件路径/dm8/data/DAMENG/
2、主备库分别初始化实例(按客户要求)
./dminit path=/dm8/data page_size=32 instance_name=RAC1
./dminit path=/dm8/data page_size=32 instance_name=RAC2
3 备份还原
# 如果是初始搭建环境,可以通过对主库脱机备份、对备库脱机还原的方式来准备数据, 如果主库已经处于运行状态,则可以对主库进行联机备份、对备库脱机还原的方式来准备数据。
实时主备由一个主库以及一个或者多个配置了实时(Realtime)归档的备库组成,其主要目的是保障数据库可用性,提高数据安全性。实时主备系统中,主库提供完整的数据库功能,备库提供只读服务。主库修改数据产生的Redo日志,通过实时归档机制,在写入联机Redo日志文件之前发送到备库,实时备库通过重演Redo日志与主库保持数据同步。当主库出现故障时,备库在将所有Redo日志重演结束后,就可以切换为主库对外提供数据库服务
1、环境准备
服务器 主库IP:192.168.90.41 dm8数据库 实例名 :RAC1 端口号:5236
服务器 备库IP:192.168.90.42 dm8数据库 实例名 :RAC2 端口号:5236
# 数据库启动服务命令路径/dm8/bin,实例配置文件路径/dm8/data/DAMENG/
2、主备库分别初始化实例(按客户要求)
./dminit path=/dm8/data page_size=32 instance_name=RAC1
./dminit path=/dm8/data page_size=32 instance_name=RAC2
3 备份还原
# 如果是初始搭建环境,可以通过对主库脱机备份、对备库脱机还原的方式来准备数据, 如果主库已经处于运行状态,则可以对主库进行联机备份、对备库脱机还原的方式来准备数据。
12月19
咱话不多说,正如标题所见,实践开始。
首先打开cmd,win键+r打开运行,输入cmd打开控制台。
在控制台中输入msg / server:IP地址 * "要发送的内容。" 注:(这里的引号要加,且*号左右必须空一格)
例如:我的ipv4地址是192.168.90.1** 注:(用ipconfig命令可查)
首先打开cmd,win键+r打开运行,输入cmd打开控制台。
在控制台中输入msg / server:IP地址 * "要发送的内容。" 注:(这里的引号要加,且*号左右必须空一格)
例如:我的ipv4地址是192.168.90.1** 注:(用ipconfig命令可查)
12月14
一. 相同之处
都是为了解决人的需求,都需要去深入挖掘目标用户的需求,进行分析转化为功能,利用最低的成本去满足用户最迫切的需求。
都需要把产品做好,用户用得爽,才能实现盈利。
产品经理和销售经理都需要具备核心能力(包括:需求分析、产品管理、项目管理、沟通能力、技术能力、业务能力、产品设计、学习能力、逻辑思维等)。
二、不同之处
(1)产品定位:
To C需从产品能给人们解决哪些问题的角度去考虑产品定位;
To B是结合商业公司内部使用需要的层面去考虑;B端产品一定要在企业的利润链上产生价值,对企业的利润产生贡献。对最终的利润正向贡献越大,产品的价值也就越大。
To G则是从国家政策、政府工作报告等体现要做什么样的产品(比如:通过“数字政府”营造粤港澳大湾区营商与政务环境)。产品定位决定了目前用户、场景、需求等一系列维度。
(2)用户定位:To C面向个人用户;To B面向企业;To G面向政府(使用用户可以为政府决策人员、普通大众、行业用户)。
(3)需求场景:To C使用场地是随时对地;To B更多是内网;To G是内外网相结合(互联网+政务)。
(4)产品模式:商业模式或者市场路线。To C需要进行用户调研寻找细分用户,通过市场调研挖掘本职需求,需要更多地思考产品设计和用户体验层次的问题;To B和To G则需要对客户进行深度沟通,寻找MVP,而且需要一套能说服客户又能寻求利益最大化的定价策略。
(5)用户需求:To C要结合用户的“人性”需要,去挖掘大多数用户的可能性,需要做各种各样的竞品分析(包括同类产品功能层面和不同类产品解决方案);To B也是找寻大多数企业的共性需求,除非是定制化需求;To G这种则是通过一个个项目形式去满足不同时期政策的需要和符合财政预算,这类需求需要通过政府客户获取。
(6)盈利模式:To C通过内容吸引用户,有了用户流,带动资金流、物流,每个用户都是盈利的来演;To B和To G走的都是项目合同制,可以分为一期、二期和n期,需要不断保持与客户的合作关系,进行迭代规划,才能实现产品的持续变现。
(7)MVP思路不同:
建设B端和C端产品时,大的原则是类似的,都是先做加法,即充分讨论、穷举所有需求和可能性;然后再做减法,选出最核心的需求点;最后设计具体方案并将其落地,用最短的时 间和最低的成本支持业务启动。
但是在选取最小功能集合(或最小可行产品)时,B端和C端产品的区别很大:
B端产品要支持业务整体运作,所以在选取最小功能集合时,即便再简化,也要保证一个核心业务流程的运转,因此B端MVP往往是一个具备一定复杂度的系统,不可能是一个或几个功能点。
C端产品需要解决用户的痛点,需要挑选一个核心痛点去打动用户,如果核心痛点定位错误,就会导致验证失败。所以在选取最小功能集合时,C端产品要聚焦用户的核心痛 点,C端MVP可能只包含一两个功能点。
都是为了解决人的需求,都需要去深入挖掘目标用户的需求,进行分析转化为功能,利用最低的成本去满足用户最迫切的需求。
都需要把产品做好,用户用得爽,才能实现盈利。
产品经理和销售经理都需要具备核心能力(包括:需求分析、产品管理、项目管理、沟通能力、技术能力、业务能力、产品设计、学习能力、逻辑思维等)。
二、不同之处
(1)产品定位:
To C需从产品能给人们解决哪些问题的角度去考虑产品定位;
To B是结合商业公司内部使用需要的层面去考虑;B端产品一定要在企业的利润链上产生价值,对企业的利润产生贡献。对最终的利润正向贡献越大,产品的价值也就越大。
To G则是从国家政策、政府工作报告等体现要做什么样的产品(比如:通过“数字政府”营造粤港澳大湾区营商与政务环境)。产品定位决定了目前用户、场景、需求等一系列维度。
(2)用户定位:To C面向个人用户;To B面向企业;To G面向政府(使用用户可以为政府决策人员、普通大众、行业用户)。
(3)需求场景:To C使用场地是随时对地;To B更多是内网;To G是内外网相结合(互联网+政务)。
(4)产品模式:商业模式或者市场路线。To C需要进行用户调研寻找细分用户,通过市场调研挖掘本职需求,需要更多地思考产品设计和用户体验层次的问题;To B和To G则需要对客户进行深度沟通,寻找MVP,而且需要一套能说服客户又能寻求利益最大化的定价策略。
(5)用户需求:To C要结合用户的“人性”需要,去挖掘大多数用户的可能性,需要做各种各样的竞品分析(包括同类产品功能层面和不同类产品解决方案);To B也是找寻大多数企业的共性需求,除非是定制化需求;To G这种则是通过一个个项目形式去满足不同时期政策的需要和符合财政预算,这类需求需要通过政府客户获取。
(6)盈利模式:To C通过内容吸引用户,有了用户流,带动资金流、物流,每个用户都是盈利的来演;To B和To G走的都是项目合同制,可以分为一期、二期和n期,需要不断保持与客户的合作关系,进行迭代规划,才能实现产品的持续变现。
(7)MVP思路不同:
建设B端和C端产品时,大的原则是类似的,都是先做加法,即充分讨论、穷举所有需求和可能性;然后再做减法,选出最核心的需求点;最后设计具体方案并将其落地,用最短的时 间和最低的成本支持业务启动。
但是在选取最小功能集合(或最小可行产品)时,B端和C端产品的区别很大:
B端产品要支持业务整体运作,所以在选取最小功能集合时,即便再简化,也要保证一个核心业务流程的运转,因此B端MVP往往是一个具备一定复杂度的系统,不可能是一个或几个功能点。
C端产品需要解决用户的痛点,需要挑选一个核心痛点去打动用户,如果核心痛点定位错误,就会导致验证失败。所以在选取最小功能集合时,C端产品要聚焦用户的核心痛 点,C端MVP可能只包含一两个功能点。
11月23
用 security加redis写项目时一直报这个错误,说是没有set方法?我用的data注解怎么可能
这个bug找了一下午,终于找到原因了:redis序列化会查询所有以get和set开头的方法,而我的user继承了security的UserDetails,多了一个集合类型的getAuthorities方法,所有导致无法序列化,使用的是jackson的序列化器
解决办法:
加上@JsonIgnore注解设置不序列化
@JsonIgnore
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
ArrayList<NdpAuthority> grantedAuthorities = CollectionUtil.newArrayList();
if (ObjUtil.isNotEmpty(roles)) {
roles.forEach(dict -> {
String roleName = dict.getStr(CommonConstant.NAME);
NdpAuthority ndpAuthority = new NdpAuthority(roleName);
grantedAuthorities.add(ndpAuthority);
});
}
return grantedAuthorities;
}
加个属性,写个对应的set方法
这个bug找了一下午,终于找到原因了:redis序列化会查询所有以get和set开头的方法,而我的user继承了security的UserDetails,多了一个集合类型的getAuthorities方法,所有导致无法序列化,使用的是jackson的序列化器
解决办法:
加上@JsonIgnore注解设置不序列化
@JsonIgnore
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
ArrayList<NdpAuthority> grantedAuthorities = CollectionUtil.newArrayList();
if (ObjUtil.isNotEmpty(roles)) {
roles.forEach(dict -> {
String roleName = dict.getStr(CommonConstant.NAME);
NdpAuthority ndpAuthority = new NdpAuthority(roleName);
grantedAuthorities.add(ndpAuthority);
});
}
return grantedAuthorities;
}
加个属性,写个对应的set方法
11月23
在实际项目开发过程中,我们有时候需要让项目在启动时执行特定方法。如要实现这些功能:
提前加载相应的数据到缓存中;
检查当前项目运行环境;
检查程序授权信息,若未授权则不能使用后续功能;
执行某个特定方法;
一直想整理一下Springboot启动后自执行某段代码或者方法相关的点,囿于时间问题及担心理解不是太全面所以没整理,后来一想先整理出来,将这一方面的东西记录下来。其实这篇文章不应该体现spring boot,因为自动执行方式不仅限于spring boot,java spring细化到bean的初始化都可以完成。
一、java自身的启动时加载方式
1、static代码块
static静态代码块,在类加载的时候即自动执行。 由于静态代码块没有名字,我们并不能主动调用,它会在类加载的时候,自动执行。所以静态代码块,可以更早的给类中的静态属性,进行初始化赋值操作。并且,静态代码块只会自动被执行一次,因为JVM在一次运行中,对一个类只会加载一次!
2、构造函数constructor
在对象初始化时执行。执行顺序在static静态代码块之后。
3、@PostConstruct注解
@PostConstruct
public void testInit() {
System.out.printin("postConstruct“);
}
@PostConstruct注解使用在方法上,这个方法在对象依赖注入初始化之后执行。执行节点在BeanPostProcessor的postProcessBeforeInitialization之后,在postProcessAfterInitialization之前。
很多人以为该注解是Spring提供的。其实是Java自己的注解。Java中该注解的说明:@PostConstruct该注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。
注意:加了postconstruct注解的方法,如果执行失败,整个程序会无法正常启动!这个方法执行不完,整个程序也启动不了!也不建议将耗时逻辑放到这里面来。
二、Servlet加载的方式
1、实现ServletContextListener接口contextInitialized方法
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
@Slf4j
@Component
public class ServletContextListenerImpl implements ServletContextListener {
/**
* 在初始化Web应用程序中的任何过滤器或Servlet之前,将通知所有ServletContextListener上下文初始化。
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("启动时自动执行 ServletContextListener 的 contextInitialized 方法");
}
}
注意:该方法会在填充完普通Bean的属性,但是还没有进行Bean的初始化之前执行
三、Spring启动时加载方式
1、实现ServletContextAware接口setServletContext 方法
@Component
public class StartInitServletContext implements ServletContextAware {
@Override
public void setServletContext(ServletContext servletContext) {
System.out.println("StartInitServletContext: 开始处理事情");
}
}
2、ApplicationListener监听器
创建Listener的方式有两种:
方式1:编程实现ApplicationListener接口
方式2:使用@EventListener注解
注意监听的事件,通常是ApplicationStartedEvent 或者ApplicationReadyEvent,其他的事件可能无法注入bean。
编程实现ApplicationListener接口
/**
* 监听的是 ApplicationStartedEvent 事件,
* 则 ApplicationListener 一定会在 CommandLineRunner 和 ApplicationRunner 之前执行;
*/
@Component
public class StartInitStartedEvent implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("StartInitStartedEvent:开始处理事情");
}
}
/**
* 监听的是 ApplicationReadyEvent 事件,
* 则 ApplicationListener 一定会在 CommandLineRunner 和 ApplicationRunner 之后执行;
*/
@Component
public class StartInitReadyEvent implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
System.out.println("StartInitReadyEvent: 开始处理事情");
}
}
实现 public interface ApplicationListener<E extends ApplicationEvent> 接口,监听 ApplicationEvent 及其下面的子事件:
/**
* 事件监听器一般是由开发者自己定义
* 定义事件监听器
*/
@Component
//@Lazy
public class MyApplicationListener implements ApplicationListener{
@Override
public void onApplicationEvent(ApplicationEvent event) {
event = (PayloadApplicationEvent)event;
System.out.println(((PayloadApplicationEvent<?>) event).getPayload());
}
}
@EventListener方式
将要执行的方法所在的类交个Spring容器扫描(@Component),并且在要执行的方法上添加@EventListener注解执行
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class EventListenerTest {
@EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
log.info("启动时自动执行 @EventListener 注解方法");
}
}
3、InitializingBean接口
@Component
@Data
public class TestInit implements InitializingBean,eanFactoryAware,ApplicationContextAware{
private BeanFactory beanFactory:
private ApplicationContext applicationContext;
private String name;
@Override
public voidafterPropertiesSet(hrows Exception {
System.out.printin("InIt heck");
}
}
Spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中通过init-method指定,两种方式可以同时使用。
实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率要高一点,但是init-method方式消除了对spring的依赖。先调用afterPropertieSet()方法,然后再调用init-method中指定的方法。
4、ApplicationRunner和CommandLineRunner
SpringBoot提供了两个接口来实现Spring容器启动完成后执行的功能,两个接口分别为CommandLineRunner和ApplicationRunner。这两个接口需要实现一个run方法,将代码在run中实现即可。这两个接口功能基本一致,其区别在于run方法的入参。ApplicationRunner的run方法入参为ApplicationArguments,为CommandLineRunner的run方法入参为String数组。
提前加载相应的数据到缓存中;
检查当前项目运行环境;
检查程序授权信息,若未授权则不能使用后续功能;
执行某个特定方法;
一直想整理一下Springboot启动后自执行某段代码或者方法相关的点,囿于时间问题及担心理解不是太全面所以没整理,后来一想先整理出来,将这一方面的东西记录下来。其实这篇文章不应该体现spring boot,因为自动执行方式不仅限于spring boot,java spring细化到bean的初始化都可以完成。
一、java自身的启动时加载方式
1、static代码块
static静态代码块,在类加载的时候即自动执行。 由于静态代码块没有名字,我们并不能主动调用,它会在类加载的时候,自动执行。所以静态代码块,可以更早的给类中的静态属性,进行初始化赋值操作。并且,静态代码块只会自动被执行一次,因为JVM在一次运行中,对一个类只会加载一次!
2、构造函数constructor
在对象初始化时执行。执行顺序在static静态代码块之后。
3、@PostConstruct注解
@PostConstruct
public void testInit() {
System.out.printin("postConstruct“);
}
@PostConstruct注解使用在方法上,这个方法在对象依赖注入初始化之后执行。执行节点在BeanPostProcessor的postProcessBeforeInitialization之后,在postProcessAfterInitialization之前。
很多人以为该注解是Spring提供的。其实是Java自己的注解。Java中该注解的说明:@PostConstruct该注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。
注意:加了postconstruct注解的方法,如果执行失败,整个程序会无法正常启动!这个方法执行不完,整个程序也启动不了!也不建议将耗时逻辑放到这里面来。
二、Servlet加载的方式
1、实现ServletContextListener接口contextInitialized方法
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
@Slf4j
@Component
public class ServletContextListenerImpl implements ServletContextListener {
/**
* 在初始化Web应用程序中的任何过滤器或Servlet之前,将通知所有ServletContextListener上下文初始化。
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("启动时自动执行 ServletContextListener 的 contextInitialized 方法");
}
}
注意:该方法会在填充完普通Bean的属性,但是还没有进行Bean的初始化之前执行
三、Spring启动时加载方式
1、实现ServletContextAware接口setServletContext 方法
@Component
public class StartInitServletContext implements ServletContextAware {
@Override
public void setServletContext(ServletContext servletContext) {
System.out.println("StartInitServletContext: 开始处理事情");
}
}
2、ApplicationListener监听器
创建Listener的方式有两种:
方式1:编程实现ApplicationListener接口
方式2:使用@EventListener注解
注意监听的事件,通常是ApplicationStartedEvent 或者ApplicationReadyEvent,其他的事件可能无法注入bean。
编程实现ApplicationListener接口
/**
* 监听的是 ApplicationStartedEvent 事件,
* 则 ApplicationListener 一定会在 CommandLineRunner 和 ApplicationRunner 之前执行;
*/
@Component
public class StartInitStartedEvent implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("StartInitStartedEvent:开始处理事情");
}
}
/**
* 监听的是 ApplicationReadyEvent 事件,
* 则 ApplicationListener 一定会在 CommandLineRunner 和 ApplicationRunner 之后执行;
*/
@Component
public class StartInitReadyEvent implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
System.out.println("StartInitReadyEvent: 开始处理事情");
}
}
实现 public interface ApplicationListener<E extends ApplicationEvent> 接口,监听 ApplicationEvent 及其下面的子事件:
/**
* 事件监听器一般是由开发者自己定义
* 定义事件监听器
*/
@Component
//@Lazy
public class MyApplicationListener implements ApplicationListener{
@Override
public void onApplicationEvent(ApplicationEvent event) {
event = (PayloadApplicationEvent)event;
System.out.println(((PayloadApplicationEvent<?>) event).getPayload());
}
}
@EventListener方式
将要执行的方法所在的类交个Spring容器扫描(@Component),并且在要执行的方法上添加@EventListener注解执行
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class EventListenerTest {
@EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
log.info("启动时自动执行 @EventListener 注解方法");
}
}
3、InitializingBean接口
@Component
@Data
public class TestInit implements InitializingBean,eanFactoryAware,ApplicationContextAware{
private BeanFactory beanFactory:
private ApplicationContext applicationContext;
private String name;
@Override
public voidafterPropertiesSet(hrows Exception {
System.out.printin("InIt heck");
}
}
Spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中通过init-method指定,两种方式可以同时使用。
实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率要高一点,但是init-method方式消除了对spring的依赖。先调用afterPropertieSet()方法,然后再调用init-method中指定的方法。
4、ApplicationRunner和CommandLineRunner
SpringBoot提供了两个接口来实现Spring容器启动完成后执行的功能,两个接口分别为CommandLineRunner和ApplicationRunner。这两个接口需要实现一个run方法,将代码在run中实现即可。这两个接口功能基本一致,其区别在于run方法的入参。ApplicationRunner的run方法入参为ApplicationArguments,为CommandLineRunner的run方法入参为String数组。
10月11
${ew.customSqlSegment} 会直接在前面添加 where
@Select(select * from a ${ew.customSqlSegment})
List<a> getHeck(@Param(Constants.WRAPPER)QueryWrapper queryWrapper)
${ew.sqlSegment} 就只有条件语句
@Select(select * from a where ${ew.sqlSegment})
List<a> getHeck(@Param(Constants.WRAPPER)QueryWrapper queryWrapper)
${ew.sqlSelect} 就是 queryWrapper.select(****) 你所定义需要查询的字段
@Select(select ${ew.sqlSelect} from a )
List<a> getHeck(@Param(Constants.WRAPPER)QueryWrapper queryWrapper)
@Select(select * from a ${ew.customSqlSegment})
List<a> getHeck(@Param(Constants.WRAPPER)QueryWrapper queryWrapper)
${ew.sqlSegment} 就只有条件语句
@Select(select * from a where ${ew.sqlSegment})
List<a> getHeck(@Param(Constants.WRAPPER)QueryWrapper queryWrapper)
${ew.sqlSelect} 就是 queryWrapper.select(****) 你所定义需要查询的字段
@Select(select ${ew.sqlSelect} from a )
List<a> getHeck(@Param(Constants.WRAPPER)QueryWrapper queryWrapper)
9月4
错误信息:
Could not read JSON: Cannot construct instance of java.util.ArrayList$SubList(no Creators, like default construct, exist): no default no-arguments constructor found
原因是读取Redis缓存时,报错异常导致!
原因是缓存中是集合ArrayList中含有SubList,因为SubList不能序列化和反序列化,导致解析失败。
解决办法:
1、若存在使用SubList方法,只需要 重新new 下:
原代码: resultList = regionDistributionVOList.subList(ZERO, FOUR);
改正后: resultList = new ArrayList<>(regionDistributionVOList.subList(ZERO, FOUR));
或者: resultList.addAll(regionDistributionVOList.subList(ZERO, FOUR));
2、若通过 Lists.partition(ZERO, TEN)获取的,则需要将subList转为ArrayList
用: Lists.newArrayList(subList)
Could not read JSON: Cannot construct instance of java.util.ArrayList$SubList(no Creators, like default construct, exist): no default no-arguments constructor found
原因是读取Redis缓存时,报错异常导致!
原因是缓存中是集合ArrayList中含有SubList,因为SubList不能序列化和反序列化,导致解析失败。
解决办法:
1、若存在使用SubList方法,只需要 重新new 下:
原代码: resultList = regionDistributionVOList.subList(ZERO, FOUR);
改正后: resultList = new ArrayList<>(regionDistributionVOList.subList(ZERO, FOUR));
或者: resultList.addAll(regionDistributionVOList.subList(ZERO, FOUR));
2、若通过 Lists.partition(ZERO, TEN)获取的,则需要将subList转为ArrayList
用: Lists.newArrayList(subList)
8月24
首先经过了解查看源码,@Scheduled是单线程的,如果有多个定时任务,势必需要前一个任务执行完才会执行后面的任务

所以我们有三种方法解决定时任务线程池配置解决多个定时任务阻塞问题
1、重写SchedulingConfigurer#configureTasks(),直接实现SchedulingConfigurer这个接口,设置taskScheduler
2、也可以配置文件配置,Spring Boot quartz 已经提供了一个配置用来配置线程池的大小 spring.task.scheduling.pool.size=10
3、配置线程池,再使用@Async开启异步任务
package com.nine.rivers.apps.core.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.ThreadPoolExecutor;
import static com.nine.rivers.apps.core.constants.NumberConstant.*;
/**
* 定时任务线程池配置解决多个定时任务阻塞问题
* 三种方法,任选期一:
* <p>1、重写SchedulingConfigurer#configureTasks(),直接实现SchedulingConfigurer这个接口,设置taskScheduler
* <p>2、也可以配置文件配置,Spring Boot quartz 已经提供了一个配置用来配置线程池的大小 spring.task.scheduling.pool.size=10
* <p>3、配置线程池,再使用@Async开启异步任务
*
* @author heck
* @date 2023/08/24
*/
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskScheduler());
}
/**
* 覆盖taskScheduler
*/
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(SIX);
taskScheduler.setThreadNamePrefix("ndp-apps-scheduler-pool-");
return taskScheduler;
}
}
方法三
/**
* 配置线程池,再使用@Async开启异步任务
*/
@Bean
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();
poolTaskExecutor.setCorePoolSize(FOUR);
poolTaskExecutor.setMaxPoolSize(SIX);
// 设置线程活跃时间(秒)
poolTaskExecutor.setKeepAliveSeconds(TWO * SIX * TEN);
// 设置队列容量
poolTaskExecutor.setQueueCapacity(FOUR * TEN);
poolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
poolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
return poolTaskExecutor;
}
所以我们有三种方法解决定时任务线程池配置解决多个定时任务阻塞问题
1、重写SchedulingConfigurer#configureTasks(),直接实现SchedulingConfigurer这个接口,设置taskScheduler
2、也可以配置文件配置,Spring Boot quartz 已经提供了一个配置用来配置线程池的大小 spring.task.scheduling.pool.size=10
3、配置线程池,再使用@Async开启异步任务
package com.nine.rivers.apps.core.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.ThreadPoolExecutor;
import static com.nine.rivers.apps.core.constants.NumberConstant.*;
/**
* 定时任务线程池配置解决多个定时任务阻塞问题
* 三种方法,任选期一:
* <p>1、重写SchedulingConfigurer#configureTasks(),直接实现SchedulingConfigurer这个接口,设置taskScheduler
* <p>2、也可以配置文件配置,Spring Boot quartz 已经提供了一个配置用来配置线程池的大小 spring.task.scheduling.pool.size=10
* <p>3、配置线程池,再使用@Async开启异步任务
*
* @author heck
* @date 2023/08/24
*/
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskScheduler());
}
/**
* 覆盖taskScheduler
*/
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(SIX);
taskScheduler.setThreadNamePrefix("ndp-apps-scheduler-pool-");
return taskScheduler;
}
}
方法三
/**
* 配置线程池,再使用@Async开启异步任务
*/
@Bean
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();
poolTaskExecutor.setCorePoolSize(FOUR);
poolTaskExecutor.setMaxPoolSize(SIX);
// 设置线程活跃时间(秒)
poolTaskExecutor.setKeepAliveSeconds(TWO * SIX * TEN);
// 设置队列容量
poolTaskExecutor.setQueueCapacity(FOUR * TEN);
poolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
poolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
return poolTaskExecutor;
}
8月21
错误原因和现象
在执行shell脚本的时候,报错:/bin/bash^M: bad interpreter: No such file or directory。
是由于该脚本文件是在Windows平台编写,然后在MacOS或者Kylin-Server平台中执行。
在Windows平台上文件是dos格式,换行符尾\r\n,而MacOS或者Kylin-Server平台文件是unix格式,换行符尾\n。因此在运行脚本文件时,不能正确解析\r,导致编译错误、运行失败。
解决方案
在MacOS或者Kylin-Server平台上,打开命令行工具执行命令vim *.sh(编辑你的脚本文件),然后执行命令:set ff=unix,最后执行:wq( 保存退出)即可。
在执行shell脚本的时候,报错:/bin/bash^M: bad interpreter: No such file or directory。
是由于该脚本文件是在Windows平台编写,然后在MacOS或者Kylin-Server平台中执行。
在Windows平台上文件是dos格式,换行符尾\r\n,而MacOS或者Kylin-Server平台文件是unix格式,换行符尾\n。因此在运行脚本文件时,不能正确解析\r,导致编译错误、运行失败。
解决方案
在MacOS或者Kylin-Server平台上,打开命令行工具执行命令vim *.sh(编辑你的脚本文件),然后执行命令:set ff=unix,最后执行:wq( 保存退出)即可。
7月24
方式一:SM2密钥在线生成
SM2密钥在线生成工具
如果你没线下生成工具,可用下面2种线上生成方式之一:
1. sm2密钥在线生成(const.net.cn)
2. web encrypt(webencrypt.org)
方式一:生成SM2公私钥(.pem格式)
一.系统环境
系统环境:windows系统。
二.工具软件
工具软件:Win64OpenSSL。
三.生成SM2公私钥
步骤一:在windows操作系统上安装Win64OpenSSL软件;
步骤二:打开Win64OpenSSL软件,首先生成私钥,命令为:ecparam -genkey -name SM2 -out priv.key;
SM2密钥在线生成工具
如果你没线下生成工具,可用下面2种线上生成方式之一:
1. sm2密钥在线生成(const.net.cn)
2. web encrypt(webencrypt.org)
方式一:生成SM2公私钥(.pem格式)
一.系统环境
系统环境:windows系统。
二.工具软件
工具软件:Win64OpenSSL。
三.生成SM2公私钥
步骤一:在windows操作系统上安装Win64OpenSSL软件;
步骤二:打开Win64OpenSSL软件,首先生成私钥,命令为:ecparam -genkey -name SM2 -out priv.key;







