李氏老方-工作遇到的问题以及解决方案汇总

置顶

  • Spring @Transactional 事务无法生效的情况
  • Spring @Transactional 事务代理创建的原理
  • 多层代理能否被再次代理?
  • Mybatis中的TypeHandler
  • 对线程池maxSize的理解:什么时候线程池会增加worker的数量?
  • 线程池中,RejectedExecutionHandler的一个实现方案:CallerRunsPolicy的实际应用中的思考
  • 对于分布式锁的思考
依赖冲突导致NoSuchMethodErro,引发的对try-catch对的思考

marked at Alibaba 2022-01-04

Error是直接继承自Throwable,如果我们使用try-catch时,未进行Error的捕获,可能会出现丢失的情况。最保险的情况是直接进行Throwable的捕获,尤其是在事务中时。

try {} catch (Throwable e) {}
JDK引发的bug:sun.awt.FontConfiguration.getVersion NullPointerException

marked at Alibaba 2022-01-04

环境:docker-centos环境、jdk 1.8

场景:使用EasyExcel、https://github.com/adoptium/temurin-build/issues/693

解决方案:系统安装字体依赖:yum install -y dejavu-sans-fonts freetype freetype-devel fontconfig fontconfig-devel

如何优雅地设置多模块项目的版本号

marked at Alibaba 2022-01-04

  1. 添加下面插件依赖:
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>versions-maven-plugin</artifactId>
    <version>2.3</version>
    <configuration>
        <generateBackupPoms>false</generateBackupPoms>
    </configuration>
</plugin>
  1. 执行命令:mvn versions:set -DnewVersion=1.0.7
使用HttpURLConnection和使用HttpClient的请求gzip编码的资源

marked at Alibaba 2021-12-30

Accept-EncodingContent-Encoding,前者表示支持的编码的格式,后者表示响应的内容的会以某种压缩算法进行编码传输。

假设存在下面的Http服务:

<dependency>
  <groupId>com.sparkjava</groupId>
  <artifactId>spark-core</artifactId>
  <version>2.9.3</version>
</dependency>
public class SparkServerDemo {
    public static void main(String[] args) {
        Spark.port(8080);
        Spark.get("/get", (req, resp) -> {
            resp.header("Content-Encoding", "gzip");
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            GZIPOutputStream outputStream = new GZIPOutputStream(byteArrayOutputStream);
            outputStream.write("12345678".getBytes(StandardCharsets.UTF_8));
            outputStream.finish();
            return byteArrayOutputStream.toByteArray();
        });
    }
}

我们首先设置响应头的编码格式为gzip,告知客户端内容通过Gzip进行编码。

访问地址为:http://localhost:8080/get

在客户端分别使用下面代码进行请求:

public class HttpProcessDemo {

    public static void main(String[] args) throws Exception {
        /*
        1. HttpConnection.
         */
        String testUrl = "http://localhost:8080/get";
        HttpURLConnection urlConnection = (HttpURLConnection) new URL(testUrl).openConnection();
        // 设置超时时间
        urlConnection.setReadTimeout(10_000);
        urlConnection.setConnectTimeout(10_000);
        InputStream in = urlConnection.getInputStream();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        StreamUtils.copy(in, outputStream);
        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        // [3426153����]
        System.out.println(IOUtils.readLines(inputStream, StandardCharsets.UTF_8.name()));
        inputStream.reset();
        GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream);
        // [12345678]
        System.out.println(IOUtils.readLines(gzipInputStream, StandardCharsets.UTF_8.name()));


        /*
        2. HttpClient.
         */
        HttpClient httpClient = HttpClientBuilder.create().build();
        HttpGet get = new HttpGet(testUrl);
        // 客户端支持的编码类型.
        get.addHeader("Accept-Encoding", "*");
        HttpResponse httpResponse = httpClient.execute(get);
        // [12345678]
        System.out.println(IOUtils.readLines(httpResponse.getEntity().getContent(), StandardCharsets.UTF_8.name()));

    }
}
线程池中,RejectedExecutionHandler的一个实现方案:CallerRunsPolicy在实际应用中的思考

marked at Alibaba 2021-12-29

  • 使用ThreadLocal变量值被清除的’诡异现象’
public static void threadLocalProblem() throws InterruptedException {
  ThreadPoolExecutor exec = new ThreadPoolExecutor(2, 2, 2, TimeUnit.DAYS, new LinkedBlockingDeque<>(1), new BasicThreadFactory.Builder().namingPattern("DEMO-%s").build(), new ThreadPoolExecutor.CallerRunsPolicy());
  ThreadLocal<String> local = new ThreadLocal<>();
  String val = "TEST";
  local.set(val);
  for (int i = 0; i < 5; ++i) {
    int finalI = i;
    TimeUnit.MILLISECONDS.sleep(100);
    exec.submit(() -> {
      try {
        local.set(val);
        TimeUnit.SECONDS.sleep(finalI);
      } catch (InterruptedException ignored) {
      } finally {
        local.remove();
      }
    });
  }
  exec.shutdown();
  // null
  System.out.printf("final val: %s%n", local.get());
}

最后输出的结果为null,造成这种结果的原因是因为当任务队列填满之后,使用的是当前线程进行调用,此时执行任务将会将当前线程的ThreadLocal的值清除,导致结果为null

  • 队列过小导致线程池效率低下的问题
    在这里插入图片描述

从图中可以看到因为主线程执行任务,导致无法继续提交任务至线程池,导致线程池的线程处于空闲状态。

MySQL left join on的携带条件

marked at Alibaba 2021-12-29

select * from A left join B on A.id = B.join_id and A.id = 100;

在上述sql中,A.id = 100这个条件能生效嘛?答案是否定的。A作为驱动表是一定会加载所有数据的,所以on后面的条件无法对结果集进行过滤

Idea如何打上条件断点

marked at Alibaba 2021-12-29

双击断点即会出现下图所示窗口,我们只需要在condition上键入我们的条件表达式即可

在这里插入图片描述

在Spring环境中,Mybatis如何显示debug日志(可以显示sql和传入的参数值)?

marked at Alibaba 2021-12-29

logging.level.{mapper所在的包路径} = DEBUG

配置Key为即以logger.level.为前缀,追加对应的Mapper包路径即可

Mybatis如何使用枚举类型?

marked at Alibaba 2021-12-29

条件中使用枚举
'param = @com.kuaikan.ads.common.biz.enums.Granularity@DAY.getCode()'
占位符中使用枚举
${@com.kuaikan.ads.common.biz.enums.Granularity@DAY.getCode()}
CPU打满问题排查
Json序列化、反序列化大对象打满CPU

marked at Alibaba 2021-09-21

1、查看机器维度的CPU占比、负载

2、JVM仪表盘:堆内存占用升高、Full GC次数突增

Note:内存占用过高导致磁盘IO次数增加的原因:交换内存的使用

JVM的跨平台特性

1、跨平台是指“一次编译,到处运行”;

2、大多数JVM比如Hotspot是通过C++实现的,编译时需要考虑系统、硬件架构等,所以JVM本身不具有跨平台的特性,但JVM为Java提供了语言上跨平台的特性;

3、Java通过编译生成字节码,JVM通过解释字节码映射成操作系统 或者 CPU指令实现;

4、JVM提供了跨平台的特性,但并不是所有的Java特性都支持跨平台,比如JNI/JNA;

设置导出文件名

marked at kuaikan 2021-06-01

response.setHeader("Content-Disposition", String.format("attachment; filename=%s", URLEncoder.encode(fileName, StandardCharsets.UTF_8.name())));

注意这里需要做URLEncode,主要针对一些HTTP的特殊字符或者中文进行处理

Safari导出文件名未对URLEncode进行解码

marked at kuaikan 2021-06-01

String urlEncodedPart = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()));
response.setHeader("Content-Disposition", String.format("attachment; filename=%s; filename*=UTF-8''%s", urlEncodedPart, urlEncodedPart);

markdown返回问题

marked at kuaikan 2020-12-04

服务的URLEncode和前端不太一样,对于+是需要进行处理的,否则会被当成空格处理。

URI.encodeURI和URI.encodeURIComponent

marked at kuaikan 2020-12-04

MDN URI Api

Git produces “BUG: There are unmerged index entries”

marked at kuaikan 2020-12-28

git merge --no-ff -s recursive -X no-renames <branchToMerge>

解决冲突即可,解决问题的链接

实现文件服务需要考虑的问题

简单实现就是直接使用POST请求携带文件字节流,出现接收到字节流之后进行落盘,但是服务端一般是集群模式,前端到达服务端需要通过nginx反向代理,文件过大可能导致nginx出现413 Request Entity too large。

大文件可以将其切割成很多个小文件,每次请求只携带一个小文件,那如何确认哪些小文件归属于一个文件呢?通过类似于事务的操作。前端在请求文件上传前,先调用某个接口开启一个事务,服务端会开启一个事务文件夹,后续前端所有携带该事务id的分片都将会落到该文件夹(同步写文件),前端完成上传之后,调用某个接口结束事务,服务端进行文件的合并,所有操作同步进行。

可以在初始化事务的时候,让前端携带文件大小以及分块大小,方便服务端进行文件校验。

如何进行文件续传?前端可以携带某个事务ID检查传输情况,服务端会下发缺失的部分。

前端分片大小如何进行设置?超时时间怎么进行设置?服务端(Tomcat)的连接超时时间怎么设置?

文件存储的高可用如何进行实现?FastDSF、HDFS,对象存储是如何进行实现的

Maven Surefire Test AssertException

marked at kuaikan 2020-12-05

出现如下现象:

Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.19.1:test (default-test) on project kk-ad-budget-serice: ExecutionException There was an error in the forked process
java.lang.AssertionError: Couldn't find resource: jquery.min.js
at org.testng.reporters.jq.Main.generateReport(Main.java:92)
at org.testng.TestNG.generateReports(TestNG.java:1093)
at org.testng.TestNG.run(TestNG.java:1036)
at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:132)
at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.executeSingleClass(TestNGDirectoryTestSuite.java:112)
at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:99)
at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:147)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:290)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:242)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:121

原因是jar包和项目下没有资源文件:/META-INF/resources/webjars/jquery/3.5.1/jquery.min.js

解决方案有两种:

方案一:排除包

<exclusion>
	<artifactId>testng</artifactId>
	<groupId>org.testng</groupId>
</exclusion>

方案二:项目资源目录上添加空文件

/META-INF/resources/webjars/jquery/3.5.1/jquery.min.js

Chrome错误net::ERR_CONNECTION_TIME_OUT

marked at kuaikan 2021-01-27

在请求网络的时候出现网络超时错误,在遇到这种情况时,尝试ping域名对应的ip

1、检查域名访问:外网域名、内网域名
2、检查uri访问

Nginx配置跨域

marked at kuaikan 2021-01-27

location / {
    add_header Access-Control-Allow-Origin ""https://example.com;
}

Access-Control-Expose-Headers:哪些响应的首部可以被访问

H2单测出现奇怪的语法错误

marked at kuaikan 2021-02-14

  • 尝试删除ON UPDATE CURRENT_TIMESTAMP
  • 尝试删除创建表语句的comment

Java解压Zip MALFORMED异常

marked at kuaikan 2021-03-01

java.lang.IllegalArgumentException:MALFORMED at java.util.zip.ZipCoder.toString(ZipCoder.toString:58)

1、初步猜想是:zip格式错误,使用maczip尝试解压,ok

2、写Demo使用ZipInputStream进行解压,出现异常

3、搜索得知可能是编码导致的问题,将编码更换成gbk,ok

MyBatis Mapper Xml中使用枚举进行比较导致的异常

marked at kuaikan 2021-04-01

<if test="aggByAdDate">
    <choose>
        <when test="granularity == @com.kuaikan.ads.common.biz.enums.Granularity@DAY">
            DATE(record_time),
        </when>
        <when test="granularity == @com.kuaikan.ads.common.biz.enums.Granularity@HOUR">
            DATE_FORMAT(record_time,'%Y-%m-%d %H'),
        </when>
        <otherwise>
            record_time,
        </otherwise>
    </choose>
</if>
@Getter
@AllArgsConstructor
public enum Granularity implements EnumBase {
    /**
     * 时间粒度.
     */
    DAY(1, "天级") {
        @Override
        public LocalDateTime truncate(LocalDateTime dateTime) {
            return dateTime.truncatedTo(ChronoUnit.DAYS);
        }

        @Override
        public LocalDateTime plus(LocalDateTime dateTime, int delta) {
            return dateTime.plusDays(delta);
        }
    }   
}

上面MyBatis的mapper xml定义会出现下面的异常:

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.IllegalArgumentException: invalid comparison: com.kuaikan.ads.common.biz.enums.Granularity$3 and com.kuaikan.ads.common.biz.enums.Granularity$1
### Cause: java.lang.IllegalArgumentException: invalid comparison: com.kuaikan.ads.common.biz.enums.Granularity$3 and com.kuaikan.ads.common.biz.enums.Granularity$1

该问题重要考虑这两点:

1、考虑到是否为依赖包版本的问题,导致类型不兼容的问题

2、在相应的堆栈打上断点,查看具体的值和类型

采取相关措施进行排查和解决:

1、回退之前的版本是可以成功执行

2、对比现今版本,主要是枚举在声明时进行了方法重写。

3、在相应的堆栈打上断点,查看具体的值和类型。

结果:两个枚举的值的类型不一致,导致Ognl无法进行比较。

4、为什么会出现类型不一致呢?

枚举重写方法时,会生成相应的匿名类,导致每个枚举的类型和原类型不一致,从而导致比较时出现不兼容的现象

解决:

<if test="aggByAdDate">
    <choose>
        <when test="granularity.code == @com.kuaikan.ads.common.biz.enums.Granularity@DAY.getCode()">
            DATE(record_time),
        </when>
        <when test="granularity.code == @com.kuaikan.ads.common.biz.enums.Granularity@HOUR.getCode()">
            DATE_FORMAT(record_time,'%Y-%m-%d %H'),
        </when>
        <otherwise>
            record_time,
        </otherwise>
    </choose>
</if>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木子的木木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值