项目问题汇总(持续更新中) DreamCollector 2023-09-05 2024-11-27 项目遇到的问题:
持续记录日常踩坑,希望大家自己踩一遍能帮大家少走弯路
Java篇 1. target中无自定义路径的xml文件 项目目录参考
解决方法
1、在pom.xml中放行mapper.xml,在Maven的build中加入以下配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <build > <resources > <resource > <directory > src/main/java</directory > <includes > <include > **/*.xml</include > </includes > <filtering > false</filtering > </resource > <resource > <directory > src/main/resources</directory > <includes > <include > **/*.yml</include > <include > **/*.properties</include > <include > **/*.xml</include > </includes > <filtering > false</filtering > </resource > </resources > </build >
2、配置application.properties文件
1 2 mybatis-plus.mapper-locations =classpath:com/example/common/mapper/*.xml
3、maven选择clean和campile重新编译即可
4、成功生成xml
2. 多模块找不到配置属性 报错参考 1 2 3 4 5 6 7 8 9 10 *************************** APPLICATION FAILED TO START *************************** Description: Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. Reason: Failed to determine a suitable driver class Action: Consider the following: If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
原因
1、SpringBoot启动的时候默认会在以下5个路径下找配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 springboot ┠.idea ┠config ┠my ┠src ┠main ┠java ┠resources ┠config ┠pom.xml
1 2 3 4 5 file:./config/ [项目根目录下的config目录 ]file:./config/**/ [根文件加下的config/**/目录 ]file:./ [根目录下 ]classpath:config/ [resources/config下 ]classpath: [resources下 ]
2、多模块项目启动时会去匹配当前模块的根目录路径
解决方法
1、启动模块下添加application.properties文件
2、若多模块下公用一个配置文件,可以用spring.profiles.active指定公共配置文件
3、配置完后用maven的插件compile一下
3. 多模块找不到主类 报错参考
原因
参考官方文档
一旦spring-boot-maven-plugin被包含到pomm .xml中,通过使用spring-boot:repackage目标,它会自动尝试重写归档文件,使它们可执行,当启动类找不到时会去找第一个启动方法
解决方法
1、将父类pom.xml删除spring-boot-maven-plugin相关
1 2 3 4 5 6 7 8 <plugins > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > </plugin > <plugins >
2、在启动的模块下的pom.xml添加spring-boot-maven-plugin相关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <plugins > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > <configuration > <mainClass > dc.DreamApiApplication</mainClass > </configuration > <executions > <execution > <goals > <goal > repackage</goal > </goals > </execution > </executions > </plugin > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-surefire-plugin</artifactId > <configuration > <skipTests > true</skipTests > </configuration > </plugin > </plugins >
4. jar包配置SSL失败 配置参考
我的SpringBoot依赖配置
1 2 3 springboot <version>2.1 .9 </version> tomacat <version>9.0 .22 </version> JDK <version>1.8 </version>
yaml配置(SSL证书是阿里云免费申请的.jks文件默认放Resources目录下即可)
1 2 3 4 5 6 7 8 9 server: port: 443 servlet: context-path: /ZaiZai ssl: enabled: true key-store: classpath:5989139_dreamcollector.ltd.jks key-store-password: 3Fut7Rt1 key-store-type: JKS
若本地调试提示端口占用问题
1 2 3 netstat -ano|find "443" #查找进程状态为LISTENING的进程# taskkill /f /im xxx.exe #按进程名强制结束# taskkill /f /pid 8642 #按进程PID-8642 强制结束#
解决方法
1、cmd 中查找占用端口的进程并结束进程
1 2 3 netstat -ano|find "443" #查找进程状态为LISTENING的进程# taskkill /f /im xxx.exe #按进程名强制结束# taskkill /f /pid 8642 #按进程PID-8642强制结束#
2、若本地调试运行正常但打包jar包后报错,可尝试将springboot版本降低到 2.1.8
5. 获取webp后缀图片尺寸失败 代码参考
如果在线图片是webp后缀的图片都获取不到图片尺寸
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public static void main (String[] args) throws IOException { String webpImageUrl = "https://d13n19w6sf5stu.cloudfront.net/comic/manhwahentai/popular/29340/83/01.webp" ; try { URL url = new URL (webpImageUrl); InputStream inputStream = url.openStream(); BufferedImage webpImage = ImageIO.read(inputStream); if (webpImage != null ) { int width = webpImage.getWidth(); int height = webpImage.getHeight(); Dimension imageSize = new Dimension (width, height); System.out.println("WebP 图片宽度:" + imageSize.width); System.out.println("WebP 图片高度:" + imageSize.height); } else { System.out.println("无法读取 WebP 图片。" ); } } catch (IOException e) { e.printStackTrace(); } }
原因
标准的 javax.imageio.ImageIO
不支持读取 WebP 格式的图片,ImageIO
支持读写的文件后缀:jpg
、bmp
、gif
、png
、wbmp
、jpeg
,通过以下代码可以查看:
1 2 System.out.println("ImageIO支读取的文件后缀:" + String.join("," , ImageIO.getReaderFileSuffixes())); System.out.println("ImageIO支持写入的文件后缀:" + String.join("," , ImageIO.getWriterFileSuffixes()));
解决方法
新增webp-imageio
三方扩展库依赖来支持webp后缀图片
1 2 3 4 5 6 7 <!-- https://mvnrepository.com/artifact/org.sejda.imageio/webp-imageio --> <dependency> <groupId>org.sejda.imageio</groupId> <artifactId>webp-imageio</artifactId> <version>0.1.6</version> </dependency>
6. Scheduled
定时任务没有按时执行
前提是排除没有开启定时任务@EnableScheduling
,能正常的执行定时任务的哈
代码参考 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class TestTask { @Scheduled(fixedDelay = 1000 * 60L) public void task1 () { System.out.println("task1" ); } @Scheduled(fixedDelay = 1000 * 60L) public void task2 () { System.out.println("task2" ); } @Scheduled(fixedDelay = 1000 * 60L) public void task3 () { System.out.println("task3" ); } ... }
原因
默认情况下,Spring的@Scheduled
注解是串行执行的,即任务是在单线程中执行的。如果上一次的任务还未完成,下一次任务将等待上一次任务完成后执行。在这个等待的过程中,如果首次任务的执行时间超过了1分钟,就会导致主线程第二次的任务重复执行;如果有多个定时任务时,时间挨得比较近,其中一个耗时比较长就会影响其他的定时任务,导致主线程第二次的任务迟迟不会执行
解决方法
方案1:将默认的Scheduled改为多线程的模式
1 2 3 4 5 6 7 8 9 10 11 @Configuration public class ScheduledConfig implements SchedulingConfigurer { @Override public void configureTasks (ScheduledTaskRegistrar taskRegistrar) { ThreadPoolExecutor executor = new ScheduledThreadPoolExecutor (15 , new CustomizableThreadFactory ("定时任务线程:" ), new ThreadPoolExecutor .CallerRunsPolicy()); taskRegistrar.setScheduler(executor); } }
方案2:开启异步调用@EnableAsync
,并使用@Async
注解开启异步操作,但是@Async
有安全隐患
1 2 3 4 5 6 public class TestTask { @Async @Scheduled(fixedDelay = 1000 * 60L) public void task1 () { System.out.println("task1" ); }
方案3:比较建议方案1
加上再加上方案3
一起,多线程+锁防止不同线程重复操作同一批数据,这里用Redisson
的锁做示范
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class TestTask { @Resource(name = "redissonClient") private RedissonClient redissonClient; @Scheduled(fixedDelay = 1000 * 60L) public void task1 () { RLock lock = redissonClient.getLock("taskLock" ); try { if (lock.tryLock()) { System.out.println("task1" ); } else { logger.info("Another instance is processing the task. Skip current execution." ); } } catch (Exception e) { e.printStackTrace(); logger.error("task | msg : " + e.getMessage()); } finally { lock.unlock(); } } }
7. stream.toList()的坑 代码参考 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 List<Long> ids = new ArrayList <>(); if (CollectionUtils.isNotEmpty(ids)) { List<OeChannelRuleSetting> oeChannelRuleSettings = oeChannelRuleSettingMapper.selectByAdvertiserIds(advertiserIds); adRuleIds = oeChannelRuleSettings.stream().map(OeChannelRuleSetting::getAdRuleId).toList(); } List<task> tasks=taskMapper.selectAll(ids); <select id="selectAll" resultMap="BaseResultMap" > select * from task <where> <if test="ids != null and ids.size() != 0" > and ad_rule_id in <foreach collection="ids" item="item" open="(" close=")" separator="," > #{item} </foreach> </if > </where> order by id desc </select>
报错参考 1 2 3 4 5 6 7 8 9 10 11 12 13 ### Error querying database. Cause: java.lang.reflect.InaccessibleObjectException: Unable to make public int java.util.ImmutableCollections$ListN.size() accessible: module java.base does not "opens java.util" to unnamed module @2df3b89c ### Cause: java.lang.reflect.InaccessibleObjectException: Unable to make public int java.util.ImmutableCollections$ListN.size() accessible: module java.base does not "opens java.util" to unnamed module @2df3b89c at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:96) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) at jdk.proxy2/jdk.proxy2.$Proxy84.selectList(Unknown Source) at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:147) at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:80) at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145) at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86) at jdk.proxy2/jdk.proxy2.$Proxy162.selectAll(Unknown Source) at com.maiyawx.put.service.batchput.oe.RuleTaskService.selectAll(TaskService.java:75) at com.maiyawx.put.service.batchput.oe.RuleTaskService$$FastClassBySpringCGLIB$$c5d93ce0.invoke(<generated>)
原因
在 Java 9 和以后的版本中,Collections.unmodifiableList()
返回的是一个不可变的 List
,它的实现类是 ImmutableCollections$ListN
,ImmutableCollections$ListN
类在反射方面有严格的访问控制。这个类并不允许通过反射访问其方法,因为它在模块系统中被标记为不可访问。在java.base
模块并没有将 java.util
包开放给外部模块,导致你的代码试图通过反射访问该类的 size()
等方法时抛出异常
解决方法 1 2 3 4 5 6 7 8 9 10 11 12 adRuleIds = oeChannelRuleSettings.stream() .map(OeChannelRuleSetting::getAdRuleId) .collect(Collectors.toList()); adRuleIds = new ArrayList <>(oeChannelRuleSettings.stream() .map(OeChannelRuleSetting::getAdRuleId) .toList()); adRuleIds = oeChannelRuleSettings.stream() .map(OeChannelRuleSetting::getAdRuleId) .collect(Collectors.toCollection(ArrayList::new ));
Mysql篇 1. 修改全文索引命中最小长度无效 SQL参考
查询漫画来源为manga
,并且comic_name
、comic_intro
、author_name
字段中包含Sta
的数据,若查询包含Stag
的数据则可以正常查询出来(前提:已经把索引的最小长度修改成功并重启服务,只是查询不命中)
1 2 3 4 5 6 7 8 9 SELECT * FROM comic WHERE comic_source = 'manga' AND MATCH ( comic_name, comic_intro, author_name ) AGAINST ( 'Sta' ); LIMIT 5
原因 由于Mysql的全文搜索默认是在自然MySQL的全文搜索默认在自然语言模式下工作,它可能会忽略某些单词,尤其是那些被认为是“常见”的或“不重要”的单词。即使你已经将innodb_ft_min_token_size’设置为1,Sta’这样的短词可能仍然被忽略。这是因为MySQL可能认为它是一个常见的词前缀
解决方法
使用布尔搜索模式,+
和*
不可忽略
1 2 3 4 5 6 7 8 9 SELECT * FROM comic WHERE comic_source = 'manga' AND MATCH (comic_name, comic_intro, author_name) AGAINST ('+Sta*' IN BOOLEAN MODE) LIMIT 5
完整流程
1、修改mysql根目录下的my.ini
配置文件,添加以下配置
1 2 3 4 5 [mysqld] ft_min_word_len =1 innodb_ft_min_token_size = 1
2、重启mysql服务
3、SQL查询修改是否生效,%
内换成对应存储引擎下的配置
1 SHOW GLOBAL VARIABLES LIKE '%min_token_size%'
4、新建Fulltext
全文索引,若已存在则需删除重建索引
需确保覆盖到要全文索引的字段
5、用布尔搜索模式
1 MATCH (comic_name, comic_intro, author_name) AGAINST ('+Sta*' IN BOOLEAN MODE)
2. order by
+limit
数据重复出现 SQL参考
前提:publish_at
没有任何索引,为了更直观的比较第一页跟第二页重复的数据可以用INTERSECT
关键字将两条sql所查询出来的数据做并集(只有当数据总量足够多的时候分页才可能会出现重复出现数据,而且INTERSECT
关键字得看具体Mysql版本)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #1.根据发布时间降序的第一页,每页30条数据 SELECT * FROM comic ORDER BY publish_at DESC LIMIT 30 #求两SQL并集的关键字 INTERSECT #2.根据发布时间降序的第二页,每页30条数据 SELECT * FROM comic ORDER BY publish_at DESC LIMIT 30 OFFSET 30
原因 order by
+limit
时Mysql会进行优化,使用的是内存中的filesort
文件排序,in memory filesort 使用的是优先级队列(priority queue),优先级队列使用的二叉堆。使用priority queue
的目的,就是在不能使用索引有序性的时候,如果要排序,并且使用了limit n,那么只需要在排序的过程中,保留n条记录即可这样虽然不能解决所有记录都需要排序的开销,但是只需要 sort buffer 少量的内存就可以完成排序。因此,在limit n时,只会堆排序前n个,且是不稳定排序,因此并不能保证字段值相同时的相对顺序,因此分页时可能造成重复;MySQL 5.5 没有这个优化,所以也就不会出现这个问题,5.6版本之后才出现了这种情况
官方描述 :如果多行在列中具有相同的值ORDER BY
,则服务器可以自由地以任何顺序返回这些行,并且可以根据整体执行计划以不同的方式返回这些行。换句话说,这些行的排序顺序相对于无序列来说是不确定的。影响执行计划的因素之一是 LIMIT
,因此ORDER BY
带有和不带有 的查询LIMIT
可能会以不同的顺序返回行。
解决方法
在ORDER BY
子句中包含其他列以使顺序具有确定性,例如id
为主键具有唯一性,又或者ORDER BY
的字段拥有索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #1.加入`id`字段确保顺序唯一 SELECT * FROM comic ORDER BY publish_at,id DESC LIMIT 30 OFFSET 30 #2.给`publish_at`字段上索引,利用索引的有序性 CREATE INDEX idx_publish_at ON comic (publish_at); SELECT * FROM comic ORDER BY publish_at DESC LIMIT 30 OFFSET 30;