设计模式--访问者模式
定义表示一个作用于某对象结构中各个元素的操作。它使得用户可以在不改变各个元素的类的前提下定义作用于这些元素的新操作。(好抽象呀)
结构
抽象元素:一个抽象类,该类定义了接收访问者的 accept 操作
具体元素:抽象元素的子类
抽象访问者:一个接口,该接口定义操作具体元素的方法。
具体访问者:实现 抽象访问者 接口的类
自己的理解
抽象访问者:定义了一个接口,这个接口定义了,具体的访问者的方法。比如要访问哪个类型的数据等等
这里的抽象访问者定义了两个 visit 方法的重载,能够让具体访问者,去访问 Coder 和 Worker 类型
具体访问者:实现上面的接口。对 visit 方法做出具体的动作。
抽象元素:一个抽象类,定义了被访问类型的一些共有的特性和行为
具体元素,能够被访问的元素,继承自抽象元素
uml 图
最终调用
双重分派
优点
设计模式--策略模式
定义定义一系列算法,把他们一个个封装起来,并且使他们可相互替换。本模式使得算法可独立于使用它的客户而变化。
结构
策略:策略是一个接口,该接口定义若干个算法标识,及定义了若干个抽象方法。
上下文:上下文是依赖于策略接口的类,及最终使用方法完成具体业务的类。
具体策略:具体策略是实现策略接口的类。具体策略实现策略接口所定义的抽象方法。即给出算法标识的具体算法。
举例
个人理解策略模式是定义了一个接口,声明了这个算法要实现的方法。然后由不同的需求,去实现同名的不同算法。最后上下文获得的具体算法类不同。就可以执行不同的需求,而不用改动上下文的代码。具体算法和上下文之间,是一种松耦合。
适合场景
01|反射
反射的概念反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。
在 java 中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。
若程序运行时接收到外部传入的一个对象,该对象的编译类型是 Object,但程序又需要调用该对象运行类型的方法:
若编译和运行类型都知道,使用 instanceof 判断后,强转。
编译时根本无法预知该对象属于什么类,程序只能依靠运行时信息来发现对象的真实信息,这时就必须使用反射了。
要是想得到对象真正的类型,就得使用反射。
Java 中,能够调用什么方法,看对象的引用,具体调用什么方法,看引用指向的对象。
反射的优缺点为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念,
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了 java 的灵活性,体现了多态的应用,有以降低类之间的藕合性。
一句话,反射机制的 ...
07|行锁
行锁是在引擎层由各个引擎自己实现的。但并不是所有的引擎都支持行锁,比如 MyISAM 引擎就不支持行锁。不支持行锁意味着并发控制只能使用表锁,对于这种引擎的表,同一张表上任何时刻只能有一个更新在执行,这就会影响到业务并发度。InnoDB 是支持行锁的,这也是 MyISAM 被 InnoDB 替代的重要原因之一。
行锁定义顾名思义,行锁就是针对数据表中行记录的锁。这很好理解,比如事务 A 更新了一行,而这时候事务 B 也要更新同一行,则必须等事务 A 的操作完成后才能进行更新。
两阶段锁我先给你举个例子。在下面的操作序列中,事务 B 的 update 语句执行时会是什么现象呢?假设字段 id 是表 t 的主键。这个问题的结论取决于事务 A 在执行完两条 update 语句后,持有哪些锁,以及在什么时候释放。你可以验证一下:实际上事务 B 的 update 语句会被阻塞,直到事务 A 执行 commit 之后,事务 B 才能继续执行。知道了这个答案,你一定知道了事务 A 持有的两个记录的行锁,都是在 commit 的时候才释放的。
也就是说,在 InnoDB 事务中,行锁是在需要的 ...
06|全局锁和表锁
为什么会有数据库锁数据库锁设计的初衷是处理并发问题。作为多用户共享的资源,当出现并发访问的时候,数据库需要合理地控制资源的访问规则。而锁就是用来实现这些访问规则的重要数据结构。
锁的分类根据加锁的范围,MySQL 里面的锁大致可以分成
全局锁
表级锁
行锁。
全局锁顾名思义,全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法,命令是 Flush tables with read lock (FTWRL)。当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。全局锁的典型使用场景是,做全库逻辑备份。也就是把整库每个表都 select 出来存成文本。以前有一种做法,是通过 FTWRL 确保不会有其他线程对数据库做更新,然后对整个库做备份。注意,在备份过程中整个库完全处于只读状态。但是让整库都只读,听上去就很危险:
如果你在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆;
如果你在从库上备份,那么备份期间从库不能执行主库同步过 ...
05|索引(下)
开始在下面这个表 T 中,如果我执行 select * from T where k between 3 and 5,需要执行几次树的搜索操作,会扫描多少行?下面是这个表的初始化语句。
mysql> create table T (
ID int primary key,
k int NOT NULL DEFAULT 0,
s varchar(16) NOT NULL DEFAULT '',
index k(k))
engine=InnoDB;
insert into T values(100,1, 'aa'),(200,2,'bb'),(300,3,'cc'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');
去 k 索引数查找 k=3 的值,找到 id=300,去 id 索引树,根据 id=300,找到 r3
去 k 索引数查找 k=5 的值,找到 id=500,去 id 索引树,根据 id=500,找到 R4;
去 k 索引数查找 k=6 的值,不满足条件,结束
在 ...
04 | 索引
定义一句话简单来说,索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。一本 500 页的书,如果你想快速找到其中的某一个知识点,在不借助目录的情况下,那我估计你可得找一会儿。同样,对于数据库的表而言,索引其实就是它的“目录”。
索引的常见模型索引的出现是为了提高查询效率,但是实现索引的方式却有很多种,所以这里也就引入了索引模型的概念。可以用于提高读写效率的数据结构很多,这里有三种常见、也比较简单的数据结构,它们分别是
哈希表
有序数组
搜索树。
哈希表
哈希表是一种以键 - 值(key-value)存储数据的结构,我们只要输入待查找的键即 key,就可以找到其对应的值即 Value。
哈希的思路很简单,把值放在数组里,用一个哈希函数把 key 换算成一个确定的位置,然后把 value 放在数组的这个位置。
不可避免地,多个 key 值经过哈希函数的换算,会出现同一个值的情况。处理这种情况的一种方法是,拉出一个链表。
假设,你现在维护着一个身份证信息和姓名的表,需要根据身份证号查找对应的名字,这时对应的哈希索引的示意图如下所示:
图中,User2 和 User4 ...
03 | 事务
事务的概念数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。
事务的几大特性俗称 “ACID” (原子性,一致性,隔离性,持久性)
原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性(Consistency)事务前后数据的完整性必须保持一致。
隔离性(Isolation)事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
隔离性与隔离级别当数据库上有多个事务同时执行的时候,就可能出现 脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read) 的问题,为了解决这些问题,就有了“隔离级别”的 ...
02| 日志系统:一条SQL更新语句是如何执行的?
update 语句会把跟这个表有关的查询缓存失效,这个表上的缓存结果全部清空。这也是不推荐使用查询缓存的原因。
重要的日志模块redo log(重做日志)介绍不知道你还记不记得《孔乙己》这篇文章,酒店掌柜有一个粉板,专门用来记录客人的赊账记录。如果赊账的人不多,那么他可以把顾客名和账目写在板上。但如果赊账的人多了,粉板总会有记不下的时候,这个时候掌柜一定还有一个专门记录赊账的账本。如果有人要赊账或者还账的话,掌柜一般有两种做法:
一种做法是直接把账本翻出来,把这次赊的账加上去或者扣除掉;
另一种做法是先在粉板上记下这次的账,等打烊以后再把账本翻出来核算。
在生意红火柜台很忙时,掌柜一定会选择后者,因为前者操作实在是太麻烦了。首先,你得找到这个人的赊账总额那条记录。你想想,密密麻麻几十页,掌柜要找到那个名字,可能还得带上老花镜慢慢找,找到之后再拿出算盘计算,最后再将结果写回到账本上。这整个过程想想都麻烦。相比之下,还是先在粉板上记一下方便。你想想,如果掌柜没有粉板的帮助,每次记账都得翻账本,效率是不是低得让人难以忍受?
同样,在 MySQL 里也有这个问题,如果每一次的更新操 ...
01基础架构:一条SQL查询语句是如何执行的?
MySQL 的基础架构
MySQL 大概可分为两个部分:Server 层和引擎层
mysql 的储存引擎是插件式的,只要遵循 mysql 的接口规范,就可以编写自己的储存引擎,如 Innodb,myisam,memory 等
Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
储存引擎层负责数据的存储和提取。从 MySQL5.5.5 版本开始,innodb 成为了默认的储存引擎
不同的储存引擎共用一个 Server 层
连接器
连接器负责跟客户端建立连接、获取权限、维持和管理连接。
mysql -h$ip -P$port -u$user -p
# $ip代表连接的ip,如果mysql服务器是在本地,则不需写-h$ip -P代表端口,如果采用默认端口3306,则不需填写
—u代表用户,p代表密码,你可以直接在命令行中输入密码,但容易造成密码泄露
连接命令中的 mysql 是客户端工具,用来跟服务端建 ...