置顶
- 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
- 添加下面插件依赖:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.3</version>
<configuration>
<generateBackupPoms>false</generateBackupPoms>
</configuration>
</plugin>
- 执行命令:
mvn versions:set -DnewVersion=1.0.7
使用HttpURLConnection和使用HttpClient的请求gzip编码的资源
marked at Alibaba 2021-12-30
Accept-Encoding、Content-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
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>