什么是仿射变换

一组设备无关的坐标被用来将所有的坐标信息传递给Graphics2D对象。AffineTransform对象作为Graphics2D对象状态的一部分。该对象定义了如何将用户空间的坐标转化为设备空间的设备相关的坐标点。

AffineTransform类代表一个2D的仿射变化,将一组2D的坐标进行线性映射到另一组保留了平行关系和竖直关系的2D坐标中。该转化包括平移,缩放,翻转,旋转和扭曲。

根据AffineTransform定义的变化有两个非常重要的属性:
直线依然是直线
平行的线依然保持平行

AffineTransform是限次那个转化,所以可以通过矩阵的形式表示转化,然以一个AffineTransform可以通过数学的形式转化为一个包含六个数字的矩阵。
sx shx tx
shy sy ty

这里省略了矩阵的大括号。

阅读全文 »

基础知识

  1. 指令的历史记录位于~/.bash_history文件中,可以使用cat指令查看。需要注意的是,它存储的是上一次登录时执行过的命令,而这一次登录中执行的命令将先暂存在内存中
  2. Tab键可以用来补全命令或是提示可选的操作
  3. \可以用来换行增强指令的可读性
  4. 将根据环境变量PATH来寻找指令,可以使用echo $PATH来查看环境变量
  5. 在命令执行的过程中,反引号中的指令会先执行,执行的结果会作为外部的输入信息,$()具有同样的效果
  6. 命令执行顺序:以相对/绝对路径执行命令,以alias找到该命令来执行,由bash内置的命令来执行,通过$PATH的顺序找到第一个命令并执行
  7. 数据流重定向是指将某个指令执行后应该要出现在屏幕上的数据传输到其它地方。
  8. 直接执行和bash或sh执行脚本会在子进程中执行,而使用source执行脚本则会在父进程中执行
阅读全文 »

安装JAVA

在这里使用yum来安装java的jdk,可以使用指令yum search java | grep jdk来查看yum下提供了哪些jdk版本。这里选择1.8版本,安装指令为:sudo yum install java-1.8.0-openjd

安装完毕后还需要修改环境变量,这里的环境变量我们将在/etc/profile.d中添加一个java.sh文件中设置,指令如下:

1
2
cd /etc/profile.d
sudo vim java.sh

在里面填写如下内容:

1
2
3
4
5
6
#set java environment
JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.7.0.75.x86_64
JRE_HOME=$JAVA_HOME/jre
CLASS_PATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin
export JAVA_HOME JRE_HOME CLASS_PATH PATH

然后保存并退出。(这里需要了解vim的操作,本文将不详述)

最后在用source /etc/profile启动环境变量,可以使用java -version查看配置是否成功。

阅读全文 »

前言

一直以来存储树状结构都采用经典的结构<id,pid>的组合,即每一个节点持有其父节点的ID,并由此构成完整的树状结构。但是这样的结构在遇到大量的查询时会成为严重的性能瓶颈,因为它涉及了对数据库的递归查询。因此我查找了一下网上的各种层次结构的存储方式并决定对其分别实现。本文将通过MySQL+MyBatis+SpringBoot实现先序树存储。
阅读本文之前需要了解:

  • Spring Boot
  • MyBatis
  • MySQL CRUD & Procedure

本文的源码可以在GitHUB上查看。欢迎大家给出意见。

阅读全文 »

前言

相信所有面试java开发的童鞋一定都被问到过是否使用过Spring,是否了解其IOC容器,为什么不直接使用工厂模式,以及究竟IOC和DI区别在于哪里这种问题。今天就结合JAVA语言,解释一下究竟是如何衍生出DI模式,以及其在Spring中的实现。

很久很久以前

初学Java,我们一定会学到面向对象的编程思想,以及使用new关键字新建一个对象。假设现在有一个邮件发送系统,该系统包含拼写检查功能。那么本着面向对象的思想以及关注点分离的思想,我们会将其分解为两个类:EmailerSpellChecker。其中,Emailer依赖着SpellChecker提供的服务,这两个类的实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class SpellChecker{
...
public void check(){
...
}
}

public class Emailer{
private SpellChecker spellChecker;
public Emailer(){
spellChecker = new SpellChecker();
}
}

可以看到我们在构造器中使用new新建了一个SpellChecker的对象。

现在我们来分析一下这个实现的不足之处:

  • 可测试性:假设现在我希望测试Emailer的功能是否完善,但是此时SpellChecker并没有完成开发与测试,那么我们将无法对Emailer进行测试。就算SpellChecker已经开发完成,但是我们也无法排除当前的错误是否和SpellChecker的实现无关。
  • 可维护性:假设现在支持多语种,那么我需要分别实现一个EnglishEmailer和FrenchEmailer类。他们的构造函数中分别初始化EnglishSpellChecker和FrenchSpellChecker。以后每增加一个语种都需要新建一个新的Emailer类。而这些类的代码本质上都是重复的。更不要提假设里面

因此我们就需要一种新的初始化依赖的方式。

阅读全文 »

前言

在十几年前,我们无法想象一个分布式系统会是什么样子。它给我们带来了全新的架构思路,但同时也引入了一些问题。
当时这些系统非常少有而且架构简单,工程师们通过尽可能的减少远程交互的方式降低复杂度。解决分布式问题最好的方法是尽可能的避免分布式系统,尽管这意味着会有大量重复的逻辑分布在不同的系统上。

但是,工业需求将架构继续推进,从原先的几个集中的系统演化为成百上千的微服务。在这个新的领域,我们不得不开始摆脱困境,应对新的挑战并提出问题,从以个案方式提出临时解决方案,到使用更复杂的方法。随着我们更多地了解问题领域并设计出更好的解决方案,我们开始将一些最常见的需求纳入模式,库和平台。

阅读全文 »

前言

这篇文章主要是记录文,用于记录一下最近看到的关于分布式一致性的一些核心理念。

ACID

事务是由一系列对系统中数据进行访问与更新的操作所组成的一个程序执行逻辑单元,狭义上的事务特指数据库事务。事务具有ACID属性。

Atomicity 原子性

事务中包含的各项操作在一次执行过程中,只允许出现全部执行成功或是全部不执行两种状态。任何一项操作失败都将导致整个事务失败,同时其他已经被执行的操作都将被撤销并回滚。

Consistency 一致性

事务的执行不能破坏数据库数据的完整性和一致性。一个事务执行之前和执行之后,数据库都必须处于一致性的状态。当数据库只包含成功事务提交的结果时,就能说数据库处于一致性状态。而如果数据库系统在运行过程中发生故障,有些事务尚未完成被迫中断,这些未完成的事务对数据库所做的修改有一部分已经写入物理数据库。这时数据库就处于不一致状态。

Isolation 隔离性

并发的事务是相互隔离的,一个事务的执行不能被其它事务干扰。即,不同事务并发操纵相同的数据时,每个事务有各自完整的数据空间。事务的四个隔离级别如下:
Read Uncommited 读未提交
允许脏读,隔离界别最低。如果一个事务正在处理某一数据,并对其进行了更新,同时尚未完成事务,即没有进行事务提交。但是,与此同时,允许你另一个事务能够访问该数据。

Read Commited 读已提交
和读未提交的区别在于只允许获取已经被提交的数据。但是无法实现可重复读取。即如果事务A在同一个事务中执行了两次对同一条数据的select操作,同时事务B和C分别在第一条select之前和第二条select之前执行了对该数据的更新操作,那么A的两条select将得到不同的数据。

Repeatable Read 可重复读
在事务处理过程中,多次读取同一个数据时,其值和事务开始时刻是一致的。但是该级别会出现幻读。
幻读:第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。

Serializable
要求所有的事务被串行执行,即事务只能一个接一个的进行处理,不能并发执行。

Durability 持久性

一个事务一旦提交,它对数据库中对应数据状态的变更就应该是持久性的。也就是说,即使发生系统崩溃,只要数据库能够重启,就一定能够将其恢复到事务成功结束时的状态。

CAP

Consistency 一致性

在分布式环境中,一致性是指数据在多个副本之间能够保持一致性。当一个系统在数据一致的状态下执行更新操作后,应该保证系统的数据仍然处于一致的状态。在分布式系统中,如果能够在一个数据项的更新操作执行成功后,所有的用户都可以读取到其最新的值,那么这样的系统就被任务具有强一致性。

Availability 可用性

系统一直处于可用的状态,对于每一个操作请求总能够在有限时间内返回结果。有限时间是指能够在指定的响应时间内返回对应的结果,超过这个时间即可认为系统不可用。指定的响应时间通常根据不同的系统有不同的标准。返回结果是指能够正常的相应结果,而不是看到系统错误等信息。

Partiion Tolerance 分区容忍性

分布式系统在遇到任何网络分区的故障的时候,仍然需要能够保持对外提供满足一致性和可用性的服务,除非整个网络环境都发生了故障。

BASE

Basically Available 基本可用

分布式系统在出现不可预知的故障的时候,允许损失可用性(不是说系统不可用)。比如响应时间比指定时间长一点,在功能上进行限流降级熔断等等。

Sofa State 弱状态

允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统的不同节点之间的数据副本之间进行数据同步的过程中存在延时

Eventually Consistent 最终一致性

最终一致性强调系统中所有的数据副本,在经过一段时间的同步之后,最终能够达到一致的状态。这是相对于实时强一致而产生的概念。

Casual Consistency 因果一致性
进程A在更新完某个数据之后通知了进程B,那么进程B之后对该数据项的访问都应该能够获取到进程A更新后的最新值。即如果B依赖于A的更新,则更新必须顺序进行。但是与进程A无因果关系的进程C则无这样的限制。

Read Your Writes 读己之所写
进程A更新一个数据项之后,自己总是能够访问到更新过后的最新值,而不是看到旧值。即一种特殊的因果一致性。

Session Consistency 回话一致性
系统保证在一个有效的回话中实现读己之所写一致性。也就说,执行更新操作后,客户端能够在同一个回话中始终读取到该数据项的最新值。

Monotonic Read Consistency 单调读一致性
如果一个进程从系统中读取出一个数据项的某个值后,那么系统对于该进程后续的任何数据访问都不应该返回更旧的值。

Monotonic Write Consistency 单调写一致性
一个系统需要能够保证来自同一个进程的写操作能够顺序执行。

分布式事务中的两种角色

分布式事务中的组件有两种角色:

  1. 协调者:统一调度所有分布式节点的执行逻辑
  2. 参与者:被调度的分布式节点

Two-Phase Commit 2PC

阶段一:提交事务请求(投票阶段)

  1. 事务询问。协调者询问所有参与者发送事务内容,询问是否可以执行事务提交操作,并等待各个参与者的相应
  2. 执行事务。各参与者执行事务操作,并将undo和redo信息记入事务日志中
  3. 各参与者向协调者反馈事务询问的响应

阶段二:执行事务提交(执行阶段)

根据参与者额反馈情况来决定最终是否可以进行事务的提交
情况一:执行事务提交,即收到的反馈都是YES

  1. 协调者发送提交请求
  2. 事务提交:参与者收到提交请求之后,正式执行事务提交,提交之后释放在整个事务执行期间占用的事务资源
  3. 反馈事务提交ACK结果
  4. 完成事务
    情况二:中断事务,即收到了No响应
  5. 协调者发送回滚请求
  6. 参与者利用undo日志的信息进行事务回滚,并在回滚完成之后释放在整个事务执行期间占用的事务资源
  7. 反馈事务回滚结果
  8. 完成事务中断

优点:原理简单,实现方便
缺点:同步阻塞,单点问题(协调者),太过保守

Three-Phase Commit 3PC

阶段一:CanCommit

  1. 事务询问。协调者向所有参与者发送一个包含事务内容的canCommit请求,询问是否可以执行事务提交操作
  2. 参与者根据自身情况向协调者反馈事务询问

阶段二:PreCommit

根据CanCommit的回复可以产生以下两种操作:
情况一:执行事务预提交
假设收到的ACK均为YES,则

  1. 发送PreCommit请求
  2. 参与者执行事务操作,并将Undo和Redo信息记录到事务日志中
  3. 参与者向协调者反馈事务执行的响应
    情况二:中断事务
    假设收到了至少一个ACk为NO或是等待超时
  4. 协调者发出中断请求
  5. 参与者收到协调请求或是等待超时,都会中断事务

阶段三:DoCommit

情况一:执行提交
收到PreCommit阶段的全部ACK

  1. 发送提交请求
  2. 事务提交
  3. 反馈事务提交结果
  4. 完成事务
    情况二:中断事务
    假设协调者没有收到全部的YES ACK则
  5. 发送中断请求
  6. 事务回滚
  7. 反馈事务回滚结果
  8. 中断事务

优点:降低参与者阻塞范围
缺点:参与者收到preCommit消息后,如果网络出现分区,此时协调者所在的节点和参与者无法进行正常的网络通信。这种情况下,参与者依然会进行事务提交,从而出现数据的不一致性,

简介

  • 大多数时候,开发者极少关注事务管理从而导致大量代码需要重新开发,或是实现事务的时候没有注意事务究竟是如何实现的以及在这些场景中需要关注的维度。
  • 事务管理的一个重要方面是定义正确的事务边界,例如事务何时开始,什么时候应该结束,什么时候应该在数据库中提交数据,什么时候应该回滚(在出现异常的时候)。
  • 对于开发人员而言,最重要的是了解如何在应用程序中更好的实现事务管理。所以现在让我们用不同的方式探索事务。
    阅读全文 »

前言

Java ClassLoader是java运行系统中一个至关重要但是经常被忽略的组件。它负责在运行时寻找并加载类文件。创建自定义的ClassLoader可以彻底重定义如何将类文件加载至系统。

这个教程对Java的ClassLoader进行总体概述,并给了一个自定义ClassLoader的例子。这个ClassLoader会在加载代码之前自动编译。你将会了解ClassLoader是做什么的,以及如何创建自定义ClassLoader。

本教程需要阅读者对Java编程有基础了解,包括创建,编译和执行简单的命令行Java程序。

阅读完本教程之后,你会知道如何:

  • 扩展JVM的功能
  • 创建一个自定义的ClassLoader
  • 学习如何将ClassLoader集成至Java应用
  • 修改ClassLoader使其符合Java2版本
    阅读全文 »
0%