为什么要进行数据库版本控制?
假设我们有一个名为 Shiny 的项目,其主要交付项目是一个名为 Shiny Soft 的软件,该软件连接到名为 Shiny DB 的数据库。
最简单的图可能看起来像这样:
在 Github 上我们经常看到提交记录里有各种图标,如 🎨⚡️🍎 等,是如何实现的呢?
在 Web 开发中,静态资源的访问是必不可少的,如:图片、JS、CSS 等资源的访问。
Spring Boot 对静态资源访问提供了很好的支持,基本使用默认配置就能满足开发需求。
Spring Boot 默认将 /** 所有访问映射到静态资源目录。
1 | /static |
举例:我们可以在 src/main/resources/ 目录下创建目录 static,在该位置创建一个 demo.txt 文件,内容为 Hello world 。启动程序后,尝试访问 http://localhost:8080/demo.txt 。如能显示 Hello world,则配置成功。
我们都知道 Maven 本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有 这些任务都交给插件来完成,例如编译源代码是由 maven- compiler-plugin
完成的。进一步说,每个任务对应了一个插件目标(goal),每个插件会有一个或者多个目标,例如 maven- compiler-plugin
的 compile 目标用来编译位于src/main/java/
目录下的主源码,testCompile 目标用来编译位于src/test/java/
目录下的测试源码。
用户可以通过两种方式调用 Maven 插件目标。第一种方式是将插件目标与生命周期阶段(lifecycle phase)绑定,这样用户在命令行只是输入生命周期阶段而已,例如 Maven 默认将 maven-compiler-plugin 的 compile 目标与 compile 生命周期阶段绑定,因此命令 mvn compile 实际上是先定位到 compile 这一生命周期阶段,然后再根据绑定关系调用 maven-compiler-plugin 的 compile 目标。第二种方式是直接在命令行指定要执行的插件目标,例如 mvn archetype:generate 就表示调用 maven-archetype-plugin 的 generate 目标,这种带冒号的调用方式与生命周期无关。
(1)在代码进入同步块的时候,如果同步对象锁状态为无锁状态(锁标志位为“01”状态,是否为偏向锁为“0”),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝,官方称之为 Displaced Mark Word。这时候线程堆栈与对象头的状态如图2.1所示。
(2)拷贝对象头中的Mark Word复制到锁记录中。
(3)拷贝成功后,虚拟机将使用CAS操作尝试将对象的Mark Word更新为指向Lock Record的指针,并将Lock record里的owner指针指向object mark word。如果更新成功,则执行步骤(4),否则执行步骤(5)。
(4)如果这个更新动作成功了,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位设置为“00”,即表示此对象处于轻量级锁定状态,这时候线程堆栈与对象头的状态如图2.2所示。
(5)如果这个更新操作失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果是就说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步块继续执行。否则说明多个线程竞争锁,轻量级锁就要膨胀为重量级锁,锁标志的状态值变为“10”,Mark Word中存储的就是指向重量级锁(互斥量)的指针,后面等待锁的线程也要进入阻塞状态。 而当前线程便尝试使用自旋来获取锁,自旋就是为了不让线程阻塞,而采用循环去获取锁的过程。
在 Hotspot
虚拟机中,对象在内存中的布局分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding);
从上面的这张图里面可以看出,对象在内存中的结构主要包含以下几个部分: