Java程序猿搬砖笔记(十)

作为码农平时搜集一些小知识点个人认为是个不错的习惯,书上说

好记性不如烂笔头

我想即使是以前忽略或者新get的很简单的东西,自己动手记下来不管如何印象也会更深刻。

synchronized锁定的对象

synchronized修饰的作用:
让多个线程排队依次获取某个资源,保证数据不会出错(原子性)。
synchronized锁定的元素:

  • 修饰方法
    • 静态方法,锁定的是类
    • 普通方法,锁定的时方法的调用者
  • 修饰代码块,锁定的时传入的对象

Java线程内存模型(JMM)定义的8中原子操作

  • read(读取):从主内存中读取数据
  • load(载入):将主内存读取到的数据写入工作内存
  • use(使用):从工作内存读取数据来计算
  • assgin(赋值):将计算好的值重新赋值到工作内存中
  • store(存储):将工作内存数据写入主内存,会经过总线,到总线后就开始广播其他线程
  • write(写入):将store过去的变量值赋值给主内存中的变量
  • lock(锁定):将主内存变量加锁,标识为线程独占状态
  • unlock(解锁):将主内存变量解锁,解锁后其他线程可以锁定该变量
    MESI缓存一致性协议:
    多个cpu从主内存读取同一个数据到各自的高速缓存,当其中某个cpu修改了缓存里的数据,该数据会马上同步回主内存,其他cpu通过总线嗅探机制可以感知到数据的变化从而将自己缓存里的数据失效。
    一般lock锁加在线程的赋值之后,存储之前,这样的锁的粒度不大。volatile保证数据可见性、synchronized保证原子性。

MySQL分区学习

参考链接参考链接参考链接

根据hash中的键模糊删除

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
27
28
/**
* 根据hash中的键模糊删除
* @param key key redis的key
* @param item item hash的键
*/
public void removeHashItem(String key, String item){

ArrayList<String> items = new ArrayList<>();
// 模糊查询出准确的item
redisTemplate.execute(new RedisCallback() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
Cursor<Map.Entry<byte[], byte[]>> entryCursor = connection.hScan(key.getBytes(), ScanOptions.scanOptions().match("*" + item + "*").count(1800).build());
while(entryCursor.hasNext()){
Map.Entry<byte[], byte[]> next = entryCursor.next();
String key = new String(next.getKey());
// 将查询出的item放入list
items.add(key);
}
connection.close();
return null;
}
});
// 批量删除对应key中的item
for (String str: items){
redisTemplate.opsForHash().delete(key, str);
}
}

union和ordery by一起使用报"Incorrect usage of UNION and ORDER BY"错误的解决方法

原因

每条字句都使用order by会报错。

解决方法

方法一:只在最后一条字句使用order by,意思是对整个结果集进行order by
参考代码如下:

1
2
3
4
select * from t1 where username like 'l%'
union
select * from t1 where username like '%m%'
order by score asc

方法二:union后整体改为临时表
参考代码如下:

1
2
3
4
5
select * from 
(select * from t1 where username like 'l%'
union
select * from t1 where username like '%m%')tmp
order by tmp.score asc

方法三:每一层都改为临时表再union

1
2
3
4
select * from (select * from t1 where username like 'l%') t1
union
select * from (select * from t1 where username like '%m%') t2
order by score asc

参考链接

Spring Cloud Config多服务共享公共配置

参考代码:

1
2
3
4
5
6
7
8
9
10
11
spring:
application:
name: innovation
cloud:
config:
name: reward-innovation-v1,common
profile: test
uri: http://10.12.7.124:8888
failFast: true
enabled: true
main.allow-bean-definition-overriding: true

该代码读取配置中心的common-test.yml和reward-innovation-v1-test.yml文件

参考链接

解决SpringBoot启动报错:NoClassDefFoundError: org/springframework/data/redis/connection/RedisStreamCommands

查重管理的时候,在测试环境碰到一模一样的问题。

参考链接

查看Java进程当前使用的JVM参数

1、jps命令查看当前进程id

1
2
3
4
[award_dev@localhost reward_taskjob]$ jps -l
32496 reward-taskjob-202209151113-SNAPSHOT.jar
4931 award-webbas-config-2022-08-29-122959.jar
3187 reward-innovation-202209172040-SNAPSHOT.jar

2、jinfo -flags 进程id 命令查看当前进程使用的JVM参数

1
2
3
4
5
6
7
[award_dev@localhost reward_taskjob]$ jinfo -flags 32496
Attaching to process ID 32496, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13
Non-default VM flags: -XX:CICompilerCount=12 -XX:ConcGCThreads=3 -XX:G1HeapRegionSize=1048576 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=null -XX:InitialHeapSize=1289748480 -XX:MarkStackSize=4194304 -XX:MaxHeapSize=2147483648 -XX:MaxNewSize=1287651328 -XX:MinHeapDeltaBytes=1048576 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseG1GC
Command line: -Dlog4j2.formatMsgNoLookups=true -DENV_CONFIG_IP=10.12.7.181 -DENV_CONFIG_PORT=9888 -DENV_TYPE=dev -Dname=reward-taskjob-202209151113-SNAPSHOT.jar -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Duser.timezone=Asia/Shanghai -Djava.io.tmpdir=/opt/aspire/product/award_dev/reward_taskjob/data/tmp -Xms1230m -Xmx2g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./logs/java_heapdump.hprof -XX:+PrintGCDateStamps -Xloggc:/opt/aspire/product/award_dev/reward_taskjob/logs/gclog/gc-reward-taskjob-202209151113-SNAPSHOT.jar-20220919102315.log -XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+UseG1GC

RestTemplate使用Ribbon实现负载均衡的调用

1
2
3
4
5
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}

直接通过服务名调用,Eureka会去找。

1
restTemplate.postForObject("http://webbas32-manage-v1/web/login/findemployeebyphone", formEntity, String.class);

其中webbas32-manage-v1为接口提供方的服务名
调用方的Eureka配置需要添加,fetchRegistry: true //表示可以从Eureka Server获取注册的服务信息

RestTemplate.postForObject泛型丢失(返回LinkedHashMap)的问题解决方法

问题:
在这里插入图片描述
如上图所示,data类型本应该为MemberInfoVo,但是泛型丢失变为LinkedHashMap。

解决方法:
参考代码如下:

1
2
3
ParameterizedTypeReference<ResponseMsg<MemberInfoVo>> typeRef = new ParameterizedTypeReference<ResponseMsg<MemberInfoVo>>() {};
ResponseEntity<ResponseMsg<MemberInfoVo>> result = restTemplate.exchange(findEmployeeUrl, HttpMethod.POST, formEntity, typeRef);
ResponseMsg<MemberInfoVo> responseMsg = result.getBody();

成功效果:
在这里插入图片描述
参考链接

MyBatis批量更新

参考链接

Spring Cloud Eureka自我保护机制

参考链接

Spring Cloud Eureka控制台相关配置参数学习

参考链接

SpringBoot配置默认sql级别info、sql打印级别为debug

SpringBoot的默认使用的日志框架为logback,且默认的日志级别均为INFO。
为了打印sql日志信息,我们只需把对应dao层包下的日志级别改为DEBUG。

示例代码如下:

1
2
3
4
5
6
7
8
9
10
# log  
logging:
config: classpath:log4j2-dev.xml
level:
root: info
# dao层包下的日志级别修改
com:
aspirecn:
rewardmanagement:
mapper: debug

参考链接

IDEA解决完所有冲突但是分支还是在Merging状态的解决方法

1、通过git status命令查看信息(关键):
All conflicts fixed but you are still merging(use “git commit” to conclude merge)
2、根据第一步的信息提示做操作
示例操作如下:

1
2
git add -A
git commit -m '合并master'

参考链接

SpringBoot中使用@Value读取配置文件中的list、map

配置文件代码:

1
2
myList: item1,item2,item3
myMap: "{key1: 'value1', key2: 'value2'}"

Java代码:

1
2
3
4
5
@Value("#{'${myList}'.split(',')}")
private List<String> myList;

@Value("#{${myMap}}")
private Map<String,String> myMap;

注意:
上面的list配置中,一定不要用""把list所有的成员value包起来,要不然解析报错。
上面的map配置中,一定要用"" 把map所对应的value包起来,要不然解析解析报错。

参考链接

SpringBoot中多个@ControllerAdvice全局异常处理

多个ControllerAdvice,优先级由@Order决定,order的数值越小 则优先级越高。

1
2
3
4
5
6
7
8
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MsControllerAdvice {

}

注意:@ControllerAdvice只能对controller抛出的异常处理

多个@ControllerAdvice全局异常处理(含多个实用场景)
@ControllerAdvice优先级设定

SpringCloud zuul路由手动配置

示例代码:

1
2
3
4
5
6
7
8
zuul:
routes:
api-a:
path: /api-a/**
serviceId: service-ribbon
api-b:
path: /api-b/**
serviceId: service-feign

zuul路由配置说明:api-a、api-b是路由名称可以随便取,serviceId是服务的id(对应spring.application.name)。
上面配置表示,以/api-a/ 开头的请求都转发给service-ribbon服务;以/api-b/开头的请求都转发给service-feign服务。

SpringCloud zuul的路由默认自动配置

zuul可以自动根据Eureka服务器中所注册的服务自动完成路由映射、负载均衡。
在Eureka上注册了两个服务:
1、服务名management,端口18081
2、服务名gateway,端口7001
请求路径,127.0.0.1:7001/management/addressBook/getList,网关zuul会把请求转发给management服务,
实际请求路径127.0.0.1:18081/addressBook/getList

参考链接

dependencyManagement标签的作用

在Maven中dependencyManagement的作用其实相当于一个对所依赖jar包进行版本管理的管理器。
jar的版本判断的两种途径:

  • 如果dependencies里的dependency自己没有声明version元素,那么maven就会到dependencyManagement里面去找有没有对该artifactId和groupId进行过版本声明。如果有,就继承它,如果没有就会报错,告诉你必须为dependency声明一个version。
  • 如果dependencies中的dependency声明了version,那么无论dependencyManagement中有无对该jar的version声明,都以dependency里的version为准。

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--只是对版本进行管理,不会实际引入jar  -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.7</version>
</dependency>
</dependencies>
</dependencyManagement>

<!--会实际下载jar包 -->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
</dependencies>

参考链接