那么倔强的石头

那么倔强的石头 查看完整档案

成都编辑西华大学  |  计算机科学与技术 编辑互联网医疗  |  软件工程师 编辑 juejin.im/user/1881992245286237 编辑
编辑

业精于勤荒于嬉,行成于思毁于随

个人动态

那么倔强的石头 发布了文章 · 1月6日

【器篇】【缓存】一个轻量的缓存实现方式

一、引言来

系统中时常要对外暴露一些特殊数据,这些数据存储于关系型数据库中,且显著的特征是:

  • 数据请求频繁
  • 数据变动很小
  • 数据体量略大

数据请求频繁,说明要频繁的与数据库产生交互,占用与数据库的会话资源。而且数据量体量略大,又需要大量使用数据传输过程的通道。数据变动很小,说数据几乎是静态数据。
一般来说,遇到这样的场景我们会想到上缓存,例如RedisMemcachedCaffeine。但是本着能不引入,简单最好的原则,我便尝试使用Java的静态变量实现了一个简易的“缓存”。

二、实现来

具体实现如下代码,过程中使用了staticAtomicReferenceSoftReference

public class DictService {

    static final AtomicReference<SoftReference<DictRegionDTO>> regionCache = new AtomicReference<>();
    
    /**
     * fetch all of region
     * @return region all
     */
    public Optional<DictRegionDTO>  fetchRegion(){
        if(regionCache.get() !=null && regionCache.get().get() !=null ){
            return Optional.ofNullable(regionCache.get().get());
        }
        
        //todo fetch by repository,return @NotNull value
        
        final DictRegionDTO dictRegionDTO = new DictRegionDTO(new ArrayList<>());
        regionCache.set(new SoftReference<>(dictRegionDTO));
        return Optional.of(dictRegionDTO);
    }
}

static,保证此变量全局共享。补充说明JDK8 以后静态变量存储在JVM 的堆上。

AtomicReference 保证多线程环境下使用变量时候是原子操作,实现对象引用的原子更新。

SoftReference即对象的软引用,如果一个对象具有软引用,且内存空间足够,GC就不会回收它;如果内存空间不足了,GC就会回收这些对象的内存。

使用SoftReference是为了防止缓存的数据量过大,出现堆内存不够的情况。

三、总结来

当然,这样的实现是为了不引入新的组件,增加系统的开发和维护成本。如果本身系统有使用第三方缓存的需求,例如需要持久化,分布式,缓存特殊策略等,那么大胆的使用第三方缓存吧!

查看原文

赞 0 收藏 0 评论 0

那么倔强的石头 发布了文章 · 2020-11-19

【术篇】【数据结构与算法】 数据结构与算法概述

一、引言来

大学学习的第二个重要的课程就是《数据结构与算法》,当时学下来云里雾里饶,也不知道有什么作用,只是把重要的概念记下来应付考试。工作以后发现除了面试考官经常问起来,更重要的时候工作上很多时候都能用上,用上合适的数据存储结构、作用于特定数据结构上算法后,在空间复杂度和时间复杂度上都有明显的效率提升。为了回顾数据结构与算法并加上印象,特开展专题记录。

二、介绍来

1.何为数据结构与算法

  • 广义上,也就是从课本上说,数据结构就是一组存储数据的结构,而算法能就是操作数据的一组方法。
  • 狭义上,其实是针对著名的数据结构与算法。著名的意思即前人的智慧结晶,我们时常听到的堆,栈,二分查找,快速排序等都是著名的数据结构与算法。站在巨人的肩膀上,我们能有更卓越的成就。

2.数据结构与算法的关系

总的来说两者是相辅相成的,缺一不可。

数据结构是为算法服务的,算法要作用在特定的数据结构之上。 因此,我们无法孤立数据结构来讲算法,也无法孤立算法来讲数据结构。

数据结构是静态的,它只是组织数据的一种方式。如果不在它的基础上操作、构建算法,孤立存在的数据结构就是没用的。

3.学习两者的方向

3.1. 掌握常用的数据结构和算法的特点(口诀)
重点是学习他们的: “ 来历 ” 、 “ 特点 ” 、 “ 适合解决什么问题 ” 和 “实际的应用场景 ” 。

数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、 Trie 树

算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法

3.2. 能进行复杂度分析(心法)
效率和资源消耗的度量衡即复杂度分析是数据结构和算法学习的精髓

数据结构和算法解决的是如何更省、更快地存储和处理数据的问题,因此,我们就需要一个考量效率和资源消耗的方法,这就是复杂度分析方法。

查看原文

赞 1 收藏 1 评论 0

那么倔强的石头 发布了文章 · 2020-11-19

【器篇】【Mysql】 基于GTID的主主备份实践

一、引言来

此教程简要指导针对Mysql数据库的基于GTID的双主备份。

二、步骤来

0.环境准备

  • 两台Centos系统的服务器,服务器分配在同一网段,并保证相互网络畅通

    -server-a ip : 192.168.1.220

    -server-b ip : 192.168.1.221

  • 服务器预先安装好DockerDocker-Compose,pull Mysql:8.0镜像
  • Navicat for mysql 执行数据库命令

1.设置Mysql配置文件

新建mysql配置文件my.cnf,详细配置省去,只说明主从备份相关配置。

1.1设置server-a的配置文件

与主主备份相关的配置


[mysqld]
#为服务器分配id,可以自定义,不区分大小,起标识作用。不同数据库节点分配不同的id
server_id=1

# 打开Mysql 日志,日志格式为二进制
log-bin=mysql-bin

# 可选项Mixed,Statement,Row,默认格式是 Statement,mixed混合Satement,ROW两种模式
binlog_format=mixed

#当启用时,服务器通过只允许执行可以使用GTID安全地记录的语句来强制GTID一致性。
enforce-gtid-consistency=true

#启用基于GTID的复制,启用之前必须保证enforce-gtid-consistency=true
gtid_mode=ON

#该选项让从库写入哪些来自于主库的更新,并把这些更新写入bin-log文件,一台服务器即做主库又做从库必须开启
log-slave-updates=true

一些定制化的配置


针对主服务器

忽略不同步主从的数据库

#一般设置 sys,performace_schema,infomation_schema,mysql
binlog-ignore-db=<YOUR-DB-NAME>

允许同步的数据库

#一般设置成备份的生产数据的数据库
binlog-do-db=<YOUR-DB-NAME>

针对从服务器

忽略不同步主从的数据库

#一般设置 sys,performace_schema,infomation_schema,mysql
replicate-ignore-db=<YOUR-DB-NAME>

允许同步的数据

#一般设置成备份的生产数据的数据库
replicate-do-db=<YOUR-DB-NAME>

因为我们配置的是双主服务器,每台服务器既要作为主又要作为从。所以以上针对主,从服务器的个性化配置在两台数据库都要按具体业务需求进行配置。

另,以上4个定制化参数可重复设置,如下图

replicate-ignore-db=sys
replicate-ignore-db=mysql
1.2 设置server-b配置

区别于server-a的配置,改动以下配置即可,其余定制化配置按需自定义

#server_id 必须独一无二
server_id=2

2.编辑docker-compose.yml

两个服务器配置相同内容的docker-compoe.yml文件

version: '3.7'
services:
  #mysql service
  mysql:
    image: mysql:8.0
    ports:
      - "3306:3306"
    command:  --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --default-time-zone='+8:00'
    restart: always
    volumes:
     #持久化数据库,注意路径
      - ./data/db:/var/lib/mysql
     #替换数据库配置文件,注意路径
      - ./my.conf:/etc/mysql/conf.d/mysql.cnf
    environment:
      MYSQL_ROOT_PASSWORD: <YOUR_PAASWORD>
    container_name: mysql_service

3.docker 开启数据库容器

每个服务器针对数据库的docker-compose目录如下(供参考):

-mysql_replicate

docker-compose.yml

my.conf

-data

-db

启动数据库服务

docker-compose up -d

确保数据库服务启动成功。

4.配置同步信息并启动同步

4.1 查看两台服务器Mysql状态
MySQL [(none)]> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000014 |      81  |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

File 表示当前正在写入的binlog文件

Postion 表示当前正在写入的位置

Binlog_Do_DB表示只记录指定数据库的二进制文件

Binlog_Ignore_DB表示不记录指定数据库的二进制文件

Executed_Gtid_Set这是5.7mysql库引入了新的表gtid_executed,会记录当前执行的GTID

如果未开启GTID,配置同步信息会用到FilePostion

4.2创建Replication用户

创建针对限定host的Slave登录用账户和密码,并刷新权限

针对server-a,其ip为192.168.8.220

create user 'repl'@'192.168.1.221' identified by 'vo7kphndxlzfr6u3';
grant replication slave on *.* to 'repl'@'192.168.1.221';
flush privileges;

针对server-b,其ip为192.168.8.221

create user 'repl'@'192.168.1.220' identified by 'vo7kphndxlzfr6u3';
grant replication slave on *.* to 'repl'@'192.168.1.220';
flush privileges;
4.3配置同步信息

使数据库实例和Master实例关联起来

针对server-a,其ip为192.168.8.220

 change master to 
     master_host='192.168.1.221',
     master_port=3306,
     master_user='repl',
     master_password='vo7kphndxlzfr6u3',
 MASTER_AUTO_POSITION=1,
 GET_MASTER_PUBLIC_KEY=1;

针对server-b,其ip为192.168.8.221

 change master to 
     master_host='192.168.1.220',
     master_port=3306,
     master_user='repl',
     master_password='vo7kphndxlzfr6u3',
 MASTER_AUTO_POSITION=1,
 GET_MASTER_PUBLIC_KEY=1;

MASTER_AUTO_POSITION自动获取Master 的位置,就不要去指定master_log_filemaster_log_pos

GET_MASTER_PUBLIC_KEY很重要,如果不设置此参数,会导致Slave开启后,Slave无法连接到Master。错误见下图

eror connecting to master 'repl@mysql-master:3306' - retry-time: 60  retries: 3, Error_code: MY-002061
...

这个是因MySQL 8默认启用了caching_sha2_password authentication plugin,通过mysql官方文档介绍可以在CHANGE MASTER TO添加GET_MASTER_PUBLIC_KEY=1参数来解决这个问题。

4.4 启动同步和查看同步状态

在两个数据库实例中启动同步

start slave;

表示启动从库的两个线程:

  1. I/O线程,表示线程会连接远程Master的mysql,并把它的bin-log拷贝到本机的中继日志relay-log中。
  2. sql线程,表示该线程会读取本机中继日志中的数据,并把这些数据恢复到本机自己的mysql表中。

这样Master的数据就会同步到从库的数据库中。

查看同步状态

show slave status;

显示以下状态则正常

Slave_IO_Running: Yes
Slave_SQL_Running: Yes

至此,配置同步信息,启动同步完成。修改任意数据库表结构或表数据,会同步更新到另一个数据库中。

三、扩展来

主主备份的设置过程已经清楚了,那么Mysql数据库是如何完成备份过程的?如何解决主从备份过程中同步有延迟问题呢?主从同步过程中出现行数据冲突如何处理?先留给同志们思考思考。接下来会有其它文章进行一一阐述。

查看原文

赞 0 收藏 0 评论 0

那么倔强的石头 发布了文章 · 2020-11-19

【器篇】【Docker】 Docker以及Docker-Compose 安装方法

一、引言来

Docker是近几年比较火的容器技术,借助它能显著提高开发团队构建和发布服务的能力。本教程指导如何在Centos 7 上安装Docker CEDocker-compose

二、安装步骤来

具体手动安装步骤参照下面操作。

1.安装Docker CE

Docker CE 分为 stabletestnightly 三个更新频道。每六个月发布一个 stable 版本 (18.09, 19.03, 19.09...),生产环境使用stable版本。

1.1 卸载旧版本Docker,Docker-Engine

确定未安装过Docker可不进行此步骤

$ sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-selinux \
                  docker-engine-selinux \
                  docker-engine
1.2 配置 Ali Docker YUM源
#first 安装依赖包
$sudo yum install -y yum-utils device-mapper-persistent-data lvm2
#then  使用ali仓库源
$sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
1.3安装Docker CE

查看可供安装的版本

 #按需选择适合自己的版本
 $yum list docker-ce --showduplicates

接下来提供两种安装方式,一种是脚本安装,一种是非脚本安装。
非脚本安装latest stable

#更新源缓存
$sudo yum makecache fast
$sudo yum install docker-ce

脚本安装latest stable

仅限于centos上使用此方法,简化安装步骤,使用--mirror 设定国内源,加快下载速度。

$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun

若是需要旧版本的Docker CE,可按照以下方法安装

#安装较旧版本,需要指定完整的rpm包的包名,并加上参数--setopt=obsoletes=0
$yum install -y --setopt=obsoletes=0 \
   docker-ce-17.03.3.ce-1.el7.centos.x86_64 \
   docker-ce-selinux-17.03.2.ce-1.el7.centos.noarch
#安装较新的版本,加上rpm包名的版本号部分即可
$sudo yum install docker-ce-18.03.0.ce
1.4启动Docker 服务
# 配置开机启动
$ sudo systemctl enable docker
# 启动docker 服务
$ sudo systemctl start docker

使用Docker --version Docker 安装启动成功

2.设置Docker国内镜像源

使用 Docker 需要经常从官方获取镜像,国内拉取镜像的过程非常耗时,所以要更换到国内镜像源

a.创建或修改 /etc/docker/daemon.json

# 设置网易镜像源,也可选择其它
{
    "registry-mirrors": ["http://hub-mirror.c.163.com"]
}

b.重启Docker服务,完成。

$systemctl restart docker

若不想设置全局的镜像源,也可在拉取镜像时指定镜像源。

#临时指定镜像源
$docker pull registry.docker-cn.com/library/ubuntu:16.04

3.安装Docker-Compose

因为安装Docker CE并不会安装Docker-Compose,所以需要另外进行安装。

a.使用Curl下载Docker-Compose的二进制文件到/usr/local/bin目录

$sudo curl -L "https://github.com/docker/compose/releases/download/1.23.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

因为网络状况,下载过程也许会很缓慢,耐心等待...

b.使二进制文件可执行

$sudo chmod +x /usr/local/bin/docker-compose

c.验证是否成功

$docker-compose --version

三、扩展来

当然,我想到了你们会说,上面的步骤好多,过于复杂。那么,也行,接下来提供一个脚本去自动安装,以解放你们的双手。

echo -e "$R config yum and install docker-ce with docker-compose $docv $S"

yum install -y epel-release
yum install -y lrzsz vim htop yum-utils device-mapper-persistent-data lvm2 haveged && systemctl enable haveged &&systemctl start haveged
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache fast
yum install -y docker-ce
systemctl start docker
curl -L "https://github.com/docker/compose/releases/download/$docv/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose &&\
chmod +x /usr/local/bin/docker-compose
usermod -aG docker admin
查看原文

赞 0 收藏 0 评论 0

那么倔强的石头 发布了文章 · 2020-11-19

【术篇】【设计模式】 设计模式概述及其原则

一、引言来

设计模式代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

设计模式主要是基于面向对象的以下原则:

  • 面向接口编程而不是实现
  • 推崇对象组合而不是继承

二、设计模式分类

共分为三大类

  1. 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
  2. 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
  3. 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

除以上三大类以外还有两类,即并发型模式和线程池模式。

三、设计模式六大原则

0.总原则-开闭原则

对扩展开放,对修改封闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码,实现一个热插拔的效果。即:为了使程序的扩展性好,易于维护和升级。

1.单一职责原则(Single Responsibility Principle,简称SRP )

  • 核心思想:应该有且仅有一个原因引起类的变更
  • 问题描述:假如有类Class1完成职责T1,T2,当职责T1或T2有变更需要修改时,有可能影响到该类的另外一个职责正常工作。
  • 好处:类的复杂度降低、可读性提高、可维护性提高、扩展性提高、降低了变更引起的风险。
  • 需注意:单一职责原则提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口或类设计得是否优良,但是“职责”和“变化原因”都是不可以度量的,因项目和环境而异。

2.里氏替换原则(Liskov Substitution Principle,简称LSP)

  • 核心思想:在使用基类的的地方可以任意使用其子类,能保证子类完美替换基类。
  • 通俗来讲:只要父类能出现的地方子类就能出现。反之,父类则未必能胜任。
  • 好处:增强程序的健壮性,即使增加了子类,原有的子类还可以继续运行。
  • 需注意:如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系 采用依赖、聚合、组合等关系代替继承。

3.依赖倒置原则(Dependence Inversion Principle,简称DIP)

  • 核心思想:高层模块不应该依赖底层模块,二者都该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象;
  • 说明:高层模块就是调用端,低层模块就是具体实现类。抽象就是指接口或抽象类。细节就是实现类。
  • 通俗来讲:依赖倒置原则的本质就是通过抽象(接口或抽象类)使个各类或模块的实现彼此独立,互不影响,实现模块间的松耦合。
  • 问题描述:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
  • 解决方案:将类A修改为依赖接口interface,类B和类C各自实现接口interface,类A通过接口interface间接与类B或者类C发生联系,则会大大降低修改类A的几率。
  • 好处:依赖倒置的好处在小型项目中很难体现出来。但在大中型项目中可以减少需求变化引起的工作量。使并行开发更友好。

4.接口隔离原则(Interface Segregation Principle,简称ISP)
  • 核心思想:类间的依赖关系应该建立在最小的接口上
  • 通俗来讲:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
  • 问题描述:类A通过接口interface依赖类B,类C通过接口interface依赖类D,如果接口interface对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不需要的方法。
  • 需注意:
  • 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度
  • 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情
  • 为依赖接口的类定制服务。只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。

5.迪米特法则(Law of Demeter,简称LoD)

  • 核心思想:类间解耦。
  • 通俗来讲: 一个类对自己依赖的类知道的越少越好。自从我们接触编程开始,就知道了软件编程的总的原则:低耦合,高内聚。无论是面向过程编程还是面向对象编程,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率。低耦合的优点不言而喻,但是怎么样编程才能做到低耦合呢?那正是迪米特法则要去完成的。

6.开放封闭原则(Open Close Principle,简称OCP)

  • 核心思想:尽量通过扩展软件实体来解决需求变化,而不是通过修改已有的代码来完成变化
  • 通俗来讲: 一个软件产品在生命周期内,都会发生变化,既然变化是一个既定的事实,我们就应该在设计的时候尽量适应这些变化,以提高项目的稳定性和灵活性。

四、总结来

  • 单一职责原则,实现类要职责单一。
  • 里氏替换原则,不要破坏继承体系。
  • 依赖倒置原则,要面向接口编程。
  • 接口隔离原则,在设计接口的时候要精简单一。
  • 迪米特法则,要降低耦合。
  • 开闭原则是总纲,对扩展开放,对修改关闭。
查看原文

赞 0 收藏 0 评论 0

那么倔强的石头 发布了文章 · 2020-11-19

【器篇】【Flyway】 Flyway 概述

一.引言来

在软件项目开发工程中,一般来说项目都是几个开发人员齐头并进的,常常遇到的事情是,大家都同时提交数据库表修改语句后,并不告知其它人,或者几个开发人员同时修改一个表结构,导致其他人运行项目出错。

还有在项目上线运行过程中,常常会因为管理数据库表结构或者表数据版本而发愁,甚至有的时候还不得不为生产数据做迁移操作。

以上的问题,我们一般的操作都是约定+脚本,但效率不高,并且常常会因为版本冲突,不得不手动merge。这个时候一个敏捷工具,用于数据库的移植的Flyway应用而生,它的主要用于在你的应用版本不断升级的同时,升级你的数据库结构和里面的数据。

二、介绍来

1. Flyway 的特色

Flyway 大受欢迎是由于它具备如下优势:

  • 简单 很是容易安装和学习,同时迁移的方式也很容易被开发者接受。
  • 专注 专一于用作数据库迁移、版本控制而并无其它反作用。
  • 强大 专为连续交付而设计,让Flyway在应用程序启动时迁移数据库。

2. Flyway 的工作机制

Flyway 须要在 DB 中先建立一个 metadata 表 (缺省表名为 flyway_schema_history), 在该表中保存着每次 migration (迁移)的记录, 记录包含 migration 脚本的版本号和 SQL 脚本的 checksum 值。下图表示了多个数据库版本。

img

对应的 metadata 表记录:spring

installed_rankversiondescriptiontypescriptchecksuminstalled_byinstalled_onexecution_timesuccess
11Initial SetupSQLV1__Initial_Setup.sql1996767037axel2016-02-04 22:23:00.0546true
22First ChangesSQLV2__First_Changes.sql1279644856axel2016-02-06 09:18:00.0127true

Flyway 扫描文件系统或应用程序的类路径读取 DDLDML 以进行迁移。根据metadata 表进行检查迁移。**若是脚本声明的版本号小于或等于标记为当前版本的版本号之一,将忽略它们。其他迁移是待处理迁移:可用,但未应用。最后按版本号对它们进行排序并按顺序执行 并将执行结果写入 metadata 表。

img

对应的 metadata 表记录:数据库

installed_rankversiondescriptiontypescriptchecksuminstalled_byinstalled_onexecution_timesuccess
11Initial SetupSQLV1__Initial_Setup.sql1996767037axel2016-02-04 22:23:00.0546true
22First ChangesSQLV2__First_Changes.sql1279644856axel2016-02-06 09:18:00.0127true
32.1RefactoringJDBCV2_1__Refactoringaxel2016-02-1017:45:05.4251true

Flyway 支持命令行(须要下载命令行工具)和 Java Api ,也支持构建工具 MavenGradle 。这里咱们将目光放在 Java Api 上。

3. Flyway 的规则

Flyway 是如何比较两个 SQL 文件的前后顺序呢?它采用 采用左对齐原则, 缺位用 0 代替

1.0.1.1 比 1.0.1 版本高

1.0.10 比 1.0.9.4 版本高

1.0.10 和 1.0.010 版本号同样高, 每一个版本号部分的前导 0 会被忽略

FlywaySQL 文件分为 VersionedRepeatableUndo 三种:

  • Versioned 用于版本升级, 每一个版本有惟一的版本号并只能执行一次。
  • Repeatable 可重复执行, 当 Flyway检测到 Repeatable 类型的 SQL 脚本的 checksum 有变更, Flyway 就会从新应用该脚本. 它并不用于版本更新, 这类的 migration 老是在 Versioned 执行以后才被执行。
  • Undo 用于撤销具备相同版本的版本化迁移带来的影响。可是该回滚过于粗暴,过于机械化,通常不推荐使用。通常建议使用 Versioned 模式来解决。

这三种的命名规则以下图:

naming.png

  • Prefix 可配置,前缀标识,默认值 V 表示 Versioned, R 表示 Repeatable, U 表示 Undo
  • Version 标识版本号, 由一个或多个数字构成, 数字之间的分隔符可用点 . 或下划线 _
  • Separator 可配置, 用于分隔版本标识与描述信息, 默认为两个下划线 __
  • Description 描述信息, 文字之间能够用下划线 _ 或空格 ``分隔
  • Suffix 可配置, 后续标识, 默认为 .sql

4.flyway命令行

flyway 提供命令行工具, 常用的命令包括:

  • Clean: 删除所有创建的数据库对象, 包括用户、表、视图等. 注意不要在生产库上执行 clean 操作.
  • Migrate: 对数据库依次应用版本更改.
  • Info: 获取目前数据库的状态. 那些迁移已经完成, 那些迁移待完成. 所有迁移的执行时间以及结果.
  • Validate: 验证已 Apply 的脚本是否有变更, Flyway 的 Migration 默认先做 Validate.
  • Baseline: 根据现有的数据库结构生成一个基准迁移脚本.
  • Repair: 修复命令尽量不要使用, 修复场景有: 1. 移除失败的 migration 记录. 2.已经应用的 SQL 脚本被修改, 我们想重新应用该 SQL 脚本.

maven 插件

           <plugin>
                <groupId>org.flywaydb</groupId>
                <artifactId>flyway-maven-plugin</artifactId>
                <configuration>
                    <user>${flyway.user}</user>
                    <password>${flyway.password}}</password>
                    <url>${flyway.url}</url>
                </configuration>
            </plugin>

5.flyway 最佳实践

1.SQL 的文件名

开发环境和生产环境的 migration SQL 不共用. 开发过程往往是多人协作开发, DB migration 也相对比较频繁, 所以 SQL 脚本会很多. 而生产环境 DB migration 往往由 DBA 完成, 每次升级通常需要提交一个 SQL 脚本.

DDL DML 分开

  • 开发环境 SQL 文件建议采用时间戳作为版本号, 多人一起开发不会导致版本号争用, 同时再加上生产环境的版本号, 这样的话, 将来手工 merge 成生产环境 V1.2d migration 脚本也比较方便, SQL 文件示例:

    • V20180317.14.59__V1.2_Add_SomeTables.sql
    • V20180317.14.59__V1.0.1_ProjectName_{Feature|fix}_Developer_Description.sql
  • 生产环境 SQL 文件, 应该是手动 merge 开发环境的 SQL 脚本, 版本号按照正常的版本, 比如 V2.1.5_001__Unique_User_Names.sql
2. migration 后的SQL 脚本不应该再被修改.
3. spring.flyway.outOfOrder 取值 true /false

对于开发环境, 可能是多人协作开发, 很可能先 apply 了自己本地的最新 SQL 代码, 然后发现其他同事早先时候提交的 SQL 代码还没有 apply, 所以 开发环境应该设置 spring.flyway.outOfOrder=true, 这样 flyway 将能加载漏掉的老版本 SQL 文件; 而生产环境应该设置 spring.flyway.outOfOrder=false

4. 多个系统公用要 DB schema

很多时候多个系统公用一个 DB schema , 这时候使用 spring.flyway.table 为不同的系统设置不同的 metadata 表, 缺省为 flyway_schema_history

5.尽量配置.sql到filesystem,而不是项目工程下,原因是方便替换,并不占用jar包大小
6.不推荐使用Undo,太过粗暴

7.实际工程配置和目录

  # flyway 配置内容,对应 FlywayAutoConfiguration.FlywayConfiguration 配置项
  flyway:
    enabled: true # 开启 Flyway 功能
    cleanDisabled: true # 禁用 Flyway 所有的 drop 相关的逻辑,避免出现跑路的情况。
    locations: # 迁移脚本目录
      - classpath:db/migration/dev # 配置 SQL-based 的 SQL 脚本在该目录下
    check-location: false # 是否校验迁移脚本目录下。如果配置为 true ,代表需要校验。此时,如果目录下没有迁移脚本,会抛出 IllegalStateException 异常
    url: jdbc:mysql://192.168.8.94:3399/flyway-test?useSSL=false&useUnicode=true&characterEncoding=UTF-8 # 数据库地址
    user: root # 数据库账号
    password: 1234123 #数据库密码
    baseline-version: 1.0
    baseline-description: "baseline"
    encoding: UTF-8
    out-of-order: true # 是否容许不按顺序迁移 开发建议 true  生产建议 false
    # 如果指定 schema 包含了其他表,但没有 flyway schema history 表的话, 在执行 flyway migrate 命令之前, 必须先执行 flyway baseline 命令.
    # 设置 spring.flyway.baseline-on-migrate 为 true 后, flyway 将在需要 baseline 的时候, 自动执行一次 baseline.
    baselineOnMigrate: true
    table: flyway_schema_history

项目工程目录

三、扩展来

除开Flyway,还有其它的数据库迁移和版本控制工具,例如强大的Liquibase。两者具体的差异,在后续的文章阐述。在以往的经验中,小项目,整体变动不大的用Flyway,而大应用和企业应用用Liquibase更合适。

查看原文

赞 0 收藏 0 评论 0

那么倔强的石头 发布了文章 · 2020-11-19

【奇淫技巧篇】 如何在电脑查看已连接的wifi密码

一、引言来

在实际工作中,常常会遇到新来的同事问你wifi密码的事情,但是大多数时候都记不清楚。借鉴youtube上一位Po主的视频教程,整理出这篇文章,希望对有需要的同志提供帮助。
该教程仅限于windows系列,后续有机会再出一版linux教程。

二、实战来

1.以管理员身份进入命令行(cmd)窗口

2.输入netsh,回车

>netsh

3.输入以下命令,查看WLAN配置文件信息

>wlan show profile

4.输入以下命令,获取指定连接安全密钥

>wlan show profile <your wifi name> key=clear

至此结束,成功获取到密码12341234

查看原文

赞 0 收藏 0 评论 0

那么倔强的石头 发布了文章 · 2020-11-19

【顶得住系列】【java基础】 Integer 和 int == 比较分析

一、引言来

在java语言中,众所周知,int是基础类型,Integer是int的包装类型,属于引用类型。面试中,一般会问到两者有什么区别,答案无非就是侧重描述基础类型和引用类型的区别,这个很简单。面试难度升级就是用 ==进行比较两者,接下来就展开讨论一下这道面试题。

二、题来

            Integer a = new Integer(3); //@1
            Integer b = 3; //@2
            int c = 3; //@3
            int h = 3; //@4
            Integer d = 3;
            Integer e = 300;
            Integer f = 300;
            
            System.out.println(c == h);
            System.out.println(a == b);
            System.out.println(a == c);
            System.out.println(b == d);
            System.out.println(e == f);

想想,会打印什么内容,似乎并不容易回答出来,里面有几层小坑坑,待我细细分析。

先看看运行结果!为什么会这样呢?

三、分析来

我们先逐句分析一下每行代码在执行以后到底发生了什么!

Integer a = new Integer(3); //@1

Integer 是引用类型对象,所以new对象这个过程,先是在上创建了变量a,然后在上创建对象存储数值3,最后将变量a指向在堆上分配的地址。

Integer b = 3; //@2

这行代码直接将基础类型的值赋值给引用类型b,这儿就涉及到装箱的知识点。此行代码执行的时候会触发Integer.valueOf(int i)这个Integer自带方法。方法内容如下:

    public static Integer valueOf(int i) {
        //此处便是常量池,Integer的常量池范围为[-128,127]
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            //如果i变量的值在常量池范围内,则直接使用常量池的值
            return IntegerCache.cache[i + (-IntegerCache.low)];
        //如果i变量的值不在常量池的范围内,堆上新分配空间存储
        return new Integer(i);
    }

根据Integer源码分析,因为3的值在[-128,127]范围内,所以执行这段代码,会先在上创建变量b,然后将变量指向常量池中3。

int c = 3; //@3
int h = 3; //@4

上述代码,因为int是基础类型,所以执行@3行代码时,会先在栈上创建变量c,然后查找栈上有无数值3,没有存储3,然后使变量c指向它。
执行@4时候,执行流程大致与@3一致,只是因为执行到这句时,数值3在栈上已存在,所以直接使变量h指向已创建好的数值3。

所以结果分析就很明了。

System.out.println(c == h);//对于基础类型int,==都是数值比较,肯定是true

System.out.println(a == b);//因为两个变量都是引用类型,所以==比较引用的对象。 变量a引用的对象存储在堆上,变量b引用的对象在常量池,所以为false。

System.out.println(a == c);//Integer类型跟int类型比较,都按照基础类型的比较(拆箱)。因为数值相等,所以为true。

System.out.println(b == d);//因为数值的范围都在[-128,127],所以两个变量指向的对象都是常量池。所以为true。

System.out.println(e == f);//因为范围都超出[-128,127],所以两个变量指向的对象都是在堆各自新创建的堆对象。所以为false。

四、总结来

  1. 对于基础类型int,==都是数值比较。
  2. Integer和int的变量进行比较,==都按照数值比较。
  3. 直接为Integer赋基础类型数值,要考虑到数值的范围,是不是在常量池[-128,127]范围内。

言而总之,对于==,基础类型,比较值;引用类型比较引用的对象。

五、拓展来

上文我们了解Integer常量池(缓存)机制的知识点,由此发散思维,是否其它的基础类型的包装类有类似的机制。
答案是肯定的,我们常用的ShortLongByteCharacter都有类似的机制,碍于篇幅,具体细节不一一细讲,留个同志们去研究研究。
除开基础类型的包装类,还有一个String类型很特殊,后文再细讲它的内存分配以及变量比较。

查看原文

赞 0 收藏 0 评论 0

那么倔强的石头 赞了回答 · 2018-04-19

解决npm start 运行'webpack-dev-server'报错 Cannot find module 'webpack'

webpack.config.js里使用了webpack,所以webpack也需局部安装(本项目)依赖;
图片描述
图片描述

关注 3 回答 2

那么倔强的石头 关注了用户 · 2018-04-19

toBeTheLight @tobethelight

熟练掌握 TS(0.5/1)
学习经济学(1/1)
学习数学知识(0/n)
学习编译原理(0/1)
文笔更好一些(1/1)

关注 26536

认证与成就

  • 获得 1 次点赞
  • 获得 3 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 3 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2018-04-19
个人主页被 309 人浏览