不懂咱就学,记不住多看几遍(二)

一、Redis分布式锁中加锁与解锁、过期如何续命

实现要点:

  1. 互斥性,同一时刻,只能有一个客户端持有锁。
  2. 防止死锁发生,如果持有锁的客户端因崩溃而没有主动释放锁,也要保证锁可以释放并且其他客户端可以正常加锁。
  3. 加锁和释放锁必须是同一个客户端。
  4. 容错性,只要redis还有节点存活,就可以进行正常的加锁解锁操作。

加锁:直接使用set命令同时设置唯一id和过期时间;

解锁:加锁之后可以返回唯一id,标志此锁是该客户端锁拥有;释放锁时要先判断拥有者是否是自己,然后删除,这个需要redis的lua脚本保证两个命令的原子性执行。

@Slf4j
public class RedisDistributedLock {private static final String LOCK_SUCCESS = "OK";private static final Long RELEASE_SUCCESS = 1L;private static final String SET_IF_NOT_EXIST = "NX";private static final String SET_WITH_EXPIRE_TIME = "PX";// 锁的超时时间private static int EXPIRE_TIME = 5 * 1000;// 锁等待时间private static int WAIT_TIME = 1 * 1000;private Jedis jedis;private String key;public RedisDistributedLock(Jedis jedis, String key) {this.jedis = jedis;this.key = key;}// 不断尝试加锁public String lock() {try {// 超过等待时间,加锁失败long waitEnd = System.currentTimeMillis() + WAIT_TIME;String value = UUID.randomUUID().toString();while (System.currentTimeMillis() < waitEnd) {String result = jedis.set(key, value, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, EXPIRE_TIME);if (LOCK_SUCCESS.equals(result)) {return value;}try {Thread.sleep(10);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}} catch (Exception ex) {log.error("lock error", ex);}return null;}public boolean release(String value) {if (value == null) {return false;}// 判断key存在并且删除key必须是一个原子操作// 且谁拥有锁,谁释放String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";Object result = new Object();try {result = jedis.eval(script, Collections.singletonList(key),Collections.singletonList(value));if (RELEASE_SUCCESS.equals(result)) {log.info("release lock success, value:{}", value);return true;}} catch (Exception e) {log.error("release lock error", e);} finally {if (jedis != null) {jedis.close();}}log.info("release lock failed, value:{}, result:{}", value, result);return false;}
}

过期续命:守护线程续命,额外起一个线程,定期检查线程是否还持有锁,如果有则延长过期时间。Redisson 里面就实现了这个方案,使用 “看门狗” 定期检查(每1/3的锁时间检查1次),如果线程还持有锁,则刷新过期时间。

在获取锁成功后,给锁加一个 watchdog,watchdog 会起一个定时任务,在锁没有被释放且快要过期的时候会续期。

二、Spring的ApplicationEvent的使用场景

实现观察者模式的方法,ApplicationContextAware 我们可以把系统中所有ApplicationEvent传播给系统中所有的ApplicationListener;

三、SpringMVC拦截器和过滤器区别

1 拦截器是基于java的反射机制的,而过滤器是基于函数回调。
2 过滤器是servlet规范规定的,只能用于web程序中,而拦截器是在spring容器中,它不依赖servlet容器。
3 过滤器可以拦截几乎所有的请求(包含对静态资源的请求),而拦截器只拦截action请求(不拦截静态资源请求)。
4 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
5 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
6 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
7 拦截器是被包裹在过滤器之中。
Filter pre -> doService -> dispatcher -> preHandle -> controller -> postHandle -> afterCompletion -> Filter after

四、一个项目中可以有多个dispatcherServelt吗?为什么?

可以配置,优先级不同;

<load-on-startup>1</load-on-startup>是启动顺序,让这个Servlet随Servletp容器一起启动。
<url-pattern>*.form</url-pattern>会拦截*.form结尾的请求。
<servlet-name>example</servlet-name>

五、SpringAOP涉及到什么设计模式?底层原理?

使用到的模式:适配器模式 单例模式 责任链模式 简单工厂 观察者 模版 代理 策略

【1】AOP的设计
    在Spring的底层,如果我们配置了代理模式,Spring会为每一个Bean创建一个对应的ProxyFactoryBean的FactoryBean来创建某个对象的代理对象。
    每个 Bean 都会被 JDK 或者 Cglib 代理。取决于是否有接口。
    每个 Bean 会有多个“方法拦截器”。注意:拦截器分为两层,外层由 Spring 内核控制流程,内层拦截器是用户设置,也就是 AOP。
    当代理方法被调用时,先经过外层拦截器,外层拦截器根据方法的各种信息判断该方法应该执行哪些“内层拦截器”。内层拦截器的设计就是职责连的设计。

【2】代理的创建
    首先,需要创建代理工厂,代理工厂需要 3 个重要的信息:拦截器数组,目标对象接口数组,目标对象。
    创建代理工厂时,默认会在拦截器数组尾部再增加一个默认拦截器 —— 用于最终的调用目标方法。
    当调用 getProxy 方法的时候,会根据接口数量大余 0 条件返回一个代理对象(JDK or Cglib)。
    注意:创建代理对象时,同时会创建一个外层拦截器,这个拦截器就是 Spring 内核的拦截器。用于控制整个 AOP 的流程。

【3】代理的调用
    当对代理对象进行调用时,就会触发外层拦截器。
    外层拦截器根据代理配置信息,创建内层拦截器链。创建的过程中,会根据表达式判断当前拦截是否匹配这个拦截器。而这个拦截器链设计模式就是职责链模式。
    当整个链条执行到最后时,就会触发创建代理时那个尾部的默认拦截器,从而调用目标方法。最后返回。

五、SpringBoot配置文件加载优先级

1.命令行参数
2.jar包外部的application-{profile}.propertie或application.yml(带spring.profile)配置文件
3.jar包内部的application-{profile}.propertie或application.yml(带spring.profile)配置文件
4.jar包外部的application.propertie或application.yml(不带spring.profile)配置文件
5.jar包内部的application.propertie或application.yml(不带spring.profile)配置文件

六、SpringBoot启动原理

1.从MANIFEST.MF可以看到Main函数是JarLauncher
2.JarLauncher先找到自己所在的目标jar的路径,然后创建了一个Archive。
3.获取lib/下面的jar,并创建一个LaunchedURLClassLoader
4.再从MANIFEST.MF里读取到Start-Class,然后创建一个新的线程来启动应用的Main函数。

七、MySQL聚簇索引

数据库的索引从不同的角度可以划分成不同的类型,聚簇索引便是其中一种。

聚簇索引英文是 Clustered Index,有时候小伙伴们可能也会看到有人将之称为聚集索引等,与之相对的是非聚簇索引或者二级索引。

聚簇索引并不是一种单独的索引类型,而是一种数据的存储方式。在 MySQL 的 InnoDB 存储引擎中,所谓的聚簇索引实际上就是在同一个 B+Tree 中保存了索引和数据行:此时,数据放在叶子结点中,聚簇聚簇,意思就是说数据行和对应的键值紧凑的存在一起。

假设我有如下数据:

那么它的聚簇索引大概就是这个样子:

MySQL 表中的数据在磁盘中只可能保存一份,不可能保存两份,所以,在一个表中,聚簇索引只可能有一个,不可能有多个。

聚簇索引和主键

在 MySQL 中,如果表本身就有设置主键,那么主键就是聚簇索引;如果表本身没有设置主键,则会选择表中的一个唯一且非空的索引来作为聚簇索引;如果表中连唯一非空的索引都没有,那么就会自动选择表中的隐式主键来作为聚簇索引。

1.聚簇索引不一定是主键索引。

2.主键索引一定是聚簇索引。

最佳实践

在使用聚簇索引的时候,主键最好不要使用 UUID 这种随机字符串,使用 UUID 随机字符串至少存在两方面的问题:

    1.插入效率低,因为插入可能会导致页分裂,这个前面已经说过了。

    2.UUID 字符串所占用的存储空间远远大于一个 bigint,如果使用 UUID 来做主键,意味着在二级索引中,一个叶子结点能够存储的主键值就非常有限,进而可能会导致树增高,搜索时候 IO 次数增多,性能下降。

所以相对来说,主键自增会优于 UUID。

八、重写和重载,参数列表相同,只是泛型不同,会不会报错

重载: 发生在 同一个类中方法名相同而参数列表不同(类型,个数,顺序),返回值类型访问修饰符 可以相同也可以不同。

虽然在方法重载中可以使两个方法的返回值类型不同,但是只有返回值类型不同并不足以区分两个方法的重载,还需要通过参数列表来设置。

重写: 发生在 父子类中方法名和参数列表必须相同 ,返回值类型小于等于父类(即与被重写的方法的返回值类型相同或者是其子类),抛出的异常范围小于等于父类,访问修饰符大于等于父类;如果父类方法访问修饰符为 private ,则子类不能重写该方法。

九、写一个单例(如何防止反射反序列化破坏)

饿汉式:线程安全,调用效率高,不可延时加载

public class Singleton {//单例,构造方法不能给到外界调用private Singleton() {};//加载类时就直接创建对象private static Singleton instance = new Singleton();//将对象的调用方法暴露给外界public static Singleton getInstance(){return instance;}
}

饱汉式:线程安全,调用效率低,可延时加载

public static volatic Singleton  {//单例,构造方法不能给到外界调用private Singleton() {};//饱汉,调用时才实例化,多线程需要禁止指令重排序,且变量的改变需要对其它线程都可见,必须使用volatileprivate static volatile Singleton instance = null;//将对象的调用方法暴露给外界public static Singleton getInstance() {if (null == instance){//对象未创建时,进入实例化对象语句块synchronized (Singleton.class){//需要考虑并发,多个线程进入语句块,保证只有一个线程能实例化对象if( null == instance)	{instance = new Singleton();	}}	}return instance;}
}

内部静态类: 具备饿汉式单例模式优点的同时,又可延迟加载

public class Singleton {//单例,构造方法不能给到外界调用private Singleton() {};//静态内部类可以访问外部类的静态属性和静态方法private static class Inner {private static Singleton instance = new Singleton();	}//将对象的调用方法暴露给外界public static Singleton getInstance(){return Inner.instance;}
}

枚举类:枚举单例模式可以防止反射去创建实例

public enum  EnumSingleton {//创建一个枚举对象,该对象天生为单例INSTANCE;public EnumSingleton getInstance(){return INSTANCE;}
}

另一种防止反射的方式(修改构造函数,支持饿汉式、饱汉式、内部静态类):

/*** 单例防反射测试  饿汉式试验* @author Administrator*/
public class SingletonTest {private static boolean flag = false;//单例,构造方法不能给到外界调用private SingletonTest() {synchronized(SingletonTest.class) {if (false == flag) {flag = !flag;} else {throw new RuntimeException("单例模式正在被攻击");}}};//加载类时就直接创建对象private static SingletonTest instance = new SingletonTest();//将对象的调用方法暴露给外界public static SingletonTest getInstance(){return instance;}public static void main(String[] args) {try {Class<SingletonTest> classType = SingletonTest.class;Constructor<SingletonTest> constructor = classType.getDeclaredConstructor(null);constructor.setAccessible(true);SingletonTest singleton = (SingletonTest) constructor.newInstance();SingletonTest singleton2 = SingletonTest.getInstance();System.out.println(singleton == singleton2);} catch (Exception e) {e.printStackTrace();}}
}

可以参考:单例线程池小工具,轻量级使用,可以在小项目中通过一两句话使用线程池。_getsinglepool()-CSDN博客

内存级缓存ConcurrentSkipListMap实现方式_folly concurrentskiplistmap-CSDN博客 中的MemoryCache类

十、ArrayList底层原理

1.使用数组存储元素

2.动态扩容 初始化10,自增1.5倍

3.线程不安全

4.插入和删除元素需要移动数组,导致效率下降

5.随机访问:读取元素时效率较高

十一、手写一个定时的线程池

一篇文章让你彻底搞懂定时线程池ScheduledThreadPoolExecutor(深度剖析)-CSDN博客

十二、Java自带的序列化方式

JDK 自带的序列化,只需实现 java.io.Serializable接口即可

JDK 自带的序列化方式一般不会用 ,因为序列化效率低并且存在安全问题。比较常用的序列化协议有 Hessian、Kryo、Protobuf、ProtoStuff,这些都是基于二进制的序列化协议。

像 JSON 和 XML 这种属于文本类序列化方式。虽然可读性比较好,但是性能较差,一般不会选择。

十三、项目中如何使用策略模式

if判断非常多的时候

public interface Strategy {public int doOperation(int num1, int num2);
}public class OperationAdd implements Strategy{@Overridepublic int doOperation(int num1, int num2) {return num1 + num2;}
}public class OperationSubtract implements Strategy{@Overridepublic int doOperation(int num1, int num2) {return num1 - num2;}
}public class Context {private Strategy strategy;public Context(Strategy strategy){this.strategy = strategy;}public int executeStrategy(int num1, int num2){return strategy.doOperation(num1, num2);}
}public class StrategyPatternDemo {public static void main(String[] args) {Context context = new Context(new OperationAdd());    System.out.println("10 + 5 = " + context.executeStrategy(10, 5));context = new Context(new OperationSubtract());      System.out.println("10 - 5 = " + context.executeStrategy(10, 5));}
}

 参考: 五:策略模式 + 工厂方法

十四、Spring注解demo

注解类:

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {/*** 模块*/String title() default "";/*** 功能*/BusinessType businessType() default BusinessType.OTHER;/*** 操作人类别*/OperatorType operatorType() default OperatorType.MANAGE;/*** 是否保存请求的参数*/boolean isSaveRequestData() default true;/*** 是否保存响应的参数*/boolean isSaveResponseData() default true;/*** 排除指定的请求参数*/String[] excludeParamNames() default {};}

业务执行类:

/*** 操作日志记录处理** @author douzi*/
@Slf4j
@Aspect
@Component
public class LogAspect {/*** 排除敏感属性字段*/public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };/*** 处理完请求后执行** @param joinPoint 切点*/@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {handleLog(joinPoint, controllerLog, null, jsonResult);}/*** 拦截异常操作** @param joinPoint 切点* @param e         异常*/@AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {handleLog(joinPoint, controllerLog, e, null);}protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {try {// *========数据库日志=========*//OperLogEvent operLog = new OperLogEvent();operLog.setStatus(BusinessStatus.SUCCESS.ordinal());// 请求的地址String ip = ServletUtils.getClientIP();operLog.setOperIp(ip);operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));operLog.setOperName(LoginHelper.getUsername());if (e != null) {operLog.setStatus(BusinessStatus.FAIL.ordinal());operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));}// 设置方法名称String className = joinPoint.getTarget().getClass().getName();String methodName = joinPoint.getSignature().getName();operLog.setMethod(className + "." + methodName + "()");// 设置请求方式operLog.setRequestMethod(ServletUtils.getRequest().getMethod());// 处理设置注解上的参数getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);// 发布事件保存数据库SpringUtils.context().publishEvent(operLog);} catch (Exception exp) {// 记录本地异常日志log.error("异常信息:{}", exp.getMessage());exp.printStackTrace();}}/*** 获取注解中对方法的描述信息 用于Controller层注解** @param log     日志* @param operLog 操作日志* @throws Exception*/public void getControllerMethodDescription(JoinPoint joinPoint, Log log, OperLogEvent operLog, Object jsonResult) throws Exception {// 设置action动作operLog.setBusinessType(log.businessType().ordinal());// 设置标题operLog.setTitle(log.title());// 设置操作人类别operLog.setOperatorType(log.operatorType().ordinal());// 是否需要保存request,参数和值if (log.isSaveRequestData()) {// 获取参数的信息,传入到数据库中。setRequestValue(joinPoint, operLog, log.excludeParamNames());}// 是否需要保存response,参数和值if (log.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult)) {operLog.setJsonResult(StringUtils.substring(JsonUtils.toJsonString(jsonResult), 0, 2000));}}/*** 获取请求的参数,放到log中** @param operLog 操作日志* @throws Exception 异常*/private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception {Map<String, String> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());String requestMethod = operLog.getRequestMethod();if (MapUtil.isEmpty(paramsMap)&& HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);operLog.setOperParam(StringUtils.substring(params, 0, 2000));} else {MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES);MapUtil.removeAny(paramsMap, excludeParamNames);operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 2000));}}/*** 参数拼装*/private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) {StringJoiner params = new StringJoiner(" ");if (ArrayUtil.isEmpty(paramsArray)) {return params.toString();}for (Object o : paramsArray) {if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {String str = JsonUtils.toJsonString(o);Dict dict = JsonUtils.parseMap(str);if (MapUtil.isNotEmpty(dict)) {MapUtil.removeAny(dict, EXCLUDE_PROPERTIES);MapUtil.removeAny(dict, excludeParamNames);str = JsonUtils.toJsonString(dict);}params.add(str);}}return params.toString();}/*** 判断是否需要过滤的对象。** @param o 对象信息。* @return 如果是需要过滤的对象,则返回true;否则返回false。*/@SuppressWarnings("rawtypes")public boolean isFilterObject(final Object o) {Class<?> clazz = o.getClass();if (clazz.isArray()) {return clazz.getComponentType().isAssignableFrom(MultipartFile.class);} else if (Collection.class.isAssignableFrom(clazz)) {Collection collection = (Collection) o;for (Object value : collection) {return value instanceof MultipartFile;}} else if (Map.class.isAssignableFrom(clazz)) {Map map = (Map) o;for (Object value : map.values()) {return value instanceof MultipartFile;}}return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse|| o instanceof BindingResult;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/689953.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPF中样式

WPF中样式:类似于winform中控件的属性 <Grid><!-- Button属性 字体大小 字体颜色 内容 控件宽 高 --><Button FontSize="20" Foreground="Blue" Content="Hello" Width="100" Height="40"/></Grid&g…

proteus8.15图文安装教程

proteus8.15版本可以用STM32系列单片机来进行仿真设计&#xff0c;比7.8版本方便多了&#xff0c;有需要的朋友们可以在公众号后台回复 proteus8.15 获取软件包。 1、下载好软件包&#xff0c;解压如下&#xff0c;右键proteus8.15.sp1以管理员身份运行。 2、第一次安装&#x…

ALINX黑金AXU3EGB 开发板用户手册RS485通信接口图示DI RO信号方向标识错误说明

MAX3485这类RS485芯片&#xff0c;DI是TTL信号输入&#xff0c;RO是TTL信号输出 如下图是MAX3485手册规格书。 因此 ALINX黑金AXU3EGB 用户手册 Page 43页 图 3-11-1 PL 端 485 通信的连接示意图&#xff0c;MAX3485芯片的DI RO信号输入输出标识方向是错误的&#xff0c;应为蓝…

Redis 只会用缓存?16种妙用让同事直呼牛X

1、缓存2、数据共享分布式3、分布式锁4、全局ID5、计数器6、限流7、位统计8、购物车9、用户消息时间线timeline10、消息队列11、抽奖12、点赞、签到、打卡13、商品标签14、商品筛选15、用户关注、推荐模型16、排行榜图片 1、缓存 String类型 例如:热点数据缓存(例如报表、明…

机器学习---HMM前向、后向和维特比算法的计算

1. HMM import numpy as np# In[15]:class HiddenMarkov:def forward(self, Q, V, A, B, O, PI): # 使用前向算法N len(Q) # 状态序列的大小M len(O) # 观测序列的大小alphas np.zeros((N, M)) # alpha值T M # 有几个时刻&#xff0c;有几个观测序列&#xff0c;就有…

小米4A路由器如何刷OpenWRT并结合内网穿透实现公网远程访问

文章目录 推荐前言1. 安装Python和需要的库2. 使用 OpenWRTInvasion 破解路由器3. 备份当前分区并刷入新的Breed4. 安装cpolar内网穿透4.1 注册账号4.2 下载cpolar客户端4.3 登录cpolar web ui管理界面4.4 创建公网地址 5. 固定公网地址访问 推荐 前些天发现了一个巨牛的人工智…

红队学习笔记Day6 --->干货分享

今天看到这样的一个东西&#xff0c;好好好&#xff0c;有点恐怖&#x1f613;&#x1f613;&#x1f631;&#x1f631;&#x1f631;&#x1f631; 我就想网安是不是也有这种东西&#xff1f; 我来试试 icmp&#xff0c;RDP&#xff0c;arp&#xff0c;dhcp&#xff0c;nat&a…

Android 基础技术——Binder 机制

笔者希望做一个系列&#xff0c;整理 Android 基础技术&#xff0c;本章是关于Binder 机制 什么是Binder 机制&#xff1a;Binder 是一种进程间通信机制 驱动&#xff1a;Binder 是一个虚拟物理设备驱动 应用层&#xff1a;Binder 是一个能发起通信的 Java 类 为什么要使用Bind…

react封装通用Modal弹窗组件

目录 1、【src/component/modal/hoc.js】 2、【src/component/modal/componentModal.js】 3、【src/page/projectView.js】 【说明】&#xff1a;后台管理的项目中会经常遇到弹窗&#xff0c;于是封装了一个简单的公共弹窗组件 这个公共组件不适用复杂的功能&#xff0c;简单的…

20. 【Linux教程】emacs 编辑器

前面小节介绍了如何使用 vim 编辑器和 nano 编辑器&#xff0c;本小节介绍 emacs 编辑器&#xff0c;emacs 编辑器最开始是作为控制台的编辑器&#xff0c;并且 emacs 编辑器仍然提供最早的命令行模式。 1. 检查 Linux 系统中是否安装 emacs 编辑器 使用如何命令检查 emacs 编…

SpringIOC之support模块SimpleThreadScope

博主介绍:✌全网粉丝5W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验✌ 博主作品:《Java项目案例》主要基于SpringBoot+MyBatis/MyBatis-plus+…

PAM | 账户安全 | 管理

PAM PAM&#xff08;Pluggable Authentication Modules&#xff0c;可插入式身份验证模块&#xff09;是一个灵活的身份验证系统&#xff0c;允许我们通过配置和组合各种模块来实现不同的身份验证策略。 在 Linux 或类 Unix 系统中&#xff0c;常见的 PAM 模块包括以下几种类…

零基础搭建 Kubernetes 集群

零基础搭建 Kubernetes 集群 1、简介 在数字化时代&#xff0c;容器技术已经变成了软件开发和部署的标准&#xff0c;而在众多容器管理工具中&#xff0c;Kubernetes&#xff08;简称为 K8s&#xff09;凭借其高效的资源管理、弹性伸缩和自我修复的能力&#xff0c;成为了行业…

多线程、分布式运行用例

python多线程 threading模块 多线程实例 # -*- coding: utf-8 -*- # Time : 2024/2/7 15:50 # Author : 居里夫人吃橘子 # File : class01.py # Software: PyCharm import threading from time import sleepdef run(name):print(name 该起床了)sleep(2)print(name …

Linux CentOS系统安装SQL Server并结合内网穿透实现公网访问本地数据

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&…

Ubuntu在终端编辑完配置文件怎么保存退出?

1.退出&#xff0c;按【Ctrlx】&#xff0c;回车键。 2.保存&#xff0c;则先按【Ctrlo】&#xff0c;回车键&#xff0c;再按【Ctrlx】退出

小白水平理解面试经典题目LeetCode 1025 Divisor Game【动态规划】

1025 除数游戏 小艾 和 小鲍 轮流玩游戏&#xff0c;小艾首先开始。 最初&#xff0c;黑板上有一个数字 n 。在每个玩家的回合中&#xff0c;该玩家做出的动作包括&#xff1a; 选择任意 x&#xff0c;使 0 < x < n 和 n % x 0 。将黑板上的数字 n 替换为 n - x 。 此…

Dom节点继承树基本操作

遍历节点树 基于元素节点树的遍历 parcntElcrmcnt -> 返回当前元素的父元秦节点 (IE不兼容)children ->只返回当前元素的元素子节点node.childFlement(ount nodechildren.length当前元素节点的子元素(IE不兼容)firstElementChild->返回的是第一个元素节点(IE不兼容)l…

IDEA-常用插件

1、Mybatis Log Free 当我们使用mybatis log在控制台输出sql 内容&#xff0c;输出内容将语句与参数分开打印&#xff0c;还需要手动将参数替换到指定位置。 使用对应插件后&#xff0c;自动将输出内容组装成完整的可直接执行的SQL 在插件市场 查看对应名称&#xff0c;并安装。…

【数据结构】图的存储与遍历

图的概念 图是由顶点集合及顶点间的关系组成的一种数据结构&#xff1a;G (V&#xff0c; E) 图分为有向图和无向图 在有向图中&#xff0c;顶点对<x, y>是有序的&#xff0c;顶点对<x&#xff0c;y>称为顶点x到顶点y的一条边(弧)&#xff0c;<x, y>和&l…