数据库事务机制
ACID原则
事务机制遵循ACID原则:
Atomicity
原子性:事务是一个原子操作,由一系列操作组成。事务的原子性确保所有操作要么完成,要么完全不起作用(完整性)。Consistency
一致性:事务执行前后,系统必须确保它所建模的业务处于一致的状态。例如转账,无论事务是否成功,转账者和收款人的总额应该不变。Isolation
隔离性:并发操作相同的数据时,各事务之间相互独立。(但难免会存在冲突)Durability
持久性:一旦事务完成,它对数据的改变是持久的,即使数据库发生故障也不影响持久性。
只有保证了事务的持久性、原子性、隔离性之后,一致性才能得到保障(A、I、D是手段,C是目的)。
Java虚拟机 JVM
JVM启动入口:JLI_Launch
函数
以OPENJDK8源码GitHub - openjdk/jdk at jdk8-b120为例,虚拟机的启动入口在jdk/src/share/bin/java.c
的JLI_Launch
函数,整个流程分为:
- 配置JVM装载环境
- 解析虚拟机参数
- 设置线程栈大小
- 执行
JavaMain
方法
HTTP请求出现HttpMediaTypeNotAcceptableException报错
现象
发起HTTP请求调用,控制台报错:
org.springframework.web.HttpMediaTypeNotAcceptableException: No acceptable representation
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:322) ~[spring-webmvc-6.1.10.jar:6.1.10]
利用函数式接口剥离事务操作
任何接口,如果只包含一个抽象方法,它就是一个函数式接口。对于函数式接口,可以通过Lambda表达式来创建该接口的对象
Runnable就是一个函数式接口。
- 新建一个函数式接口,并在抽象方法上加上
@Transactional
的事务注解。 - 在实际业务逻辑中需要事务的地方,通过Lambda表达式创建该接口的对象(必须实现唯一的抽象方法)。
- 执行该接口对象的方法,即将方法内的逻辑以事务的形式去执行。
spring事务的依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
public class Test {
public void testTransaction() {
int a = 0;
int b = 1;
TransactionConsumer transactionConsumer = () -> {
insertDataA(a);
updateDataB(b);
};
transactionConsumer.doInTransaction();
}
private void updateDataB(int b) {
}
private void insertDataA(int a) {
}
}
@FunctionalInterface
public interface TransactionConsumer {
@Transactional
void doInTransaction();
}
Lombok
Lombok介绍
Lombok 项目其实就是一个 java 库,它可以自动插入到编辑器和构建工具中,增强 java 的性能。以后你 只需要一些简单的注解,就可以再也不用在类中反复去写 getter、equals 等方法,让代码变得简介,不用过多地去关注相应的方法。属性修改时,也简化了维护这些属性所生成的 get、set 方法。
使用方式:
IDEA 下载 Lombok 插件
项目中导入 Lombok 的 jar 包
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
- 在 实体类 上使用 Lombok 注解
Optional的使用
Optional 被设计出来,主要是为了解决空指针异常。
以一个 Student 类为例:
@Getter
class Student {
private String name;
private int age;
private int score;
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
public Student() {
}
}
分布式事务
PriorityQueue与Comparator
PriorityQueue的使用场景
Queue<Integer> queue1 = new PriorityQueue<>();
Queue<Integer> queue2 = new PriorityQueue<>(Comparator.comparingInt(o -> o));
Queue<Integer> queue3 = new PriorityQueue<>(Comparator.comparingInt(o -> -o));
Java中的PriorityQueue常用于实现小顶堆、大顶堆。由上述代码可见,通常有默认无参构造函数、传入Comparator对象等方式的实现。
困惑
从构造函数层面,完全不清楚默认构造函数的排序规则,也完全不明白Comparator实现的comparingInt方法对应的排序规则。
根据网上绝大多数文章的描述,都没有解释或者只是说明了对应的排序规则,但是不知道为什么是对应升序或降序。通过阅读源码,才得到准确的认知。