JPA
- parallelStream 调用 manyToMany 清除关联关系无效
@Transactional(readOnly = true)
public void clearAuthorBooks() {
List<Long> ids = new ArrayList<>(2);
ids.add(1L);
ids.add(2L);
ids.parallelStream().forEach(this::newTransaction);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void newTransaction(Long id) {
authorRepository.findById(id).ifPresent(author -> author.getBooks().clear());
}
这里使用基于注解的 Spring 事物,Spring 中大量使用基于代理的模式来处理方法调用,如果被代理对象实现了接口则使用 JDK 动态代理
,未实现接口则使用 CGLIB 代理
,通过代理在方法调用时获取注解进行事物处理,实际在方法处理中会使用 AOP 切面编程来处理不同切入点的事件,具体的两个实现类为 CglibAopProxy
和 JdkDynamicAopProxy
,切面的不同切入点 advice
又维护一系列的拦截方法 MethodInterceptor
,通过方法调用时适合的拦截器会开始工作,比如我们这里的 TransactionInterceptor
会为方法调用包裹事物。
为什么并行流中的操作未其作用?原因在与并行流中的操作会使用 Fork/Join
被 ForkJoinTask
来执行,而该对象并没有受 Spring 代理的控制,所以在其中的方法调用并不会受注解的作用,即使我们声明了需要开启新事物。
更好的方法是使用手动事物:
public void clearAuthorBooks() {
List<Long> ids = new ArrayList<>(2);
ids.add(1L);
ids.add(2L);
ids.parallelStream().forEach(this::newTransaction);
}
public void newTransaction(Long id) {
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
authorRepository.findById(id).ifPresent(author -> author.getBooks().clear());
}
}
}
- Java11 集成 querydsl 报 javax.annotation.api not found
For those who are still fighting with the issue and when all proposed workarounds don’t work, here is what helped me (Java 11):
// querydsl
annotationProcessor 'com.querydsl:querydsl-apt:4.1.3:jpa'
annotationProcessor 'org.springframework.boot:spring-boot-starter-data-jpa' // needed because the query dsl annotation processor doesn't recognize javax.persistence.Entity
compile 'com.querydsl:querydsl-jpa:4.1.3'
Taken from https://stackoverflow.com/questions/50537096/annotationprocessor-and-dependencies
This combination taken from #2459 (comment) also works:
configure(querydslProjects) {
apply plugin: "io.spring.dependency-management"
dependencies {
compile("com.querydsl:querydsl-core")
compile("com.querydsl:querydsl-jpa")
// I guess if you need another annotation processor just change jpa to whatever you want.
annotationProcessor("com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa")
annotationProcessor("jakarta.persistence:jakarta.persistence-api")
annotationProcessor("jakarta.annotation:jakarta.annotation-api")
}
- No _valueDeserializer assigned
如果不是序列化时循环依赖,则在对应报错的 OneToMany 集合的 @JsonIgnoreProperties
注解上加上 allowSetters = true
。
相关问题:https://github.com/jhipster/generator-jhipster/issues/10743
Docker
Devops
- Jar 包加载 ClassPath 下的文件报找不到文件
JAR 代表 Java ARchive - 归档,它是一种包文件格式,通常用于将许多 Java 类文件和关联的元数据和资源聚合到一个文件中以进行分发。JAR 文件是包含 Java 特定清单文件的存档文件。它们以 ZIP 格式构建,通常具有 .jar 文件扩展名。
当我们使用 Spring 的 ClassPathResource("files/filename")
访问文件资源时,正常开发的情况下文件位于系统文件系统中,可以正常访问;当打成 JAR 包发布访问时,由于处在 JAR 特殊的 ZIP 包中,调用 getFile
将抛出错误,因为它不属于文件系统的文件。
虽然不能直接获取文件,但是还是可以通过类加载器访问到文件流或者 URL,getInputStream()
或 getURL
。
Java
- Collectors.toMap valueMapper 为 null 导致 NPE
Collectors.toMap 的 keyMapper 和 valueMapper 都不允许为 null,不管实际提供的 Map 实现是否支持 null。
它在内部使用 Map.merge,这是 JDK 的一个 open bug。
可以使用下面的写法收集流或者原始的写法:
Map<Integer, Boolean> collect = list.stream()
.collect(HashMap::new, (m,v) -> m.put(v.getId(), v.getAnswer()), HashMap::putAll);