【存儲中間件API】MySQL、Redis、MongoDB、ES常見api操作及性能比較

常見中間件api操作及性能比較

  • ?? MySQL crud操作
    • ?? maven依賴
    • ?? 配置
    • ?? 定義實體類
    • ?? 常用api
  • ?? Redis crud操作
    • ?? maven依賴
    • ?? 配置
    • ?? 常用api
  • ?? MongoDB crud操作
    • ?? maven依賴
    • ?? 配置文件
    • ?? 定義實體類
    • ?? MongoDB常用api
  • ?? ES crud操作 ??????
    • ?? 前期準備
    • ?? maven依賴
      • ?? tips
    • ?? 配置文件
    • ?? 定義實體類
    • ?? ES常用api
  • ?? 性能比較
    • ?? 模擬創建數據接口
    • ?? 查詢數據接口

本文匯總常見中間件的api操作及性能對比,主要涉及MySQL、Redis、Mongo、Es,這篇文章默認已經安裝配置好相應的中間件

關于MongoDB的安裝配置可參考文章:《【MongoDB】一問帶你深入理解什么是MongDB,MongoDB超超詳細保姆級教程》

Es安裝配置可參考:《【ELK】window下ELK的安裝與部署》

?? MySQL crud操作

mysql是目前最常用的關系型數據庫,網上有很多資料,這里大致簡單過一下主流的Mybatis-Plus用法,不展開細說

?? maven依賴

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId>
</dependency>
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId>
</dependency><!--添加 Alibaba 數據源-->
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.20</version>
</dependency>
<!--訪問mysql-->
<!--JDBC-->
<!-- MySql 5.5 Connector -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.24</version>
</dependency>

?? 配置

ip、port、數據庫名稱,賬戶密碼換成自己的

spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/csdn?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimeZone=GMT+8username: rootpassword: 123456

?? 定義實體類

實體類中,@Data、@EqualsAndHashCode、@Accessorslombok注解,@Data自動生成實體類的Getter、Setter、無參構造、有參構造等,@EqualsAndHashCode生成自動生成 equalshashCode 方法,@Accessors主要作用是支持鏈式調用,@TableName是MP注解,用于映射表名

@Data
@EqualsAndHashCode
@Accessors(chain = true)
@TableName("t_store_product")
public class StoreProduct implements Serializable {private static final long serialVersionUID = 1L;@TableId(value = "id", type = IdType.AUTO)private Integer id;private String image;private String sliderImage;private String storeName;private String storeInfo;private String keyword;private String cateId;private String unitName;private Integer sort;private Boolean isHot;private Boolean isBenefit;private Boolean isBest;private Boolean isNew;private Boolean isGood;private Integer giveIntegral;private Boolean isSub;private Integer ficti;private Integer tempId;private Boolean specType;private String activity;private String attr;private String attrValue;private String content;private String couponIds;private String flatPattern;
}

?? 常用api

見文件TestMySQL.java

@Slf4j
@SpringBootTest
public class TestMySQL {@Resourceprivate StoreProductMapper storeProductMapper;/*** @param num 生成num條模擬數據* @return*/private static List<StoreProduct> getStoreProduct(Integer num) {List<StoreProduct> result = new ArrayList<>();StoreProduct storeProduct = new StoreProduct();for (int i = 0; i < num; i++) {storeProduct.setId(999 + i).setImage("https://www.baidu.com/img/bd_logo1.png").setSliderImage("https://www.baidu.com/img/bd_logo1.png").setStoreName("測試商品" + i).setStoreInfo("測試商品").setKeyword("測試商品").setCateId("1").setUnitName("件").setSort(1).setIsHot(true).setIsBenefit(true).setIsBest(true).setIsNew(true).setIsGood(true).setGiveIntegral(1).setIsSub(true).setFicti(1).setTempId(1).setSpecType(true).setActivity("{\"test\":\"test\"}").setAttr("{\"test\":\"test\"}").setAttrValue("{\"test\":\"test\"}").setContent("{\"test\":\"test\"}").setCouponIds("{\"test\":\"test\"}").setFlatPattern("{\"test\":\"test\"}");result.add(storeProduct);}return result;}/*** 插入單條數據*/@Testvoid test_insert() {StoreProduct storeProduct = getStoreProduct(1).get(0);storeProductMapper.insert(storeProduct);}/*** 按照id刪除*/@Testvoid test_deleteById() {storeProductMapper.deleteById(999);}/*** 多個條件刪除*/@Testvoid test_deleteByMap() {Map<String, Object> columnMap = new HashMap<>();// 添加多個條件columnMap.put("id", 999);columnMap.put("store_name", "測試商品");columnMap.put("is_hot", true);storeProductMapper.deleteByMap(columnMap);}/*** 構建wrapper語句刪除*/@Testvoid test_deleteByWrapper() {// 創建 QueryWrapper 對象QueryWrapper<StoreProduct> queryWrapper = new QueryWrapper<>();// 添加刪除條件,例如刪除 id 為 "999" 的記錄,并且storeName 為 "測試商品" 的記錄queryWrapper.eq("id", 999);storeProductMapper.delete(queryWrapper);}/*** 構建wrapper語句刪除*/@Testvoid test_deleteByLambdaWrapper() {// 創建 LambdaQueryWrapper 對象LambdaQueryWrapper<StoreProduct> queryWrapper = new LambdaQueryWrapper<>();// 添加刪除條件,例如刪除 id 為 "999" 的記錄,并且storeName 為 "測試商品" 的記錄queryWrapper.eq(StoreProduct::getId, 999);storeProductMapper.delete(queryWrapper);}/*** 批量刪除*/@Testvoid test_deleteBatchIds() {storeProductMapper.deleteBatchIds(Arrays.asList(999, 1000));}/*** 更新數據*/@Testvoid test_updateById() {StoreProduct storeProduct = getStoreProduct(1).get(0);storeProduct.setStoreName("商品名字更新啦~");storeProductMapper.updateById(storeProduct);}/*** 構建wrapper語句更新*/@Testvoid test_updateByWrapper() {// 創建 UpdateWrapper 對象UpdateWrapper<StoreProduct> queryWrapper = new UpdateWrapper<>();// 添加更新條件,例如更新 id 為 "999"queryWrapper.eq("id", 999);queryWrapper.set("store_name", "商品名字再次更新啦~");storeProductMapper.update(null, queryWrapper);}/*** 構建LambdaWrapper語句更新*/@Testvoid test_updateByLambdaWrapper() {// 創建 UpdateWrapper 對象LambdaUpdateWrapper<StoreProduct> queryWrapper = new LambdaUpdateWrapper<>();// 添加更新條件,例如更新 id 為 "999"queryWrapper.eq(StoreProduct::getId, 999);queryWrapper.set(StoreProduct::getStoreName, "商品名字再再次更新啦~");storeProductMapper.update(null, queryWrapper);}/*** 通過id查找*/@Testvoid test_selectById() {StoreProduct storeProduct = storeProductMapper.selectById(999);log.info("查詢結果:{}", storeProduct);}/*** 通過id集合查找*/@Testvoid test_selectBatchIds() {List<StoreProduct> storeProducts = storeProductMapper.selectBatchIds(Arrays.asList(1, 2));for (StoreProduct storeProduct : storeProducts) {log.info("查詢結果:{}", storeProduct);}}/*** 通過map查找*/@Testvoid test_selectByMap() {Map<String, Object> columnMap = new HashMap<>();// 添加多個條件columnMap.put("store_info", "測試商品");columnMap.put("is_hot", true);List<StoreProduct> storeProducts = storeProductMapper.selectByMap(columnMap);for (StoreProduct storeProduct : storeProducts) {log.info("查詢結果:{}", storeProduct);}}/*** 根據條件查一個** 注意,如果有多個滿足條件的數據,代碼會報錯:One record is expected, but the query result is multiple records*/@Testvoid test_selectOne() {QueryWrapper<StoreProduct> queryWrapper = new QueryWrapper<>();queryWrapper.eq("id", 999);StoreProduct storeProduct = storeProductMapper.selectOne(queryWrapper);log.info("查詢結果:{}", storeProduct);}/*** 按照條件查詢count總數*/@Testvoid test_selectCount() {QueryWrapper<StoreProduct> queryWrapper = new QueryWrapper<>();queryWrapper.eq("store_name", "新款智能手機");Long count = storeProductMapper.selectCount(queryWrapper);log.info("查詢結果有:{} 條", count);}/*** 列表查詢*/@Testvoid test_selectList() {QueryWrapper<StoreProduct> queryWrapper = new QueryWrapper<>();queryWrapper.eq("store_name", "新款智能手機");List<StoreProduct> storeProducts = storeProductMapper.selectList(queryWrapper);for (StoreProduct storeProduct : storeProducts) {log.info("查詢結果:{}", storeProduct);}}/*** 查詢結果為map*/@Testvoid test_selectMaps() {QueryWrapper<StoreProduct> queryWrapper = new QueryWrapper<>();queryWrapper.eq("store_info", "測試商品");List<Map<String, Object>> maps = storeProductMapper.selectMaps(queryWrapper);for (Map<String, Object> map : maps) {log.info("查詢結果:{}", map);}}/*** 分頁查詢*/@Testvoid test_selectPage() {// 創建分頁對象,指定當前頁碼和每頁記錄數LambdaQueryWrapper<StoreProduct> lqw = new LambdaQueryWrapper<>();lqw.eq(StoreProduct::getStoreName, "新款智能手機");Page<StoreProduct> page = new Page<>(1, 10);// 調用 selectPage 方法進行分頁查詢IPage<StoreProduct> resultPage = storeProductMapper.selectPage(page, lqw);log.info("當前頁碼:{},每頁記錄數:{},總頁數:{},總記錄數:{}", resultPage.getCurrent(), resultPage.getSize(),resultPage.getPages(), resultPage.getTotal());for (StoreProduct storeProduct : resultPage.getRecords()) {log.info("查詢結果:{}", storeProduct);}}
}

代碼中構建模擬數據方法getStoreProduct()中用到了鏈式構建,Wrapper構建既能用普通Wrapper,也能用LambdaWrapper,例如查詢中的QueryWrapper()或者是LambdaQueryWrapper()test_selectOne如果查詢存在多個值,會拋出異常One record is expected, but the query result is multiple records,源碼還是非常簡單,如下:

在這里插入圖片描述

?? Redis crud操作

Redis是常見的緩存中間件,接下來看看redis的一些常見操作

?? maven依賴

<!-- Spring Boot Redis 依賴 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>2.2.0.RELEASE</version>
</dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.1.0</version>
</dependency>

?? 配置

ip、port、database,密碼換成自己的

spring:redis:host: 127.0.0.1 #地址port: 6379 #端口password:timeout: 30000 # 連接超時時間(毫秒)database: 15  #默認數據庫jedis:pool:max-active: 200 # 連接池最大連接數(使用負值表示沒有限制)max-wait: -1 # 連接池最大阻塞等待時間(使用負值表示沒有限制)max-idle: 10 # 連接池中的最大空閑連接min-idle: 0 # 連接池中的最小空閑連接time-between-eviction-runs: -1 #逐出掃描的時間間隔(毫秒) 如果為負數,則不運行逐出線程, 默認-1

?? 常用api

TestRedis.java

@Slf4j
@SpringBootTest
public class TestRedis {@Resource(name = "stringRedisTemplate")private StringRedisTemplate stringRedisTemplate;/*** 測試設置單個鍵值對*/@Testvoid testSetValue() {stringRedisTemplate.opsForValue().set("testKey", "testValue");String value = stringRedisTemplate.opsForValue().get("testKey");log.info("設置并獲取單個鍵值對,值為: {}", value);}/*** 測試設置帶有過期時間的鍵值對  10秒過期*/@Testvoid testSetValueWithExpiration() {stringRedisTemplate.opsForValue().set("expiringKey", "expiringValue", 10, TimeUnit.SECONDS);String value = stringRedisTemplate.opsForValue().get("expiringKey");log.info("設置帶有過期時間的鍵值對,值為: {}", value);try {Thread.sleep(10000);} catch (InterruptedException e) {throw new RuntimeException(e);}value = stringRedisTemplate.opsForValue().get("expiringKey");log.info("過期時間已到,鍵值對已過期,值為: {}", value);}/*** 測試獲取單個鍵的值*/@Testvoid testGetValue() {stringRedisTemplate.opsForValue().set("existingKey", "existingValue");String value = stringRedisTemplate.opsForValue().get("existingKey");log.info("獲取單個鍵的值,值為: {}", value);}/*** 測試刪除單個鍵*/@Testvoid testDeleteKey() {stringRedisTemplate.opsForValue().set("toDeleteKey", "toDeleteValue");Boolean result = stringRedisTemplate.delete("toDeleteKey");log.info("刪除單個鍵,結果: {}", result);}/*** 測試批量刪除鍵*/@Testvoid testDeleteKeys() {stringRedisTemplate.opsForValue().set("key1", "value1");stringRedisTemplate.opsForValue().set("key2", "value2");Long deletedCount = stringRedisTemplate.delete(Arrays.asList("key1", "key2"));log.info("批量刪除鍵,刪除數量: {}", deletedCount);}/*** 測試設置哈希表*/@Testvoid testSetHash() {Map<String, String> hash = new HashMap<>();hash.put("field1", "value1");hash.put("field2", "value2");stringRedisTemplate.opsForHash().putAll("testHash", hash);Map<Object, Object> result = stringRedisTemplate.opsForHash().entries("testHash");log.info("設置哈希表,結果: {}", result);}/*** 測試獲取哈希表中的單個字段值*/@Testvoid testGetHashField() {stringRedisTemplate.opsForHash().put("testHash", "field1", "value1");Object value = stringRedisTemplate.opsForHash().get("testHash", "field1");log.info("獲取哈希表中的單個字段值,值為: {}", value);}/*** 測試獲取哈希表的所有字段和值*/@Testvoid testGetAllHashFields() {Map<String, String> hash = new HashMap<>();hash.put("field1", "value1");hash.put("field2", "value2");stringRedisTemplate.opsForHash().putAll("testHash", hash);Map<Object, Object> result = stringRedisTemplate.opsForHash().entries("testHash");log.info("獲取哈希表的所有字段和值,結果: {}", result);}/*** 測試向列表左側插入元素*/@Testvoid testLeftPushToList() {stringRedisTemplate.opsForList().leftPush("testList", "element1");stringRedisTemplate.opsForList().leftPush("testList", "element2");List<String> list = stringRedisTemplate.opsForList().range("testList", 0, -1);log.info("向列表左側插入元素,列表內容: {}", list);}/*** 測試從列表右側彈出元素*/@Testvoid testRightPopFromList() {stringRedisTemplate.opsForList().leftPush("testList", "element1");stringRedisTemplate.opsForList().leftPush("testList", "element2");String poppedElement = stringRedisTemplate.opsForList().rightPop("testList");log.info("從列表右側彈出元素,彈出元素: {}", poppedElement);}/*** 測試向集合中添加元素*/@Testvoid testAddToSet() {stringRedisTemplate.opsForSet().add("testSet", "element1", "element2");Set<String> set = stringRedisTemplate.opsForSet().members("testSet");log.info("向集合中添加元素,集合內容: {}", set);}/*** 測試從集合中移除元素*/@Testvoid testRemoveFromSet() {stringRedisTemplate.opsForSet().add("testSet", "element1", "element2");Long removedCount = stringRedisTemplate.opsForSet().remove("testSet", "element1");log.info("從集合中移除元素,移除數量: {}", removedCount);}/*** 測試向有序集合中添加元素*/@Testvoid testAddToZSet() {stringRedisTemplate.opsForZSet().add("testZSet", "element1", 1.0);stringRedisTemplate.opsForZSet().add("testZSet", "element2", 2.0);Set<String> zSet = stringRedisTemplate.opsForZSet().range("testZSet", 0, -1);log.info("向有序集合中添加元素,有序集合內容: {}", zSet);}/*** 測試從有序集合中移除元素*/@Testvoid testRemoveFromZSet() {stringRedisTemplate.opsForZSet().add("testZSet", "element1", 1.0);stringRedisTemplate.opsForZSet().add("testZSet", "element2", 2.0);Long removedCount = stringRedisTemplate.opsForZSet().remove("testZSet", "element1");log.info("從有序集合中移除元素,移除數量: {}", removedCount);}
}

運行結果:

在這里插入圖片描述

?? MongoDB crud操作

MongoDB是目前常用的高性能的分布式文件存儲方案,下面看看他的api實現

?? maven依賴

<!-- mongodb連接驅動 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

?? 配置文件

我這里圖省事,直接在config中寫死了mongodb://127.0.0.1:27017/csdn,可配置在yml文件中讀取

@Configuration
public class MongoConfig {@Beanpublic MongoDatabaseFactory mongoDatabaseFactory() {String connectionString = "mongodb://127.0.0.1:27017/csdn";return new SimpleMongoClientDatabaseFactory(connectionString);}@Bean(name = "mongoTemplate")public MongoTemplate mongoTemplate() {return new MongoTemplate(mongoDatabaseFactory());}
}

?? 定義實體類

代碼中,@Data還是lombok注解,和mysql一樣,@Document注解可以理解成映射行

如下圖中:
在這里插入圖片描述

圖中的Mongo的集合(Collection)類比MySQL中的表名,Document類比表中的一行

那為什么一行在navicat中顯示有那么多條數據呢?其實Mongo底層是BSON(Binary JSON)二進制存儲格式,每個Document下面是一個大的json文件,樣例如下:

{"_id": "order123","orderDate": "2025-02-18","customer": {"customerId": "cust456","name": "John Doe","email": "john.doe@example.com"},"items": [{"productId": "prod789","productName": "Smartphone","quantity": 2,"price": 500},{"productId": "prod012","productName": "Headphones","quantity": 1,"price": 100}]
}

@Id注解可以理解成主鍵,一個對象中只能有一個,可以生動賦值,也可以用默認值,默認值按照ObjectId來取值,包含了時間戳、機器標識、進程 ID 和隨機數等信息

在這里插入圖片描述

MongoStoreProduct.java

@Data
@Document("storeproductinfo")
public class MongoStoreProduct {/*** 文檔的id使用ObjectId類型來封裝,并且貼上@Id注解*/@Id@Field("_id")@JsonProperty("_id")private String id;/*** 圖片*/@Field("image")@JsonProperty("image")private String image;/*** 輪播圖片*/@Field("sliderImage")@JsonProperty("sliderImage")private String sliderImage;/*** 店鋪名稱*/@Field("storeName")@JsonProperty("storeName")private String storeName;/*** 店鋪信息*/@Field("storeInfo")@JsonProperty("storeInfo")private String storeInfo;/*** 關鍵詞*/@Field("keyword")@JsonProperty("keyword")private String keyword;/*** 分類ID*/@Field("cateId")@JsonProperty("cateId")private String cateId;/*** 單位名稱*/@Field("unitName")@JsonProperty("unitName")private String unitName;/*** 排序*/@Field("sort")@JsonProperty("sort")private Integer sort;/*** 是否熱門*/@Field("isHot")@JsonProperty("isHot")private Boolean isHot;/*** 是否有優惠*/@Field("isBenefit")@JsonProperty("isBenefit")private Boolean isBenefit;/*** 是否精品*/@Field("isBest")@JsonProperty("isBest")private Boolean isBest;/*** 是否新品*/@Field("isNew")@JsonProperty("isNew")private Boolean isNew;/*** 是否好評*/@Field("isGood")@JsonProperty("isGood")private Boolean isGood;/*** 贈送積分*/@Field("giveIntegral")@JsonProperty("giveIntegral")private Integer giveIntegral;/*** 是否子店鋪*/@Field("isSub")@JsonProperty("isSub")private Boolean isSub;/*** 虛擬銷量*/@Field("ficti")@JsonProperty("ficti")private Integer ficti;/*** 模板ID*/@Field("tempId")@JsonProperty("tempId")private Integer tempId;/*** 規格類型*/@Field("specType")@JsonProperty("specType")private Boolean specType;/*** 活動*/@Field("activity")@JsonProperty("activity")private String activity;/*** 屬性*/@Field("attr")@JsonProperty("attr")private String attr;/*** 屬性值*/@Field("attrValue")@JsonProperty("attrValue")private String attrValue;/*** 內容*/@Field("content")@JsonProperty("content")private String content;/*** 優惠券ID列表*/@Field("couponIds")@JsonProperty("couponIds")private String couponIds;/*** 平鋪模式*/@Field("flatPattern")@JsonProperty("flatPattern")private String flatPattern;
}

?? MongoDB常用api

TestMongoDB.java

@Slf4j
@SpringBootTest
public class TestMongoDB {@Resourceprivate StoreProductMongoRepository storeProductMongoRepository;/*** 生成模擬數據** @param num 生成的數量* @return 模擬數據列表*/private List<MongoStoreProduct> getStoreProduct(Integer num) {List<MongoStoreProduct> result = new ArrayList<>();for (int i = 0; i < num; i++) {MongoStoreProduct mongoStoreProduct = new MongoStoreProduct();mongoStoreProduct.setId(String.valueOf(999 + i)).setImage("https://www.baidu.com/img/bd_logo1.png").setSliderImage("https://www.baidu.com/img/bd_logo1.png").setStoreName("測試商品" + i).setStoreInfo("測試商品" + i).setKeyword("測試商品").setCateId("1").setUnitName("件").setSort(1).setIsHot(true).setIsBenefit(true).setIsBest(true).setIsNew(true).setIsGood(true).setGiveIntegral(1).setIsSub(true).setFicti(1).setTempId(1).setSpecType(true).setActivity("{\"test\":\"test\"}").setAttr("{\"test\":\"test\"}").setAttrValue("{\"test\":\"test\"}").setContent("{\"test\":\"test\"}").setCouponIds("{\"test\":\"test\"}").setFlatPattern("{\"test\":\"test\"}");result.add(mongoStoreProduct);}return result;}/*** 插入單條數據  id相同時,內容會進行覆蓋*/@Testvoid test_insert() {MongoStoreProduct mongoStoreProduct = getStoreProduct(1).get(0);MongoStoreProduct save = storeProductMongoRepository.save(mongoStoreProduct);log.info("插入單條數據,結果: {}", save);}/*** 插入多條數據  id相同時,內容會進行覆蓋*/@Testvoid test_insertMultiple() {List<MongoStoreProduct> storeProduct = getStoreProduct(3);List<MongoStoreProduct> mongoStoreProducts = storeProductMongoRepository.saveAll(storeProduct);mongoStoreProducts.forEach(product -> log.info("插入多條數據,結果: {}", product));}/*** 根據 ID 查詢單條數據*/@Testvoid test_findById() {Optional<MongoStoreProduct> mongoStoreProductOpt = storeProductMongoRepository.findById(String.valueOf(999));if (mongoStoreProductOpt.isPresent()) {log.info("根據 ID 查詢單條數據,結果: {}", mongoStoreProductOpt.get());} else {log.info("未找到對應 ID 的數據");}}/*** 查詢所有數據*/@Testvoid test_findAll() {Iterable<MongoStoreProduct> mongoStoreProducts = storeProductMongoRepository.findAll();mongoStoreProducts.forEach(product -> log.info("查詢所有數據,結果: {}", product));}/*** 根據 ID 刪除單條數據*/@Testvoid test_deleteById() {storeProductMongoRepository.deleteById(String.valueOf(999));log.info("根據 ID 刪除單條數據,刪除完成");}/*** 刪除所有數據*/@Testvoid test_deleteAll() {storeProductMongoRepository.deleteAll();log.info("刪除所有數據,刪除完成");}/*** 分頁查詢數據*/@Testvoid test_findAllByPage() {PageRequest pageRequest = PageRequest.of(0, 2, Sort.by(Sort.Direction.ASC, "id"));Page<MongoStoreProduct> productPage  = storeProductMongoRepository.findAll(pageRequest);log.info("當前頁碼: {}, 每頁記錄數: {}, 總記錄數: {}, 總頁數: {}",productPage.getNumber(), productPage.getSize(), productPage.getTotalElements(), productPage.getTotalPages());// 當前頁碼: 0, 每頁記錄數: 2, 總記錄數: 23, 總頁數: 12productPage.getContent().forEach(product -> log.info("分頁查詢數據,結果: {}", product));}
}

分頁返回結果:

在這里插入圖片描述

注意點:

  1. mongoDB在save或者saveAll時,如果id已經存在,則會對改id數據進行覆蓋
  2. storeProductMongoRepository中沒有更新相關的接口,可以根據第一點特性進行數據覆蓋,代碼如下,
@Test
void test_updateByFindAndSave() {Optional<StoreProduct> productOptional = storeProductMongoRepository.findById(999L);if (productOptional.isPresent()) {StoreProduct product = productOptional.get();product.setStoreName("更新后的測試商品");StoreProduct updatedProduct = storeProductMongoRepository.save(product);log.info("更新數據,結果: {}", updatedProduct);} else {log.info("未找到對應 ID 的數據,無法更新");}
}

?? ES crud操作 ??????

?? 前期準備

MySQL、Redis、MongoDB可視化工具用Navicat可以解決,ES可以使用ElasticHD,當然也可以使用Postman直接查詢結果,先簡單介紹一下ElasticHD使用

  1. 下載地址:https://github.com/360EntSecGroup-Skylar/ElasticHD/releases
  2. 執行:直接雙擊ElasticHD.exe。//或./ElasticHD -p 127.0.0.1:980
  3. 啟動訪問:http://localhost:9800

這個 Dashboard的UI設計非常酷炫:

在這里插入圖片描述
輸入es連接,點connect登錄:

在這里插入圖片描述

如果有賬號密碼,使用

http://username:password@host:port

例如:

http://elastic:elastic@http://127.0.0.1:9200

數據搜索直觀易使用:

在這里插入圖片描述

索引列表看得比較清楚:

在這里插入圖片描述
這個 SQL查詢語句ESJson查詢格式的小工具挺厲害的:在這里插入圖片描述

?? maven依賴

?? tips

es 8.x以上版本,只支持springboot 2.7.x以上,且maven依賴的版本需要和es服務的版本要保持一致,因為我的springBoot版本為2.4.2,我的es選取的是7.13.2版本

在這里插入圖片描述

<!-- 引入es -->
<dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-elasticsearch</artifactId><version>4.2.9</version><scope>compile</scope><exclusions><exclusion><groupId>transport</groupId><artifactId>org.elasticsearch.client</artifactId></exclusion></exclusions>
</dependency>
<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.13.2</version>
</dependency>
<dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>7.13.2</version>
</dependency>

?? 配置文件

application.yml

spring:elasticsearch:rest:uris: 127.0.0.1:9200username:password:read-timeout: 120s
es:storeProduct:indexName: store_product_info_v2pageSize: 500
@Configuration
@ConfigurationProperties(prefix = "spring.elasticsearch.rest")
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {@Value("${spring.elasticsearch.rest.uris}")private String uris;@Value("${spring.elasticsearch.rest.username}")private String username;@Value("${spring.elasticsearch.rest.password}")private String password;@Override@Bean(name = "elasticsearchClient", destroyMethod = "close")public RestHighLevelClient elasticsearchClient() {ClientConfiguration configuration = ClientConfiguration.builder().connectedTo(uris).withBasicAuth(username, password).withConnectTimeout(Duration.ofSeconds(60)).withSocketTimeout(Duration.ofSeconds(60)).withHttpClientConfigurer(httpClientBuilder -> httpClientBuilder.setDefaultIOReactorConfig(IOReactorConfig.custom().setSoKeepAlive(true).build()).setKeepAliveStrategy((httpResponse, httpContext) -> 1000 * 60 * 3)).build();return RestClients.create(configuration).rest();}@Override@Bean(name = {"elasticsearchRestTemplate"})public ElasticsearchRestTemplate elasticsearchOperations(ElasticsearchConverter elasticsearchConverter,@Qualifier("elasticsearchClient") RestHighLevelClient elasticsearchClient) {return new ElasticsearchRestTemplate(elasticsearchClient, elasticsearchConverter);}
}

?? 定義實體類

@Document(indexName = "store_product_info_v2")注解綁定是es的索引,@Setting是配置文件的目錄,number_of_shards是分片數,number_of_replicas表示分片副本數,max_result_window允許搜索最大值

{"index": {"number_of_shards": 1,"number_of_replicas": 1,"max_result_window": 100000}
}

StoreProductEsDTO.java

@Data
@Document(indexName = "store_product_info_v2")
//@Document(indexName = "#{@StoreProductServiceImpl.getStoreProductEsIndexName()}")
@Setting(settingPath = "es/StoreProductSettings.json")
public class StoreProductEsDTO {/*** id*/@Id@Field(type = FieldType.Keyword)private String id;/*** 圖片*/@Field(value = "image", type = FieldType.Text)private String image;/*** 滑塊圖片*/@Field(value = "slider_image", type = FieldType.Text)private String sliderImage;/*** 店鋪名稱*/@Field(value = "store_name", type = FieldType.Text)private String storeName;/*** 店鋪信息*/@Field(value = "store_info", type = FieldType.Text)private String storeInfo;/*** 關鍵詞*/@Field(value = "keyword", type = FieldType.Text)private String keyword;/*** 分類 ID*/@Field(value = "cate_id", type = FieldType.Keyword)private String cateId;/*** 單位名稱*/@Field(value = "unit_name", type = FieldType.Text)private String unitName;/*** 排序*/@Field(value = "sort", type = FieldType.Integer)private Integer sort;/*** 是否熱門*/@Field(value = "is_hot", type = FieldType.Boolean)private Boolean isHot;/*** 是否有優惠*/@Field(value = "is_benefit", type = FieldType.Boolean)private Boolean isBenefit;/*** 是否精品*/@Field(value = "is_best", type = FieldType.Boolean)private Boolean isBest;/*** 是否新品*/@Field(value = "is_new", type = FieldType.Boolean)private Boolean isNew;/*** 是否優質*/@Field(value = "is_good", type = FieldType.Boolean)private Boolean isGood;/*** 贈送積分*/@Field(value = "give_integral", type = FieldType.Integer)private Integer giveIntegral;/*** 是否子項*/@Field(value = "is_sub", type = FieldType.Boolean)private Boolean isSub;/*** 虛擬數據*/@Field(value = "ficti", type = FieldType.Integer)private Integer ficti;/*** 模板 ID*/@Field(value = "temp_id", type = FieldType.Integer)private Integer tempId;/*** 規格類型*/@Field(value = "spec_type", type = FieldType.Boolean)private Boolean specType;/*** 活動*/@Field(value = "activity", type = FieldType.Text)private String activity;/*** 屬性*/@Field(value = "attr", type = FieldType.Text)private String attr;/*** 屬性值*/@Field(value = "attr_value", type = FieldType.Text)private String attrValue;/*** 內容*/@Field(value = "content", type = FieldType.Text)private String content;/*** 優惠券 ID 列表*/@Field(value = "coupon_ids", type = FieldType.Text)private String couponIds;/*** 平鋪模式*/@Field(value = "flat_pattern", type = FieldType.Text)private String flatPattern;}

?? ES常用api

TestES.java

import com.db.test.entity.dto.StoreProductEsDTO;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.*;import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;/*** @author hanson.huang* @version V1.0* @ClassName TestES* @Description es 測試類* @date 2025/2/18 19:41**/
@Slf4j
@SpringBootTest
public class TestES {@Resource(name = "elasticsearchRestTemplate")private ElasticsearchRestTemplate elasticsearchRestTemplate;/*** 生成模擬的 StoreProductEsDTO 對象* @return 模擬對象*/private StoreProductEsDTO generateMockProduct(String id) {StoreProductEsDTO product = new StoreProductEsDTO();product.setId(id);product.setImage("https://example.com/image.jpg");product.setSliderImage("https://example.com/slider_image.jpg");product.setStoreName("測試店鋪商品" + id);product.setStoreInfo("這是一個測試用的店鋪商品信息");product.setKeyword("測試商品");product.setCateId("1001");product.setUnitName("件");product.setSort(1);product.setIsHot(true);product.setIsBenefit(true);product.setIsBest(true);product.setIsNew(true);product.setIsGood(true);product.setGiveIntegral(10);product.setIsSub(false);product.setFicti(1);product.setTempId(1);product.setSpecType(true);product.setActivity("{\"name\":\"測試活動\"}");product.setAttr("{\"color\":\"red\"}");product.setAttrValue("{\"size\":\"L\"}");product.setContent("商品詳細內容描述");product.setCouponIds("{\"id\":\"C001\"}");product.setFlatPattern("{\"mode\":\"平鋪\"}");return product;}/*** 插入單條文檔*/@Testvoid testInsertDocument() {StoreProductEsDTO product = generateMockProduct("991");StoreProductEsDTO savedProduct = elasticsearchRestTemplate.save(product);log.info("插入文檔結果: {}", savedProduct);}/*** 批量插入文檔*/@Testvoid testBulkInsertDocuments() {List<StoreProductEsDTO> products = Arrays.asList(generateMockProduct("992"), generateMockProduct("993"));Iterable<StoreProductEsDTO> savedProducts = elasticsearchRestTemplate.save(products);savedProducts.forEach(product -> log.info("批量插入文檔結果: {}", product));}/*** 根據 ID 刪除文檔*/@Testvoid testDeleteDocument() {String id = "997";elasticsearchRestTemplate.delete(id, StoreProductEsDTO.class);log.info("刪除 ID 為 {} 的文檔", id);}/*** 根據 ID 更新文檔*/@Testvoid testUpdateDocument() {StoreProductEsDTO product = generateMockProduct("994");product.setStoreName("更新后的測試店鋪商品");StoreProductEsDTO updatedProduct = elasticsearchRestTemplate.save(product);log.info("更新文檔結果: {}", updatedProduct);}/*** 查詢單條文檔*/@Testvoid testSearchSingleDocument() {String id = "992";StoreProductEsDTO product = elasticsearchRestTemplate.get(id, StoreProductEsDTO.class);if (product != null) {log.info("查詢到的文檔: {}", product);} else {log.info("未查詢到 ID 為 {} 的文檔", id);}}/*** 查詢所有文檔*/@Testvoid testSearchAllDocuments() {Query query = new CriteriaQuery(new Criteria());SearchHits<StoreProductEsDTO> searchHits = elasticsearchRestTemplate.search(query, StoreProductEsDTO.class);searchHits.forEach(hit -> log.info("查詢到的文檔: {}", hit.getContent()));}/*** 分頁查詢文檔*/@Testvoid testSearchDocumentsByPage() {int page = 0;int size = 10;Pageable pageable = PageRequest.of(page, size);Query query = new CriteriaQuery(new Criteria()).setPageable(pageable);SearchHits<StoreProductEsDTO> searchHits = elasticsearchRestTemplate.search(query, StoreProductEsDTO.class);log.info("當前頁文檔數量: {}", searchHits.getSearchHits().size());// 修正遍歷部分List<org.springframework.data.elasticsearch.core.SearchHit<StoreProductEsDTO>> searchHitList = searchHits.getSearchHits();for (org.springframework.data.elasticsearch.core.SearchHit<StoreProductEsDTO> hit : searchHitList) {log.info("分頁查詢到的文檔: {}", hit.getContent());}}/*** 根據條件查詢文檔*/@Testvoid testSearchDocumentsByCondition() {Criteria criteria = new Criteria("storeName").is("測試店鋪商品");Query query = new CriteriaQuery(criteria);SearchHits<StoreProductEsDTO> searchHits = elasticsearchRestTemplate.search(query, StoreProductEsDTO.class);searchHits.forEach(hit -> log.info("根據條件查詢到的文檔: {}", hit.getContent()));}
}

條件查詢中,Criteria是模糊匹配,能查出storeName值為測試店鋪商品、‘xxx測試店鋪商品’、 ‘測試店鋪商品xxx’、 'xxx測試店鋪商品xxx’等情況

結果如下:

在這里插入圖片描述

?? 性能比較

先疊個甲,本次比較非常不專業,數量比較小,MySQL也沒設置合適索引,所以本次性能比較不具備參考性

?? 模擬創建數據接口

controller

@Resource
private StoreProductService storeProductService;/*** 添加數據** @param storeProductRequest 需要添加的數據* @return*/
@PostMapping("/addData")
public String addData(@RequestBody StoreProductRequest storeProductRequest) {storeProductService.insertData(storeProductRequest);return "success";
}

實現類:StoreProductServiceImpl.java

@Slf4j
@Data
@Service
public class StoreProductServiceImpl extends ServiceImpl<StoreProductMapper, StoreProduct> implements StoreProductService {@Resourceprivate StoreProductMapper storeProductMapper;@Resource(name = "stringRedisTemplate")private StringRedisTemplate stringRedisTemplate;@Resource(name = "elasticsearchRestTemplate")private ElasticsearchRestTemplate elasticsearchRestTemplate;@Resourceprivate StoreProductMongoRepository storeProductMongoRepository;private static final String REDIS_KEY = "storeProduct:key";@Value("${es.storeProduct.indexName:store_product_info_v2}")public String storeProductEsIndexName = "store_product_info_v2";@Value("${es.storeProduct.pageSize:500}")private int storeProductEsListPageSize = 500;@Overridepublic void insertData(StoreProductRequest storeProductRequest) {// 1.插入mysqlStoreProduct storeProduct = new StoreProduct();BeanUtils.copyProperties(storeProductRequest, storeProduct);storeProduct.setActivity(JacksonUtils.jsonEncode(storeProductRequest.getActivity()));storeProduct.setAttr(JacksonUtils.jsonEncode(storeProductRequest.getAttr()));storeProduct.setAttrValue(JacksonUtils.jsonEncode(storeProductRequest.getAttrValue()));storeProduct.setCouponIds(JacksonUtils.jsonEncode(storeProductRequest.getCouponIds()));storeProductMapper.insert(storeProduct);log.warn("數據已經插入mysql數據庫:{}", JacksonUtils.jsonEncode(storeProduct));// 2.插入redisstringRedisTemplate.opsForValue().set(REDIS_KEY + storeProduct.getId(), JacksonUtils.jsonEncode(storeProduct));log.warn("數據已經插入redis數據庫:{}", JacksonUtils.jsonEncode(storeProduct));// 3.插入mongoMongoStoreProduct mongoStoreProduct = new MongoStoreProduct();BeanUtils.copyProperties(storeProduct, mongoStoreProduct);mongoStoreProduct.setId(storeProduct.getId() + "");try {storeProductMongoRepository.save(mongoStoreProduct);log.warn("數據已經插入mongo數據庫:{}", JacksonUtils.jsonEncode(mongoStoreProduct));} catch (Exception e) {log.error("數據插入mongo數據庫失敗,失敗原因:{}", e);}// 4.插入esStoreProductEsDTO storeProductEsDTO = new StoreProductEsDTO();BeanUtils.copyProperties(storeProduct, storeProductEsDTO);storeProductEsDTO.setId(storeProduct.getId() + "");// 創建客戶端List<IndexQuery> queries = new ArrayList<>();IndexQuery indexQuery = new IndexQuery();indexQuery.setId(storeProduct.getId() + "");indexQuery.setObject(storeProductEsDTO);queries.add(indexQuery);try {elasticsearchRestTemplate.bulkIndex(queries, StoreProductEsDTO.class);log.warn("數據已經插入es數據庫:{}", JacksonUtils.jsonEncode(storeProductEsDTO));} catch (Exception e) {log.error("數據插入es數據庫失敗,失敗原因:{}", e);}}    
}

接口:

curl --location 'localhost:8081/dbTest/addData' \
--header 'Content-Type: application/json' \
--data '{"image": "https://example.com/image.jpg","sliderImage": "https://example.com/slider1.jpg,https://example.com/slider2.jpg","storeName": "新款智能手機","storeInfo": "這是一款高性能智能手機","keyword": "手機,智能手機","cateId": "1,2,3","unitName": "臺","sort": 1,"isHot": true,"isBenefit": false,"isBest": true,"isNew": true,"isGood": false,"giveIntegral": 100,"isSub": true,"ficti": 500,"tempId": 1,"specType": true,"activity": ["1", "2", "3"],"attr": [{"attrName": "顏色","attrValues": "紅色,藍色,綠色"},{"attrName": "尺寸","attrValues": "大號,中號,小號"}],"attrValue": [{"productId": 0,"stock": 100,"suk": "紅色-大號","price": 1999.00,"image": "https://example.com/red-large.jpg","cost": 1500.00,"otPrice": 2199.00,"weight": 0.5,"volume": 0.1,"brokerage": 100.00,"brokerageTwo": 50.00,"attrValue": "{\"顏色\":\"紅色\",\"尺寸\":\"大號\"}","quota": 10,"quotaShow": 10,"minPrice": 1500.00},{"productId": 0,"stock": 150,"suk": "藍色-中號","price": 1899.00,"image": "https://example.com/blue-medium.jpg","cost": 1400.00,"otPrice": 2099.00,"weight": 0.45,"volume": 0.09,"brokerage": 90.00,"brokerageTwo": 45.00,"attrValue": "{\"顏色\":\"藍色\",\"尺寸\":\"中號\"}","quota": 15,"quotaShow": 15,"minPrice": 1400.00}],"content": "<p>這是一款高性能智能手機,適合各種場景使用。</p>","couponIds": [1, 2, 3],"flatPattern": "https://example.com/flat-pattern.jpg"
}'

調用這個接口后,分別往四個中間件中插入了id為1000的數據

在這里插入圖片描述

MySQL:

在這里插入圖片描述
Redis:

在這里插入圖片描述

MongoDB:

在這里插入圖片描述

ES:

在這里插入圖片描述

這樣數據算創建完成,現在測試分別查出這條數據需要花費時間

?? 查詢數據接口

我們使用stopwatch()來統計接口耗時,stopwatch()用法可以參考文章《【StopWatch】使用 StopWatch 統計代碼中的耗時操作》

代碼如下:

/*** @return 通過四種方式獲取數據*/
@Override
public Map<String, Object> getData(Integer id) {Map<String, Object> result = new HashMap<>();// 1.從mysql獲取數據StopWatch stopWatch = new StopWatch();stopWatch.start("mysql查詢數據開始");StoreProduct storeProduct = storeProductMapper.selectById(id);result.put("mysql", storeProduct);stopWatch.stop();// 2.從redis獲取數據stopWatch.start("redis查詢數據開始");String redisData = stringRedisTemplate.opsForValue().get(REDIS_KEY + id);result.put("redis", JacksonUtils.jsonDecode(redisData, StoreProduct.class));stopWatch.stop();// 3.從mongo獲取數據stopWatch.start("mongo查詢數據開始");Optional<MongoStoreProduct> optional = storeProductMongoRepository.findById(String.valueOf(id));if (optional.isPresent()) {MongoStoreProduct mongoStoreProduct = optional.get();result.put("mongo", mongoStoreProduct);}stopWatch.stop();// 4.從es獲取數據stopWatch.start("es查詢數據開始");StoreProductEsDTO storeProductEsDTO = elasticsearchRestTemplate.get(String.valueOf(id), StoreProductEsDTO.class);result.put("es", storeProductEsDTO);stopWatch.stop();log.error("查詢數據耗時:{}", stopWatch.prettyPrint(TimeUnit.MILLISECONDS));return result;
}

調用接口:

在這里插入圖片描述
統計耗時:

查詢數據耗時:StopWatch '': running time = 87 ms
---------------------------------------------
ms         %     Task name
---------------------------------------------
000000033  38%   mysql查詢數據開始
000000012  14%   redis查詢數據開始
000000024  28%   mongo查詢數據開始
000000017  20%   es查詢數據開始

雖然結果不具備參考性,可以看出es和redis性能比較好,在大量數據情況下,就查詢數據而言,redis > es > mongoDB > mysql

總結一下:

中間件查詢效率性能分析底層存儲結構優點缺點使用場景
MySQL中等適用于結構化數據,復雜查詢性能較好關系型數據庫,使用B+樹索引1. 支持復雜查詢和事務
2. 數據一致性高
3. 成熟的生態系統和工具支持
1. 大數據量時性能下降
2. 水平擴展較復雜
3. 不適合非結構化數據
1. 金融系統(需要強一致性和事務支持)
2. ERP系統(復雜查詢和報表)
3. 傳統的關系型數據管理(如用戶管理、訂單管理)
Redis適用于高并發、低延遲的場景內存鍵值存儲,支持多種數據結構1. 極高的讀寫性能
2. 支持豐富的數據結構
3. 適合緩存和實時數據處理
1. 數據容量受內存限制
2. 持久化可能影響性能
3. 不適合復雜查詢
1. 緩存系統(如網頁緩存、會話緩存)
2. 實時排行榜(如游戲積分榜)
3. 消息隊列(如任務隊列)
4. 實時數據處理(如實時推薦系統)
MongoDB中高適用于半結構化數據,讀寫性能較好文檔型數據庫,使用BSON格式存儲,支持索引1. 靈活的數據模型
2. 水平擴展容易
3. 適合處理大量非結構化數據
1. 復雜查詢性能不如關系型數據庫
2. 事務支持較弱(雖然MongoDB 4.0+支持多文檔事務)
3. 存儲空間占用較大
1. 內容管理系統(CMS)
2. 物聯網(IoT)數據存儲
3. 日志存儲和分析
4. 實時大數據處理(如用戶行為分析)
Elasticsearch適用于全文搜索和實時分析分布式搜索引擎,使用倒排索引1. 強大的全文搜索能力
2. 實時數據分析
3. 水平擴展容易
1. 寫入性能相對較低
2. 配置和維護復雜
3. 數據一致性較弱(最終一致性)
1. 全文搜索引擎(如電商網站的商品搜索)
2. 日志和指標分析(如ELK Stack)
3. 實時數據分析(如監控和報警系統)
4. 推薦系統(基于用戶行為的實時推薦)

創作不易,不妨點贊、收藏、關注支持一下,各位的支持就是我創作的最大動力??

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/70273.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/70273.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/70273.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

51單片機入門_10_數碼管動態顯示(數字的使用;簡單動態顯示;指定值的數碼管動態顯示)

接上篇的數碼管靜態顯示&#xff0c;以下是接上篇介紹到的動態顯示的原理。 動態顯示的特點是將所有位數碼管的段選線并聯在一起&#xff0c;由位選線控制是哪一位數碼管有效。選亮數碼管采用動態掃描顯示。所謂動態掃描顯示即輪流向各位數碼管送出字形碼和相應的位選&#xff…

C++入門《類和對象》之《運算符重載》詳解|成員函數重載/非成員函數重載

C 中&#xff0c;運算符重載是一種特殊的函數&#xff0c;它允許程序員為自定義的數據類型&#xff08;如類和結構體&#xff09;重新定義運算符的行為&#xff0c;使得這些運算符能夠像處理內置數據類型一樣處理自定義類型的數據。下面將從多個方面詳細講解 C 里的運算符重載。…

Salesforce 檢索Layout的設定

做了許多Object&#xff0c;卻想不起來怎么設置我的Listview的項目了。 問題&#xff1a; salesforce 最近參照したオブジェクト 表示項目を変更したいですが、「検索レイアウト」の選択メニューが該當オブジェクトのオブジェクトマネージャーから出てないです。 解決方法&am…

SECS/GEM300應用案例參考

GEM300 是一種用于半導體制造領域的通信協議標準&#xff0c;主要用于支持 300mm 晶圓制造的自動化生產。以下是 GEM300 的一些具體應用案例&#xff1a; 1. 半導體設備集成 設備制造商的應用&#xff1a;廣州金南瓜科技有限公司通過 GEM300 SDK&#xff0c;幫助國內多個半導體…

win10系統上的虛擬機安裝麒麟V10系統提示找不到操作系統

目錄預覽 一、問題描述二、原因分析三、解決方案四、參考鏈接 一、問題描述 win10系統上的虛擬機安裝麒麟V10系統提示找不到操作系統&#xff0c;報錯&#xff1a;Operating System not found 二、原因分析 國產系統&#xff0c;需要注意的點&#xff1a; 需要看你的系統類…

情書網源碼 情書大全帝國cms7.5模板

源碼介紹 帝國cms7.5仿《情書網》模板源碼&#xff0c;同步生成帶手機站帶采集。適合改改做文學類的網站。 效果預覽 源碼獲取 情書網源碼 情書大全帝國cms7.5模板

C語言題目:鏈表數據求和操作

題目描述 讀入10個復數&#xff0c;建立對應鏈表&#xff0c;然后求所有復數的和。 輸入格式 無 輸出格式 無 樣例輸入 1 2 1 3 4 5 2 3 3 1 2 1 4 2 2 2 3 3 1 1 樣例輸出 2323i 代碼功能概述 createNode 函數&#xff1a; 創建一個包含 10 個復數節點的鏈表。 每個…

STM32 ADC介紹(硬件原理篇)

目錄 背景 AD轉換器 采樣與保持 量化 編碼 AD轉換器轉換原理 DA轉換原理 AD轉換原理 1.逐次逼近型AD轉換器 2.并聯比較型AD轉換器 編碼器 同步D觸發器和邊沿D觸發器 基本RS觸發器 同步RS觸發器 同步D觸發器 邊沿型D觸發器&#xff08;維持-阻塞D觸發器&#xff…

公網遠程家里局域網電腦過程詳細記錄,包含設置路由器。

由于從校內遷居小區,校內需要遠程控制訪問小區內個人電腦,于是早些時間剛好自己是電信寬帶,可以申請公網ipv4不需要花錢,所以就打電話直接申請即可,申請成功后訪問光貓設備管理界面192.168.1.1,輸入用戶名密碼登錄超管(密碼是網上查下就有了)設置了光貓為橋接模式,然后…

流行編程語言全解析:優勢、應用與短板

Python&#xff1a; 優勢 Python 以其簡潔、易讀的語法聞名&#xff0c;新手能快速上手。豐富的庫和框架&#xff0c;能極大地提高開發效率。 適用領域 數據科學與分析&#xff1a;處理和分析大規模數據集&#xff0c;進行數據可視化。典型示例&#xff1a;Google 用 Pytho…

統信服務器操作系統V20 1070A 安裝docker新版本26.1.4

應用場景&#xff1a; 硬件/整機信息&#xff1a;x86平臺、深信服超融合平臺 OS版本信息&#xff1a;統信V20 1070a 1.獲取docker二進制包 鏈接: https://pan.baidu.com/s/1SukBlra0mQxvslTfFakzGw?pwd5s5y 提取碼: 5s5y tar xvf docker-26.1.4.tgz groupadd docker ch…

在 Vue 3 中使用 Lottie 動畫:實現一個加載動畫

在現代前端開發中&#xff0c;動畫是提升用戶體驗的重要元素之一。Lottie 是一個流行的動畫庫&#xff0c;它允許我們使用 JSON 文件來渲染高質量的動畫。本文將介紹如何在 Vue 3 項目中集成 Lottie 動畫&#xff0c;并實現一個加載動畫效果。 如果對你有幫助請幫忙點個&#x…

【Spring】Spring配置文件

目錄 ?什么是配置文件&#xff1f; 配置文件的作用 SpringBoot配置文件 配置文件格式 配置文件的優先級 properties配置文件說明 properties基本語法 讀取配置文件 properties缺點 yml配置文件說明 yml基本語法 使用yml連接數據庫 yml配置不同數據類型及null 注意…

藍橋杯篇---實時時鐘 DS1302

文章目錄 前言特點簡介1.低功耗2.時鐘/日歷功能3.32字節的額外RAM4.串行接口 DS1302 引腳說明1.VCC12.VCC23.GND4.CE5.I/O6.SCLK DS1302 寄存器1.秒寄存器2.分鐘寄存器3.小時寄存器4.日寄存器5.月寄存器6.星期寄存器7.年寄存器8.控制寄存器 DS1302 與 IAP25F2K61S2 的連接1.CE連…

Dubbo:高效的分布式服務框架

引言 在當今互聯網應用的快速發展中&#xff0c;微服務架構已經成為一種主流的設計模式&#xff0c;它將一個大型單體應用拆分成多個小型、松耦合的服務。Dubbo 作為一款由阿里巴巴開源的 RPC 服務框架&#xff0c;專門為解決分布式系統中服務通信和治理的問題而設計。本文將深…

Visual Studio Code使用ai大模型編成

1、在Visual Studio Code搜索安裝roo code 2、去https://openrouter.ai/settings/keys官網申請個免費的配置使用

【Javascript Day18】

目錄 標簽事件綁定的屬性參數 阻止默認行為 dialog的實現及組織冒泡&#xff08;捕獲&#xff09;傳遞 基于冒泡的事件委托 鍵盤事件的事件源對象信息 JS的自動觸發操作 標簽事件綁定的屬性參數 <!-- 標簽上的事件綁定&#xff0c;事件源對象通過 關鍵字event傳遞 --…

解鎖機器學習核心算法 | 支持向量機:機器學習中的分類利刃

一、引言 在機器學習的龐大算法體系中&#xff0c;有十種算法被廣泛認為是最具代表性和實用性的&#xff0c;它們猶如機器學習領域的 “十大神器”&#xff0c;各自發揮著獨特的作用。這十大算法包括線性回歸、邏輯回歸、決策樹、隨機森林、K - 近鄰算法、K - 平均算法、支持向…

玩客云 IP查找

1.玩客云使用靜態IP在不同網段路由器下不能使用&#xff0c;動態不好找IP地址 1.1使用python3 實現自動獲取發送 import requests import os import socket# 從環境變量獲取 PushPlus 的 token 和群組編碼 PUSH_PLUS_TOKEN os.getenv("PUSH_PLUS_TOKEN") PUSH_PLU…

Linux(Centos 7.6)命令詳解:cat

1.命令作用 將文件或標準輸入連接到標準輸出(Concatenate FILE(s), or standard input, to standard output)&#xff0c; 即將文件內容輸出到屏幕上&#xff0c;或者將多個文件合并成一個文件。 2.命令語法 Usage: cat [OPTION]... [FILE]... 3.參數詳解 OPTION: -A, -…