diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/config/AsyncConfig.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/config/AsyncConfig.java index a04d12d..0c414b5 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/config/AsyncConfig.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/config/AsyncConfig.java @@ -6,6 +6,7 @@ import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; @Configuration @EnableAsync @@ -14,10 +15,20 @@ public class AsyncConfig { @Bean("imageNameSyncExecutor") public Executor imageNameSyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - executor.setCorePoolSize(5); - executor.setMaxPoolSize(10); + // 核心线程数 + executor.setCorePoolSize(2); + // 最大线程数 + executor.setMaxPoolSize(5); + // 队列容量 executor.setQueueCapacity(100); + // 线程名前缀 executor.setThreadNamePrefix("imageNameSync-"); + // 拒绝策略:由调用线程处理 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + // 等待所有任务完成后再关闭线程池 + executor.setWaitForTasksToCompleteOnShutdown(true); + // 等待时间(秒) + executor.setAwaitTerminationSeconds(60); executor.initialize(); return executor; } diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/Grouping.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/Grouping.java index 59bed50..ca495d6 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/Grouping.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/Grouping.java @@ -18,8 +18,7 @@ import java.util.Date; public class Grouping implements Serializable { @Schema(description = "分组id",implementation = Long.class) @TableId(type = IdType.ASSIGN_ID) - @JsonFormat(shape = JsonFormat.Shape.STRING) // 仅作用于此字段 - @TableField("id") + @JsonFormat(shape = JsonFormat.Shape.STRING) private Long id; @Schema(description ="上级id",implementation = Long.class) diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/Image.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/Image.java index d8d2e77..d8bd3be 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/Image.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/Image.java @@ -16,8 +16,7 @@ import java.util.Date; public class Image { @Schema(description = "图片id",implementation = Long.class) @TableId(type = IdType.AUTO) - @JsonFormat(shape = JsonFormat.Shape.STRING) // 仅作用于此字段 - @TableField("id") + @JsonFormat(shape = JsonFormat.Shape.STRING) private Long id; @Schema(description = " 外键,关联Markdown文件ID,标识图片所属文档",implementation = Long.class ) diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/ImageName.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/ImageName.java index ae5365f..f3dcb62 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/ImageName.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/ImageName.java @@ -12,7 +12,6 @@ public class ImageName { @Schema(description = "图片名称id", implementation = Long.class) @TableId(type = IdType.AUTO) @JsonFormat(shape = JsonFormat.Shape.STRING) - @TableField("id") private Long id; @Schema(description = "关联的Markdown文件ID", implementation = Long.class) diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/MarkdownFile.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/MarkdownFile.java index 6c016b8..289e86c 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/MarkdownFile.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/MarkdownFile.java @@ -18,8 +18,7 @@ import java.util.Date; public class MarkdownFile implements Serializable { @Schema(description = "文本id",implementation = Long.class) @TableId(type = IdType.AUTO) - @JsonFormat(shape = JsonFormat.Shape.STRING) // 仅作用于此字段 - @TableField("id") + @JsonFormat(shape = JsonFormat.Shape.STRING) private Long id; @Schema(description = "分组表id",implementation = Long.class) diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/MarkdownFileVO.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/MarkdownFileVO.java index 2520985..6b6f1b8 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/MarkdownFileVO.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/MarkdownFileVO.java @@ -1,6 +1,7 @@ package com.test.bijihoudaun.entity; import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import lombok.EqualsAndHashCode; @@ -11,5 +12,6 @@ public class MarkdownFileVO extends MarkdownFile { private String groupingName; @TableField(exist = false) + @JsonFormat(shape = JsonFormat.Shape.STRING) private Long groupingId; } \ No newline at end of file diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/RegistrationCode.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/RegistrationCode.java index 8c7517b..bf55c09 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/RegistrationCode.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/RegistrationCode.java @@ -18,7 +18,6 @@ public class RegistrationCode implements Serializable { @TableId(type = IdType.AUTO) @Schema(description = "主键ID", name = "id") - @TableField("id") private Long id; @Schema(description = "注册码", name = "code") diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/SystemSetting.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/SystemSetting.java index 9249e9e..4ab6b39 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/SystemSetting.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/SystemSetting.java @@ -17,7 +17,6 @@ public class SystemSetting implements Serializable { @TableId @Schema(description = "设置键", name = "settingKey") - @TableField("`setting_key`") private String settingKey; @Schema(description = "设置值", name = "settingValue") diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/User.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/User.java index f74477c..d5db427 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/User.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/User.java @@ -16,8 +16,7 @@ import java.util.Date; public class User { @Schema(description = "用户id",implementation = Long.class) @TableId(type = IdType.AUTO) - @JsonFormat(shape = JsonFormat.Shape.STRING) // 仅作用于此字段 - @TableField("id") + @JsonFormat(shape = JsonFormat.Shape.STRING) private Long id; @Schema(description = "用户名",implementation = String.class) diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/MarkdownFileMapper.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/MarkdownFileMapper.java index 37209eb..7e7db93 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/MarkdownFileMapper.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/MarkdownFileMapper.java @@ -15,7 +15,10 @@ import org.apache.ibatis.annotations.Update; @Mapper public interface MarkdownFileMapper extends BaseMapper { - @Select("SELECT mf.id, mf.grouping_id as groupingId, mf.`title`, mf.file_name, mf.`content`, mf.created_at, mf.updated_at, mf.is_deleted, mf.deleted_at, mf.deleted_by, mf.is_private, g.`grouping` as groupingName " + + /** + * 查询最近更新的笔记列表(不包含content大字段,提高性能) + */ + @Select("SELECT mf.id, mf.grouping_id as groupingId, mf.`title`, mf.file_name, null as `content`, mf.created_at, mf.updated_at, mf.is_deleted, mf.deleted_at, mf.deleted_by, mf.is_private, g.`grouping` as groupingName " + "FROM `markdown_file` mf " + "LEFT JOIN `grouping` g ON mf.grouping_id = g.id " + "WHERE mf.is_deleted = 0 " + @@ -23,14 +26,20 @@ public interface MarkdownFileMapper extends BaseMapper { "LIMIT #{limit}") List selectRecentWithGrouping(@Param("limit") int limit); - @Select("SELECT mf.id, mf.grouping_id as groupingId, mf.`title`, mf.file_name, mf.`content`, mf.created_at, mf.updated_at, mf.is_deleted, mf.deleted_at, mf.deleted_by, mf.is_private, g.`grouping` as groupingName " + + /** + * 根据分类ID查询笔记列表(不包含content大字段,提高性能) + */ + @Select("SELECT mf.id, mf.grouping_id as groupingId, mf.`title`, mf.file_name, null as `content`, mf.created_at, mf.updated_at, mf.is_deleted, mf.deleted_at, mf.deleted_by, mf.is_private, g.`grouping` as groupingName " + "FROM `markdown_file` mf " + "LEFT JOIN `grouping` g ON mf.grouping_id = g.id " + "WHERE mf.grouping_id = #{groupingId} AND mf.is_deleted = 0 " + "ORDER BY mf.updated_at DESC") List selectByGroupingIdWithGrouping(@Param("groupingId") String groupingId); - @Select("SELECT id, grouping_id, `title`, file_name, `content`, created_at, updated_at, is_deleted, deleted_at, deleted_by, is_private FROM `markdown_file` WHERE is_deleted = 1") + /** + * 查询已删除的笔记(不包含content大字段) + */ + @Select("SELECT id, grouping_id, `title`, file_name, null as `content`, created_at, updated_at, is_deleted, deleted_at, deleted_by, is_private FROM `markdown_file` WHERE is_deleted = 1") List selectDeleted(); @Delete("DELETE FROM `markdown_file` WHERE id = #{id}") @@ -48,8 +57,15 @@ public interface MarkdownFileMapper extends BaseMapper { * 获取所有笔记ID * @return 所有笔记ID列表 */ - @Select("SELECT id, grouping_id, `title`, file_name, `content`, created_at, updated_at, is_deleted, deleted_at, deleted_by, is_private FROM `markdown_file` WHERE is_deleted = 0") - List findAllIds(); + @Select("SELECT id FROM `markdown_file` WHERE is_deleted = 0") + List findAllIds(); + + /** + * 获取所有笔记的ID和content(用于图片清理任务) + * @return 所有笔记的ID和content + */ + @Select("SELECT id, `content` FROM `markdown_file` WHERE is_deleted = 0") + List selectAllIdsAndContent(); @Select("SELECT mf.id, mf.grouping_id as groupingId, mf.`title`, mf.file_name, mf.`content`, mf.created_at, mf.updated_at, mf.is_deleted, mf.deleted_at, mf.deleted_by, mf.is_private, g.`grouping` as groupingName " + "FROM `markdown_file` mf " + diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/service/ImageCleanupService.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/ImageCleanupService.java index 427d7e8..e2ccbc9 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/service/ImageCleanupService.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/ImageCleanupService.java @@ -39,17 +39,15 @@ public class ImageCleanupService { */ @Transactional public int cleanupRedundantImages() { - // 获取所有笔记ID - List allMarkdownIds = markdownFileMapper.findAllIds(); + // 批量获取所有笔记的ID和content(避免N+1查询) + List allMarkdownFiles = markdownFileMapper.selectAllIdsAndContent(); // 用于存储所有被引用的图片文件名 Set referencedImageNames = new HashSet<>(); // 遍历所有笔记,收集被引用的图片 - for (Integer markdownId : allMarkdownIds) { - MarkdownFile markdownFile = markdownFileMapper.selectById(markdownId); + for (MarkdownFile markdownFile : allMarkdownFiles) { String content = (markdownFile != null) ? markdownFile.getContent() : ""; - List imageNames = MarkdownImageExtractor.extractImageFilenames(content); referencedImageNames.addAll(imageNames); } diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/service/impl/ImageServiceImpl.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/impl/ImageServiceImpl.java index f564611..3dc2840 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/service/impl/ImageServiceImpl.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/impl/ImageServiceImpl.java @@ -132,12 +132,25 @@ public class ImageServiceImpl if (CollUtil.isEmpty(urls)) { return false; } - for (String url : urls) { - Image image = imageMapper.selectOne(new QueryWrapper().eq("url", url)); - if (ObjectUtil.isNotNull(image)) { - this.deleteImageByUrl(url); + // 批量查询,避免N+1问题 + List images = imageMapper.selectList(new QueryWrapper().in("url", urls)); + if (CollUtil.isEmpty(images)) { + return false; + } + + // 批量删除文件和数据库记录 + for (Image image : images) { + try { + Path filePath = Paths.get(uploadDir, image.getStoredName()); + Files.deleteIfExists(filePath); + } catch (IOException e) { + throw new RuntimeException("删除图片文件失败: " + image.getStoredName(), e); } } + + // 批量删除数据库记录 + List ids = images.stream().map(Image::getId).toList(); + this.removeByIds(ids); return true; } } diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/service/impl/MarkdownFileServiceImpl.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/impl/MarkdownFileServiceImpl.java index 66fb8df..08affff 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/service/impl/MarkdownFileServiceImpl.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/impl/MarkdownFileServiceImpl.java @@ -165,8 +165,8 @@ public class MarkdownFileServiceImpl imageName.setMarkdownId(markdownId); return imageName; }).toList(); - // 批量插入新的文件名 - list.forEach(imageName -> imageNameMapper.insert(imageName)); + // 批量插入新的文件名(使用MyBatis Plus批量插入) + imageNameMapper.insert(list); } } else { // 数据库中已有记录,需要对比处理 diff --git a/biji-houdaun/src/main/resources/application-dev.yml b/biji-houdaun/src/main/resources/application-dev.yml index 66efb6f..4a77b1d 100644 --- a/biji-houdaun/src/main/resources/application-dev.yml +++ b/biji-houdaun/src/main/resources/application-dev.yml @@ -1,21 +1,27 @@ spring: datasource: -# driver-class-name: org.sqlite.JDBC -# url: jdbc:sqlite:C:\it\houtaigunli\biji\mydatabase.db -# jpa: -# hibernate: -# ddl-auto: none -# show-sql: true -# properties: -# hibernate: -# format_sql: true -# dialect: org.hibernate.dialect.SQLiteDialect -# - driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://hdy-hk-8-8.311169.xyz:3306/biji_db?useSSL=false&serverTimezone=UTC&characterEncoding=utf8 username: biji_user password: Ll12331100 + # HikariCP连接池优化配置 + hikari: + # 连接池名称 + pool-name: BijiHikariPool + # 最小空闲连接数 + minimum-idle: 5 + # 最大连接数 + maximum-pool-size: 20 + # 连接空闲超时时间(毫秒) + idle-timeout: 300000 + # 连接最大存活时间(毫秒) + max-lifetime: 1200000 + # 连接超时时间(毫秒) + connection-timeout: 20000 + # 测试连接是否可用的SQL + connection-test-query: SELECT 1 + # 自动提交 + auto-commit: true jpa: hibernate: ddl-auto: update @@ -32,8 +38,12 @@ mybatis-plus: map-underscore-to-camel-case: true # 启用安全模式,防止SQL注入 safe-mode: true + # 配置日志输出 + log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl global-config: db-config: logic-delete-field: isDeleted # 全局逻辑删除的实体字段名 logic-delete-value: 1 # 逻辑已删除值(默认为 1) - logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) \ No newline at end of file + logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) + # 全局表前缀(如果有的话) + # table-prefix: t_ \ No newline at end of file diff --git a/biji-houdaun/src/main/resources/application-prod.yml b/biji-houdaun/src/main/resources/application-prod.yml index 8062945..a9d02f3 100644 --- a/biji-houdaun/src/main/resources/application-prod.yml +++ b/biji-houdaun/src/main/resources/application-prod.yml @@ -1,38 +1,43 @@ spring: datasource: -# driver-class-name: org.sqlite.JDBC -# url: jdbc:sqlite:/data/mydatabase.db -# jpa: -# hibernate: -# ddl-auto: none -# show-sql: false -# properties: -# hibernate: -# format_sql: false -# dialect: org.hibernate.dialect.SQLiteDialect - -# 上面是 默认配置,数据库为sqlite,下面是 配置mysql。从环境 变量中获取 driver-class-name: ${DB_DRIVER:com.mysql.cj.jdbc.Driver} url: ${DB_URL} username: ${DB_USERNAME} password: ${DB_PASSWORD} + # HikariCP连接池优化配置(生产环境) + hikari: + # 连接池名称 + pool-name: BijiHikariPool + # 最小空闲连接数 + minimum-idle: 10 + # 最大连接数 + maximum-pool-size: 50 + # 连接空闲超时时间(毫秒) + idle-timeout: 600000 + # 连接最大存活时间(毫秒) + max-lifetime: 1800000 + # 连接超时时间(毫秒) + connection-timeout: 30000 + # 测试连接是否可用的SQL + connection-test-query: SELECT 1 + # 自动提交 + auto-commit: true jpa: hibernate: ddl-auto: update - show-sql: true + show-sql: false properties: hibernate: - format_sql: true + format_sql: false dialect: org.hibernate.dialect.MySQLDialect - - - # MyBatis-Plus配置 mybatis-plus: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true + # 生产环境关闭SQL日志 + log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl global-config: db-config: logic-delete-field: isDeleted # 全局逻辑删除的实体字段名 diff --git a/biji-qianduan/src/components/home/HomeHeader.vue b/biji-qianduan/src/components/home/HomeHeader.vue index 9ea415a..0a151fd 100644 --- a/biji-qianduan/src/components/home/HomeHeader.vue +++ b/biji-qianduan/src/components/home/HomeHeader.vue @@ -4,19 +4,21 @@

我的笔记

- - - +