MyBatis-Plus - 论 1 个实体类被 N 个DAO 类绑定,导致 MP 特性(逻辑删)失效的解决方案

问题描述

最近遇到一个奇奇怪怪的问题,发现 Mybatis-Plus『逻辑删』特性失效,而且是偶现,有时候可以,有时候又不行。于是开启了 Debug Mybatis-Plus 源码之旅

原因分析

  • 我们接下来重点关注 TableInfoHelper 类
/** Copyright (c) 2011-2020, baomidou (jobob@qq.com).* <p>* Licensed under the Apache License, Version 2.0 (the "License"); you may not* use this file except in compliance with the License. You may obtain a copy of* the License at* <p>* https://www.apache.org/licenses/LICENSE-2.0* <p>* Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the* License for the specific language governing permissions and limitations under* the License.*/
package com.baomidou.mybatisplus.core.metadata;import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
import com.baomidou.mybatisplus.core.toolkit.*;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.builder.StaticSqlSource;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.reflection.Reflector;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.session.Configuration;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static java.util.stream.Collectors.toList;/*** <p>* 实体类反射表辅助类* </p>** @author hubin sjy* @since 2016-09-09*/
public class TableInfoHelper {private static final Log logger = LogFactory.getLog(TableInfoHelper.class);/*** 储存反射类表信息*/private static final Map<Class<?>, TableInfo> TABLE_INFO_CACHE = new ConcurrentHashMap<>();/*** 默认表主键名称*/private static final String DEFAULT_ID_NAME = "id";/*** <p>* 获取实体映射表信息* </p>** @param clazz 反射实体类* @return 数据库表反射信息*/public static TableInfo getTableInfo(Class<?> clazz) {if (clazz == null|| ReflectionKit.isPrimitiveOrWrapper(clazz)|| clazz == String.class) {return null;}// https://github.com/baomidou/mybatis-plus/issues/299TableInfo tableInfo = TABLE_INFO_CACHE.get(ClassUtils.getUserClass(clazz));if (null != tableInfo) {return tableInfo;}//尝试获取父类缓存Class<?> currentClass = clazz;while (null == tableInfo && Object.class != currentClass) {currentClass = currentClass.getSuperclass();tableInfo = TABLE_INFO_CACHE.get(ClassUtils.getUserClass(currentClass));}if (tableInfo != null) {TABLE_INFO_CACHE.put(ClassUtils.getUserClass(clazz), tableInfo);}return tableInfo;}/*** <p>* 获取所有实体映射表信息* </p>** @return 数据库表反射信息集合*/@SuppressWarnings("unused")public static List<TableInfo> getTableInfos() {return new ArrayList<>(TABLE_INFO_CACHE.values());}/*** <p>* 实体类反射获取表信息【初始化】* </p>** @param clazz 反射实体类* @return 数据库表反射信息*/public synchronized static TableInfo initTableInfo(MapperBuilderAssistant builderAssistant, Class<?> clazz) {TableInfo tableInfo = TABLE_INFO_CACHE.get(clazz);if (tableInfo != null) {if (builderAssistant != null) {tableInfo.setConfiguration(builderAssistant.getConfiguration());}return tableInfo;}/* 没有获取到缓存信息,则初始化 */tableInfo = new TableInfo(clazz);GlobalConfig globalConfig;if (null != builderAssistant) {tableInfo.setCurrentNamespace(builderAssistant.getCurrentNamespace());tableInfo.setConfiguration(builderAssistant.getConfiguration());globalConfig = GlobalConfigUtils.getGlobalConfig(builderAssistant.getConfiguration());} else {// 兼容测试场景globalConfig = GlobalConfigUtils.defaults();}/* 初始化表名相关 */final String[] excludeProperty = initTableName(clazz, globalConfig, tableInfo);List<String> excludePropertyList = excludeProperty != null && excludeProperty.length > 0 ? Arrays.asList(excludeProperty) : Collections.emptyList();/* 初始化字段相关 */initTableFields(clazz, globalConfig, tableInfo, excludePropertyList);/* 放入缓存 */TABLE_INFO_CACHE.put(clazz, tableInfo);/* 缓存 lambda */LambdaUtils.installCache(tableInfo);/* 自动构建 resultMap */tableInfo.initResultMapIfNeed();return tableInfo;}/*** <p>* 初始化 表数据库类型,表名,resultMap* </p>** @param clazz        实体类* @param globalConfig 全局配置* @param tableInfo    数据库表反射信息* @return 需要排除的字段名*/private static String[] initTableName(Class<?> clazz, GlobalConfig globalConfig, TableInfo tableInfo) {/* 数据库全局配置 */GlobalConfig.DbConfig dbConfig = globalConfig.getDbConfig();TableName table = clazz.getAnnotation(TableName.class);String tableName = clazz.getSimpleName();String tablePrefix = dbConfig.getTablePrefix();String schema = dbConfig.getSchema();boolean tablePrefixEffect = true;String[] excludeProperty = null;if (table != null) {if (StringUtils.isNotBlank(table.value())) {tableName = table.value();if (StringUtils.isNotBlank(tablePrefix) && !table.keepGlobalPrefix()) {tablePrefixEffect = false;}} else {tableName = initTableNameWithDbConfig(tableName, dbConfig);}if (StringUtils.isNotBlank(table.schema())) {schema = table.schema();}/* 表结果集映射 */if (StringUtils.isNotBlank(table.resultMap())) {tableInfo.setResultMap(table.resultMap());}tableInfo.setAutoInitResultMap(table.autoResultMap());excludeProperty = table.excludeProperty();} else {tableName = initTableNameWithDbConfig(tableName, dbConfig);}String targetTableName = tableName;if (StringUtils.isNotBlank(tablePrefix) && tablePrefixEffect) {targetTableName = tablePrefix + targetTableName;}if (StringUtils.isNotBlank(schema)) {targetTableName = schema + StringPool.DOT + targetTableName;}tableInfo.setTableName(targetTableName);/* 开启了自定义 KEY 生成器 */if (null != dbConfig.getKeyGenerator()) {tableInfo.setKeySequence(clazz.getAnnotation(KeySequence.class));}return excludeProperty;}/*** 根据 DbConfig 初始化 表名** @param className 类名* @param dbConfig  DbConfig* @return 表名*/private static String initTableNameWithDbConfig(String className, GlobalConfig.DbConfig dbConfig) {String tableName = className;// 开启表名下划线申明if (dbConfig.isTableUnderline()) {tableName = StringUtils.camelToUnderline(tableName);}// 大写命名判断if (dbConfig.isCapitalMode()) {tableName = tableName.toUpperCase();} else {// 首字母小写tableName = StringUtils.firstToLowerCase(tableName);}return tableName;}/*** <p>* 初始化 表主键,表字段* </p>** @param clazz        实体类* @param globalConfig 全局配置* @param tableInfo    数据库表反射信息*/public static void initTableFields(Class<?> clazz, GlobalConfig globalConfig, TableInfo tableInfo, List<String> excludeProperty) {/* 数据库全局配置 */GlobalConfig.DbConfig dbConfig = globalConfig.getDbConfig();ReflectorFactory reflectorFactory = tableInfo.getConfiguration().getReflectorFactory();//TODO @咩咩 有空一起来撸完这反射模块.Reflector reflector = reflectorFactory.findForClass(clazz);List<Field> list = getAllFields(clazz);// 标记是否读取到主键boolean isReadPK = false;// 是否存在 @TableId 注解boolean existTableId = isExistTableId(list);List<TableFieldInfo> fieldList = new ArrayList<>(list.size());for (Field field : list) {if (excludeProperty.contains(field.getName())) {continue;}/* 主键ID 初始化 */if (existTableId) {TableId tableId = field.getAnnotation(TableId.class);if (tableId != null) {if (isReadPK) {throw ExceptionUtils.mpe("@TableId can't more than one in Class: \"%s\".", clazz.getName());} else {isReadPK = initTableIdWithAnnotation(dbConfig, tableInfo, field, tableId, reflector);continue;}}} else if (!isReadPK) {isReadPK = initTableIdWithoutAnnotation(dbConfig, tableInfo, field, reflector);if (isReadPK) {continue;}}/* 有 @TableField 注解的字段初始化 */if (initTableFieldWithAnnotation(dbConfig, tableInfo, fieldList, field)) {continue;}/* 无 @TableField 注解的字段初始化 */fieldList.add(new TableFieldInfo(dbConfig, tableInfo, field));}/* 检查逻辑删除字段只能有最多一个 */Assert.isTrue(fieldList.parallelStream().filter(TableFieldInfo::isLogicDelete).count() < 2L,String.format("@TableLogic can't more than one in Class: \"%s\".", clazz.getName()));/* 字段列表,不可变集合 */tableInfo.setFieldList(Collections.unmodifiableList(fieldList));/* 未发现主键注解,提示警告信息 */if (!isReadPK) {logger.warn(String.format("Can not find table primary key in Class: \"%s\".", clazz.getName()));}}/*** <p>* 判断主键注解是否存在* </p>** @param list 字段列表* @return true 为存在 @TableId 注解;*/public static boolean isExistTableId(List<Field> list) {return list.stream().anyMatch(field -> field.isAnnotationPresent(TableId.class));}/*** <p>* 主键属性初始化* </p>** @param dbConfig  全局配置信息* @param tableInfo 表信息* @param field     字段* @param tableId   注解* @param reflector Reflector*/private static boolean initTableIdWithAnnotation(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo,Field field, TableId tableId, Reflector reflector) {boolean underCamel = tableInfo.isUnderCamel();final String property = field.getName();if (field.getAnnotation(TableField.class) != null) {logger.warn(String.format("This \"%s\" is the table primary key by @TableId annotation in Class: \"%s\",So @TableField annotation will not work!",property, tableInfo.getEntityType().getName()));}/* 主键策略( 注解 > 全局 ) */// 设置 Sequence 其他策略无效if (IdType.NONE == tableId.type()) {tableInfo.setIdType(dbConfig.getIdType());} else {tableInfo.setIdType(tableId.type());}/* 字段 */String column = property;if (StringUtils.isNotBlank(tableId.value())) {column = tableId.value();} else {// 开启字段下划线申明if (underCamel) {column = StringUtils.camelToUnderline(column);}// 全局大写命名if (dbConfig.isCapitalMode()) {column = column.toUpperCase();}}tableInfo.setKeyRelated(checkRelated(underCamel, property, column)).setKeyColumn(column).setKeyProperty(property).setKeyType(reflector.getGetterType(property));return true;}/*** <p>* 主键属性初始化* </p>** @param tableInfo 表信息* @param field     字段* @param reflector Reflector* @return true 继续下一个属性判断,返回 continue;*/private static boolean initTableIdWithoutAnnotation(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo,Field field, Reflector reflector) {final String property = field.getName();if (DEFAULT_ID_NAME.equalsIgnoreCase(property)) {if (field.getAnnotation(TableField.class) != null) {logger.warn(String.format("This \"%s\" is the table primary key by default name for `id` in Class: \"%s\",So @TableField will not work!",property, tableInfo.getEntityType().getName()));}String column = property;if (dbConfig.isCapitalMode()) {column = column.toUpperCase();}tableInfo.setKeyRelated(checkRelated(tableInfo.isUnderCamel(), property, column)).setIdType(dbConfig.getIdType()).setKeyColumn(column).setKeyProperty(property).setKeyType(reflector.getGetterType(property));return true;}return false;}/*** <p>* 字段属性初始化* </p>** @param dbConfig  数据库全局配置* @param tableInfo 表信息* @param fieldList 字段列表* @return true 继续下一个属性判断,返回 continue;*/private static boolean initTableFieldWithAnnotation(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo,List<TableFieldInfo> fieldList, Field field) {/* 获取注解属性,自定义字段 */TableField tableField = field.getAnnotation(TableField.class);if (null == tableField) {return false;}fieldList.add(new TableFieldInfo(dbConfig, tableInfo, field, tableField));return true;}/*** <p>* 判定 related 的值* </p>** @param underCamel 驼峰命名* @param property   属性名* @param column     字段名* @return related*/public static boolean checkRelated(boolean underCamel, String property, String column) {if (StringUtils.isNotColumnName(column)) {// 首尾有转义符,手动在注解里设置了转义符,去除掉转义符column = column.substring(1, column.length() - 1);}String propertyUpper = property.toUpperCase(Locale.ENGLISH);String columnUpper = column.toUpperCase(Locale.ENGLISH);if (underCamel) {// 开启了驼峰并且 column 包含下划线return !(propertyUpper.equals(columnUpper) ||propertyUpper.equals(columnUpper.replace(StringPool.UNDERSCORE, StringPool.EMPTY)));} else {// 未开启驼峰,直接判断 property 是否与 column 相同(全大写)return !propertyUpper.equals(columnUpper);}}/*** <p>* 获取该类的所有属性列表* </p>** @param clazz 反射类* @return 属性集合*/public static List<Field> getAllFields(Class<?> clazz) {List<Field> fieldList = ReflectionKit.getFieldList(ClassUtils.getUserClass(clazz));return fieldList.stream().filter(field -> {/* 过滤注解非表字段属性 */TableField tableField = field.getAnnotation(TableField.class);return (tableField == null || tableField.exist());}).collect(toList());}public static KeyGenerator genKeyGenerator(String baseStatementId, TableInfo tableInfo, MapperBuilderAssistant builderAssistant) {IKeyGenerator keyGenerator = GlobalConfigUtils.getKeyGenerator(builderAssistant.getConfiguration());if (null == keyGenerator) {throw new IllegalArgumentException("not configure IKeyGenerator implementation class.");}Configuration configuration = builderAssistant.getConfiguration();//TODO 这里不加上builderAssistant.getCurrentNamespace()的会导致com.baomidou.mybatisplus.core.parser.SqlParserHelper.getSqlParserInfo越(chu)界(gui)String id = builderAssistant.getCurrentNamespace() + StringPool.DOT + baseStatementId + SelectKeyGenerator.SELECT_KEY_SUFFIX;ResultMap resultMap = new ResultMap.Builder(builderAssistant.getConfiguration(), id, tableInfo.getKeyType(), new ArrayList<>()).build();MappedStatement mappedStatement = new MappedStatement.Builder(builderAssistant.getConfiguration(), id,new StaticSqlSource(configuration, keyGenerator.executeSql(tableInfo.getKeySequence().value())), SqlCommandType.SELECT).keyProperty(tableInfo.getKeyProperty()).resultMaps(Collections.singletonList(resultMap)).build();configuration.addMappedStatement(mappedStatement);return new SelectKeyGenerator(mappedStatement, true);}
}
  • 注意这里的 initTableInfo 方法,这里面是所有 MapperScan 扫码 DAO 类时候会初始化的必经之路,不过出问题的根本也就是在这个方法里
/*** <p>* 实体类反射获取表信息【初始化】* </p>** @param clazz 反射实体类* @return 数据库表反射信息*/
public synchronized static TableInfo initTableInfo(MapperBuilderAssistant builderAssistant, Class<?> clazz) {TableInfo tableInfo = TABLE_INFO_CACHE.get(clazz);if (tableInfo != null) {if (builderAssistant != null) {tableInfo.setConfiguration(builderAssistant.getConfiguration());}return tableInfo;}/* 没有获取到缓存信息,则初始化 */tableInfo = new TableInfo(clazz);GlobalConfig globalConfig;if (null != builderAssistant) {tableInfo.setCurrentNamespace(builderAssistant.getCurrentNamespace());tableInfo.setConfiguration(builderAssistant.getConfiguration());globalConfig = GlobalConfigUtils.getGlobalConfig(builderAssistant.getConfiguration());} else {// 兼容测试场景globalConfig = GlobalConfigUtils.defaults();}/* 初始化表名相关 */final String[] excludeProperty = initTableName(clazz, globalConfig, tableInfo);List<String> excludePropertyList = excludeProperty != null && excludeProperty.length > 0 ? Arrays.asList(excludeProperty) : Collections.emptyList();/* 初始化字段相关 */initTableFields(clazz, globalConfig, tableInfo, excludePropertyList);/* 放入缓存 */TABLE_INFO_CACHE.put(clazz, tableInfo);/* 缓存 lambda */LambdaUtils.installCache(tableInfo);/* 自动构建 resultMap */tableInfo.initResultMapIfNeed();return tableInfo;
}
  • 我把关键核心代码显示出来,其他忽略掉先,单单看下面代码意味着什么呢?
  • 简单理解:TABLE_INFO_CACHE 集合存放实体类和DAO类的映射关系,KV结构(K - 实体类全限定名,V - DAO 类绑定数据源的相关信息)
  • 如果按照这个理解,那显而易见,如果说有 1 个实体类,被多个 DAO 绑定的话,那一定会被扫到初始化时,后来者会覆盖前者,这样就导致了只有后者的 DAO 拥有 MP 特性,前者就会失去一些 MP 特性,但是经测试基本的 MyBatis 特性有些具备,反正就会功能不完整
private static final Map<Class<?>, TableInfo> TABLE_INFO_CACHE = new ConcurrentHashMap<>();public synchronized static TableInfo initTableInfo(MapperBuilderAssistant builderAssistant, Class<?> clazz) {TableInfo tableInfo = TABLE_INFO_CACHE.get(clazz);if (tableInfo != null) {if (builderAssistant != null) {tableInfo.setConfiguration(builderAssistant.getConfiguration());}return tableInfo;}/* 没有获取到缓存信息,则初始化 */// .../* 放入缓存 */TABLE_INFO_CACHE.put(clazz, tableInfo);// ...return tableInfo;
}

解决方案

  1. 方法一:把实体类复制出来换个名字,重新给另一个DAO绑定上即可
  2. 方法二:抽出公共实体类和DAO,这样多处使用的时候可以共享

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

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

相关文章

算法:两数之和(暴力解法和优化算法)

暴力解法&#xff1a;使用快慢指针解决&#xff0c;时间复杂度 O(n^2)&#xff0c;空间复杂度 O(n) /*** param {number[]} nums* param {number} target* return {number[]}*/ var twoSum function(nums, target) {let slow 0let fast 1// 如果慢指针没有超过nums边界就继…

代理IP怎么使用?Mac苹果系统设置http代理IP教程

代理IP是一种通过将请求转发到另一个服务器&#xff0c;以隐藏自己的真实IP地址的服务器。使用代理IP可以保护您的隐私和安全&#xff0c;防止被跟踪或被攻击。在本文中&#xff0c;我们将介绍如何在Mac苹果系统上设置http代理IP教程。 一、了解代理IP 代理IP地址是一种可以用来…

基于Java二手房交易管理系统

基于Java二手房交易管理系统 功能需求 1、房源信息管理&#xff1a;系统需要能够记录和管理所有房源的详细信息&#xff0c;包括房屋地址、房屋面积、售价、房屋类型等。管理员和房东可以添加、编辑和删除房源信息。 2、买家信息管理&#xff1a;系统需要能够记录和管理所有…

2023.12.9 关于 Spring Boot 事务传播机制详解

目录 事务传播机制 七大事务传播机制 支持当前调用链上的事务 Propagation.REQUIRED Propagation.SUPPORTS Propagation.MANDATORY 不支持当前调用链上的事务 Propagation.REQUIRES_NEW Propagation.NOT_SUPPORTED Propagation.NEVER 嵌套事务 Propagation.NESTED…

蜂窝、无线设备应用 HXG-242+、PVGA-123+、PMA-5452+、PSA-39+、PSA-14+射频放大器(IC器件)

1、HXG-242 射频放大器 IC 无线 LAN&#xff0c;LTE 700MHz 至 2.4GHz&#xff0c;6-SMD 模块 HXG-242&#xff08;符合RoHS规范&#xff09;是一款先进的放大器模块&#xff0c;结合了高动态范围MMIC技术和优化电路&#xff0c;可在聚焦频率范围内提供业界领先的线性度。它采…

创建并测试第一个django项目并解决过程中遇到的问题

Django 是一个高级 Python Web 框架&#xff0c;它鼓励快速开发和简洁、实用的设计。它由经验丰富的开发人员构建&#xff0c;解决了 Web 开发的大部分麻烦&#xff0c;因此您可以专注于编写应用程序&#xff0c;而无需重新发明轮子。它是免费和开源的。 目录 一、django项目 …

Nginx 简单入门操作

前言:之前的文章有些过就不罗嗦了。 Nginx 基础内容 是什么? Nginx 是一个轻量级的 HTTP 服务器,采用事件驱动、异步非阻塞处理方式的服务器,它具有极好的 IO 性能,常用于 HTTP服务器(包含动静分离)、正向代理、反向代理、负载均衡 等等. Nginx 和 Node.js 在很多方…

pdb 调试 python 代码

pdb python的官方调试工具; 默认下载的模块 参考文档 pdbpdb有官方文档, 也有源码, 可能阅读python源码更容易理解; 和gdb非常相似&#xff0c;也支持扩展; 基于bdb,cmd拓展; 代码中设置调试点(一次性调试) 好处是可以源码级别的调试, 对于刚了解pdb又想调试子进程的比较…

大语言模型有什么意义?亚马逊训练自己的大语言模型有什么用?

近年来&#xff0c;大语言模型的崭露头角引起了广泛的关注&#xff0c;成为科技领域的一项重要突破。而在这个领域的巅峰之上&#xff0c;亚马逊云科技一直致力于推动人工智能的发展。那么&#xff0c;作为一家全球科技巨头&#xff0c;亚马逊为何会如此注重大语言模型的研发与…

解读 | GPT-4突然“变赖“ 是莫名其妙还是另有玄机

大家好&#xff0c;我是极智视界&#xff0c;欢迎关注我的公众号&#xff0c;获取我的更多前沿科技分享 邀您加入我的知识星球「极智视界」&#xff0c;星球内有超多好玩的项目实战源码和资源下载&#xff0c;链接&#xff1a;https://t.zsxq.com/0aiNxERDq 事情是这样的&#…

初学websocket有感-待研究

https://www.bilibili.com/video/BV1KN411n7WD/ 看到一半的时候就会想到以下的问题&#xff1a; 初学websocket有感-待研究 既然每一个endPoint都是对应着一个服务器和客户端浏览器的连接对象&#xff0c;那么就是说要创建很多个endPoint对象咯。 一、是否回将创建的这么多…

项目经理和产品经理哪个更有发展前景?

如果是单看“钱途”的话&#xff0c;如果是在传统行业&#xff0c;可能差不多&#xff1b;如果是在IT行业的话&#xff0c;可能更需要项目经理&#xff1b;互联网行业的话&#xff0c;可能更需要产品经理。 项目经理跟产品经理两个证都挺受市场欢迎的&#xff0c;两个岗位职责…

关东升老师Python著作推荐(由电子工业出版社出版)

前言&#xff1a;关东升老师简单介绍 一个在IT领域摸爬滚打20多年的老程序员、软件架构师、高级培训讲师、IT作家。熟悉Java、Kotlin、Python、iOS、Android、游戏开发、数据库开发与设计、软件架构设计等多种IT技术。参与设计和开发北京市公交一卡通百亿级大型项目&#xff0c…

钓鱼网站域名识别工具dnstwist算法研究

先上一个AI的回答&#xff1a; dnstwist是一种钓鱼网站域名识别工具&#xff0c;可帮助用户识别和检测可能被恶意使用的域名。它通过生成类似的域名变体来模拟攻击者可能使用的钓鱼域名&#xff0c;并提供了一系列有用的功能和信息。 dnstwist能够生成一组类似的域名变体&…

HTML常见的列表标签

目录 &#x1f367;无序列表&#x1f367;有序列表&#x1f367; 定义列表&#x1f367; 菜单列表 &#x1f367;无序列表 ulli的组合,ul标签与li标签之间尽量不要写标签或内容 列表可以嵌套多层 type属性&#xff0c;可以指定序号的类型 可选值&#xff1a;默认值&#xff0c;…

15:00面试,15:06就出来了,问的问题太变态了。。

刚从小厂出来&#xff0c;没想到在另一家公司我又寄了。 在这家公司上班&#xff0c;每天都要加班&#xff0c;但看在钱给的比较多的份上&#xff0c;也就不太计较了。但万万没想到5月一纸通知&#xff0c;所有人不准加班了&#xff0c;不仅加班费没有了&#xff0c;薪资还要降…

有病但合理的 ChatGPT 提示语

ChatGPT 面世一年多了&#xff0c;如何让大模型输出高质量内容&#xff0c;让提示词工程成了一门重要的学科。以下是一些有病但合理的提示词技巧&#xff0c;大部分经过论文证明&#xff0c;有效提高 ChatGPT 输出质量&#xff1a; ​1️⃣ Take a deep breath. 深呼吸 ✨ 作用…

ChatGPT胜过我们人类吗?

引言 人工智能&#xff08;AI&#xff09;一直是众多技术进步背后的驱动力&#xff0c;推动我们走向曾经是科幻小说领域的未来。这些进步的核心引出这样一个深刻的问题&#xff1a;机器能思考吗&#xff1f;这一问题由英国数学家和计算机科学家艾伦图灵&#xff08;Alan Turin…

SSL安全证书怎么查看证书类型?

SSL安全证书是一种用于确保互联网通信安全的协议。它通过加密数据传输以保护敏感信息不被窃取或篡改。在浏览器中&#xff0c;我们可以轻松查看SSL安全证书的类型。本文将详细介绍如何查看证书类型&#xff0c;并探讨不同类型的SSL证书的用途和特点。 要查看SSL安全证书的类型&…

关于粒子群算法的一些简单尝试

粒子群算法核心思想&#xff1a;&#xff08;鸟 粒子&#xff09; &#xff08;1&#xff09;许多的鸟站在不同的地方&#xff1b; &#xff08;2&#xff09;每一只鸟都有自己寻找食物的初始飞行方向、飞行速度&#xff1b; &#xff08;3&#xff09;这些鸟儿每隔一段时间…