谁能解释下这串代码中的for循环语句是怎么写出来的?

7.1 一个案例引发的多表连接

7.1.1 笛卡尔积(或交叉连接)的理解

笛卡尔乘积是一个数学运算。

假设我有两个集合 X 和 Y,那么 X 和 Y 的笛卡尔积就是 X 和 Y 的所有可能组合,也就是第一个对象来自于 X,第二个对象来自于 Y 的所有可能。组合的个数即为两个集合中元素个数的乘积数。

#查询员工姓名和所在部门名称 
  • 笛卡尔积的错误会在下面条件下产生
    • 省略多个表的连接条件(或关联条件)
    • 连接条件(或关联条件)无效
    • 所有表中的所有行互相连接
  • 为了避免笛卡尔积, 可以在WHERE加入有效的连接条件。

7.2 多表查询分类讲解

分类1:等值连接vs非等值连接

拓展1:区分重复的列名

  • 多个表中有相同列时,必须在列名之前加上表名前缀。
  • 使用别名可以简化查询。
  • 列名前使用表名前缀可以提高查询效率。

需要注意的是,如果我们使用了表的别名,在查询字段中、过滤条件中就只能使用别名进行代替,不能使用原有的表名,否则就会报错。

  • 连接n个表,至少需要n-1个连接条件。

分类2:自连接vs非自连接

#练习:查询员工id,员工姓名及其管理者的id和姓名

分类3:内连接 vs 外连接

  • 内连接: 合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行

  • 外连接: 两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的行 ,这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL)。

    • 如果是左外连接,则连接条件中左边的表也称为主表,右边的表称为从表
    • 如果是右外连接,则连接条件中右边的表也称为主表,左边的表称为从表

  • 使用JOIN...ON子句创建连接的语法结构:

利用Union关键字,可以给出多条SELECT语句,并将它们的结果组合成单个结果集。合并时,两个表对应的列数
和数据类型必须相同,并且相互对应。各个SELECT语句之间使用UNION或UNION ALL关键字分隔。

UNION 操作符返回两个查询的结果集的并集,去除重复记录。

UNION ALL操作符返回两个查询的结果集的并集。对于两个结果集的重复部分,不去重。

如果明确知道合并数据后的结果数据不存在重复数据,或者不需要去除重复的数据,则尽量使用UNION ALL语句,以提高数据查询的效率。

#实现查询结果是A∪B

# NATURAL JOIN : 它会帮你自动查询两张连接表中`所有相同的字段`,然后进行`等值连接`。
# 指定数据表里的同名字段进行等值连接,只能配合JOIN一起使用。

【强制】超过三个表禁止 join。需要 join 的字段,数据类型保持绝对一致;多表关联查询时,保证被关联的字段需要有索引。

说明:即使双表 join 也要注意表索引、SQL 性能。

返回X的符号。正数返回1,负数返回-1,0返回0
返回大于或等于某个值的最小整数
返回小于或等于某个值的最大整数
返回0~1的随机值,其中x的值用作种子值,相同的X值会产生相同的随机
返回一个对x的值进行四舍五入后,最接近于X的整数
返回一个对x的值进行四舍五入后最接近X的值,并保留到小数点后面Y位
返回数字x截断为y位小数的结果
返回x的平方根。当X的值为负数时,返回NULL

将角度转化为弧度,其中,参数x为角度值
将弧度转化为角度,其中,参数x为弧度值

返回x的正弦值,其中,参数x为弧度值
返回x的反正弦值,即获取正弦为x的值。如果x的值不在-1到1之间,则返回NULL
返回x的余弦值,其中,参数x为弧度值
返回x的反余弦值,即获取余弦为x的值。如果x的值不在-1到1之间,则返回NULL
返回x的正切值,其中,参数x为弧度值
返回x的反正切值,即返回正切值为x的值
返回两个参数的反正切值
返回x的余切值,其中,X为弧度值

返回e的X次方,其中e是一个常数,2.045
返回以e为底的X的对数,当X <= 0 时,返回的结果为NULL
返回以10为底的X的对数,当X <= 0 时,返回的结果为NULL

返回f1进制数变成f2进制数

返回字符串S中的第一个字符的ASCII码值
返回字符串s的字节数,和字符集有关
将字符串str从第idx位置开始,len个字符长的子串替换为字符串replacestr
用字符串b替换字符串str中所有出现的字符串a
将字符串s的所有字母转成大写字母
将字符串s的所有字母转成小写字母
返回字符串str最左边的n个字符
返回字符串str最右边的n个字符
用字符串pad对str最左边进行填充,直到str的长度为len个字符,实现右对齐效果
用字符串pad对str最右边进行填充,直到str的长度为len个字符,实现左对齐效果
去掉字符串s左侧的空格
去掉字符串s右侧的空格
去掉字符串s开始与结尾的空格
去掉字符串s开始与结尾的s1
去掉字符串s开始处的s1
去掉字符串s结尾处的s1
返回str重复n次的结果
比较字符串s1,s2的ASCII码值的大小
返回指定位置的字符串,如果m=1,则返回s1,如果m=2,则返回s2,如果m=n,则返回sn
返回字符串s在字符串列表中第一次出现的位置
返回字符串s1在字符串s2中出现的位置。其中,字符串s2是一个以逗号分隔的字符串

注意:MySQL中,字符串的位置是从1开始的。

8.3 日期和时间函数

8.3.1 获取日期、时间

返回当前日期,只包含年、月、日
返回当前时间,只包含时、分、秒
返回当前系统日期和时间
返回UTC(世界标准时间)日期
返回UTC(世界标准时间)时间

8.3.2 日期与时间戳的转换

将时间date以UNIX时间戳的形式返回。
将UNIX时间戳的时间转换为普通格式的时间

8.3.3 获取月份、星期、星期数、天数等函数

返回周几,注意,周1是0,周2是1,。。。周日是6
返回日期对应的季度,范围为1~4
返回日期是一年中的第几天
返回日期位于所在月份的第几天
返回周几,注意:周日是1,周一是2,。。。周六是7

8.3.4 日期的操作函数

返回指定日期中特定的部分,type指定返回的值
返回日期在一年中的第几个星期
返回日期在一年中的第几个月
返回日期在一年中的第几个季度

8.3.5 时间和秒钟转换的函数

将 time 转化为秒并返回结果值。转化的公式为: 小时*3600+分钟*60+秒
将 seconds 描述转化为包含小时、分钟和秒的时间

8.3.6 计算日期和时间的函数

返回与给定日期时间相差INTERVAL时间段的日期时间

上述函数中type的取值:

返回time1加上time2的时间。当time2为一个数字时,代表的是秒 ,可以为负数
返回time1减去time2后的时间。当time2为一个数字时,代表的是秒,可以为负数
返回从0000年1月1日起,N天以后的日期
返回日期date距离0000年1月1日的天数
返回date所在月份的最后一天的日期
针对给定年份与所在年份中的天数返回一个日期
将给定的小时、分钟和秒组合成时间并返回
返回time加上n后的时间

8.3.7 日期的格式化与解析

按照字符串fmt格式化日期date值
按照字符串fmt格式化时间time值
返回日期字符串的显示格式
按照字符串fmt对str进行解析,解析为一个日期

上述非GET_FORMAT函数中fmt参数常用的格式符:

两位数字表示月份(01,02,03。。。)
两位数字表示月中的天数(01,02...)
两位数字表示小数,24小时制(01,02..) 两位数字表示小时,12小时制(01,02..)
数字形式的小时,24小时制(1,2,3) 数字形式表示小时,12小时制(1,2,3,4....)
两位数字表示分钟(00,01,02)
一周中的星期名称(Sunday...)
以数字表示年中的第几周,(1,2,3。。)其中Sunday为周中第一天
以数字表示年中的第几周,(1,2,3。。)其中Monday为周中第一天

8.5 加密与解密函数

返回字符串str的加密版本,41位长的字符串。加密结果不可逆,常用于用户的密码加密。在mysql8.0中已弃用。
返回字符串str的md5加密后的值,也是一种加密方式。若参数为NULL,则会返回NULL
从原明文密码str计算并返回加密后的密码字符串,当参数为NULL时,返回NULL。 SHA加密算法比MD5更加安全 。

返回当前MySQL的版本号
返回当前MySQL服务器的连接数
返回MySQL命令行当前所在的数据库
返回当前连接MySQL的用户名,返回结果格式为“主机名@用户名”
返回字符串value自变量的字符集
返回字符串value的比较规则

返回对数字value进行格式化后的结果数据。n表示四舍五入后保留到小数点后n位
将value的值进行不同进制之间的转换
将以点分隔的IP地址转化为一个数字
将数字形式的IP地址转化为以点分隔的IP地址
将表达式expr重复执行n次。用于测试MySQL处理expr表达式所耗费的时间

可以对数值型数据使用AVG 和 SUM 函数。

可以对任意数据类型的数据使用 MIN 和 MAX 函数。

  • COUNT(*)返回表中记录总数,适用于任意数据类型

其实,对于MyISAM引擎的表是没有区别的。这种引擎内部有一计数器在维护着行数。

可以使用GROUP BY子句将表中的数据分成若干组

在SELECT列表中所有未包含在组函数中的列都应该包含在GROUP BY子句中

9.2.2 使用多个列分组

使用WITH ROLLUP关键字之后,在所有查询出的分组记录之后增加一条记录,该记录计算查询出的所有记录的总和,即统计记录数量。

当使用ROLLUP时,不能同时使用ORDER BY子句进行结果排序,即ROLLUP和ORDER BY是互相排斥的。

  • 非法使用聚合函数 : 不能在 WHERE 子句中使用聚合函数。

当过滤条件中有聚合函数时,则此过滤条件必须声明在HAVING中。

当过滤条件中没有聚合函数时,则此过滤条件声明在WHERE中或HAVING中都可以。但是,建议大家声明在WHERE中。

先筛选数据再关联,执行效率高 不能使用分组中的计算函数进行筛选
可以使用分组中的计算函数 在最后的结果集中进行筛选,执行效率较低

WHERE 多表的连接条件 AND 不包含组函数的过滤条件 HAVING 包含组函数的过滤条件 WHERE 不包含组函数的过滤条件 AND/OR 不包含组函数的过滤条件 HAVING 包含组函数的过滤条件 #(1)from:从哪些表中筛选 #(2)on:关联多表查询时,去除笛卡尔积 #(3)where:从表中筛选的条件 #(5)having:在统计结果中再次筛选

你需要记住 SELECT 查询时的两个顺序:

1. 关键字的顺序是不能颠倒的:

在 SELECT 语句执行这些步骤的时候,每个步骤都会产生一个虚拟表,然后将这个虚拟表传入下一个步骤中作为输入。

需要注意的是,这些步骤隐含在 SQL 的执行过程中,对于我们来说是不可见的。

SELECT 是先执行 FROM 这一步的。在这个阶段,如果是多张表联查,还会经历下面的几个步骤:

  1. 通过 ON 进行筛选,在虚拟表 vt1-1 的基础上进行筛选,得到虚拟表 vt1-2;

  2. 添加外部行。如果我们使用的是左连接、右连接或者全连接,就会涉及到外部行,也就是在虚拟表 vt1-2 的基础上增加外部行,得到虚拟表 vt1-3。

当然如果我们操作的是两张以上的表,还会重复上面的步骤,直到所有表都被处理完为止。这个过程得到是我们的原始数据。

当我们拿到了查询数据表的原始数据,也就是最终的虚拟表vt1,就可以在此基础上再进行WHERE阶段 。在这个阶段中,会根据 vt1 表的结果进行筛选过滤,得到虚拟表vt2

然后进入第三步和第四步,也就是GROUPHAVING阶段 。在这个阶段中,实际上是在虚拟表 vt2 的基础上进行分组和分组过滤,得到中间的虚拟表vt3vt4

当我们完成了条件筛选部分之后,就可以筛选表中提取的字段,也就是进入到SELECTDISTINCT阶段 。

首先在 SELECT 阶段会提取想要的字段,然后在 DISTINCT 阶段过滤掉重复的行,分别得到中间的虚拟表vt5-1vt5-2

当我们提取了想要的字段数据之后,就可以按照指定的字段进行排序,也就是ORDER BY阶段 ,得到虚拟表vt6

最后在 vt6 的基础上,取出指定行的记录,也就是LIMIT阶段 ,得到最终的结果,对应的是虚拟表vt7

当然我们在写 SELECT 语句的时候,不一定存在所有的关键字,相应的阶段就会省略。

同时因为 SQL 是一门类似英语的结构化查询语言,所以我们在写 SELECT 语句的时候,还要注意相应的关键字顺序,所谓底层运行的原理,就是我们刚才讲到的执行顺序。

10.1 需求分析与问题解决

题目:谁的工资比Abel高?

10.1.2 子查询的基本使用

  • 子查询(内查询)在主查询之前一次执行完成。
  • 子查询的结果被主查询(外查询)使用 。
  • 将子查询放在比较条件的右侧
  • 单行操作符对应单行子查询,多行操作符对应多行子查询

我们按内查询的结果返回一条还是多条记录,将子查询分为单行子查询多行子查询

我们按内查询是否被执行多次,将子查询划分为相关(或关联)子查询不相关(或非关联)子查询

题目:查询最低工资大于50号部门最低工资的部门id和其最低工资

10.2.5 子查询中的空值问题

需要和单行比较操作符一起使用,和子查询返回的某一个值比较
需要和单行比较操作符一起使用,和子查询返回的所有值比较
实际上是ANY的别名,作用相同,一般常使用ANY

题目:查询平均工资最低的部门id

MySQL中聚合函数是不能嵌套使用的。

10.4.1 相关子查询执行流程

如果子查询的执行依赖于外部查询,通常情况下都是因为子查询中的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重新计算一次,这样的子查询就称之为关联子查询

方式二:在 FROM 中使用子查询

结论:在SELECT中,除了GROUP BY 和 LIMIT之外,其他位置都可以声明子查询!

  • 关联子查询通常也会和 EXISTS操作符一起来使用,用来检查在子查询中是否存在满足条件的行。
  • 如果在子查询中不存在满足条件的行:
  • 如果在子查询中存在满足条件的行:
  • NOT EXISTS关键字表示如果不存在某种条件,则返回TRUE,否则返回FALSE。

题目中可以使用子查询,也可以使用自连接。一般情况建议你使用自连接,因为在许多 DBMS 的处理过程中,对于自连接的处理速度要比子查询快得多。

  1. Vector、ArrayList都是以类似数组的形式存储在内存中,LinkedList则以链表的形式进行存储。

  2. List中的元素有序、允许有重复的元素,Set中的元素无序、不允许有重复元素。

  3. LinkedList适合指定位置插入、删除操作,不适合查找;ArrayList、Vector适合查找,不适合指定位置的插入、删除操作。

  1. HashTable中hash数组的默认大小是11,增加方式的old*2+1,HashMap中hash数组的默认大小是16,增长方式一定是2的指数倍。

  2. TreeMap能够把它保存的记录根据键排序,默认是按升序排序。

不是很熟悉,相信也肯定有。

  • 镜像是大型网站常采用的提高性能和数据安全性的方式,镜像的技术可以解决不同网络接入商和地域带来的用户访问速度差异,比如ChinaNet和EduNet之间的差异就促使了很多网站在教育网内搭建镜像站点,数据进行定时更新或者实时更新。在镜像的细节技术方面,这里不阐述太深,有很多专业的现成的解决架构和产品可选。也有廉价的通过软件实现的思路,比如Linux上的rsync等工具。

  • 负载均衡将是大型网站解决高负荷访问和大量并发请求采用的终极解决办法。 负载均衡技术发展了多年,有很多专业的服务提供商和产品可以选择。

    第四层交换使用第三层和第四层信息包的报头信息,根据应用区间识别业务流,将整个区间段的业务流分配到合适的应用服务器进行处理。 第四层交换功能就象是虚IP,指向物理服务器。它传输的业务服从的协议多种多样,有HTTP、FTP、NFS、Telnet或其他协议。这些业务在物理服务器基础上,需要复杂的载量平衡算法。在IP世界,业务类型由终端TCP或UDP端口地址来决定,在第四层交换中的应用区间则由源端和终端IP地址、TCP和UDP端口共同决定。
    在硬件四层交换产品领域,有一些知名的产品可以选择,比如Alteon、F5等,这些产品很昂贵,但是物有所值,能够提供非常优秀的性能和很灵活的管理能力。Yahoo中国当初接近2000台服务器使用了三四台Alteon就搞定了。

  • 如果有一个特别大的访问量,到数据库上,怎么做优化(DB设计,DBIO,SQL优化,Java优化)

    如果出现大面积并发,在不增加服务器的基础上,如何解决服务器响应不及时问题

    假如你的项目出现性能瓶颈了,你觉得可能会是哪些方面,怎么解决问题。

    如何查找 造成 性能瓶颈出现的位置,是哪个位置照成性能瓶颈。

    你的项目中使用过缓存机制吗?有没用用户非本地缓存

    单例模式:饱汉、饿汉。以及饿汉中的延迟加载,双重检查

    工厂模式、装饰者模式、观察者模式。

    工厂方法模式的优点(低耦合、高内聚,开放封闭原则)

    列举出你说熟悉的设计模式,并对其中的一种的使用举一个例子。

    1. User user; 创建一个引用,内存分配在栈上
    2. = 将User对象地址赋值给引用

    Java的内存模型以及GC算法

    jvm性能调优都做了什么

    介绍JVM中7个区域,然后把每个区域可能造成内存的溢出的情况说明

    自己从classload 加载方式,加载机制说开去,从程序运行时数据区,讲到内存分配,讲到String常量池,讲到JVM垃圾回收机制,算法,hotspot。反正就是各种扩展

    jvm 如何分配直接内存, new 对象如何不分配在堆而是栈上,常量池解析

    数组多大放在 JVM 老年代(不只是设置 PretenureSizeThreshold ,问通常多大,没做过一问便知)

    老年代中数组的访问方式

    GC算法,永久代对象如何GC,GC有环怎么处理

    • 注意: 这种GC是full GC 堆空间也会一并被GC一次

    1. 垃圾回收器从被称为GC Roots的点开始遍历遍历对象,凡是可以达到的点都会标记为存活,堆中不可到达的对象都会标记成垃圾,然后被清理掉。

      • 类,由系统类加载器加载的类。这些类从不会被卸载,它们可以通过静态属性的方式持有对象的引用。

      注意,一般情况下由自定义的类加载器加载的类不能成为GC Roots

      • Java方法栈中的局部变量或者参数

      • JNI方法栈中的局部变量或者参数

      • 被JVM持有的对象,这些对象由于特殊的目的不被GC回收。这些对象可能是系统的类加载器,一些重要的异常处理类,一些为处理异常预留的对象,以及一些正在执行类加载的自定义的类加载器。但是具体有哪些前面提到的对象依赖于具体的JVM实现。

    2. 基于引用对象遍历的垃圾回收器可以处理循环引用,只要是涉及到的对象不能从GC Roots强引用可到达,垃圾回收器都会进行清理来释放内存。

    谁会被GC,什么时候GC

    如果想在 GC 中生存 1 次怎么办

    生存一次,释放掉对象的引用,但是在对象的finalize方法中重新建立引用,但是此方法只会被调用一次,所以能在GC中生存一次。

    当你将你的应用从 32 位的 JVM 迁移到 64 位的 JVM 时,由于对象的指针从 32 位增加到了 64 位,因此堆内存会突然增加,差不多要翻倍。这也会对 CPU 缓存(容量比内存小很多)的数据产生不利的影响。因为,迁移到 64 位的 JVM 主要动机在于可以指定最大堆大小,通过压缩 OOP 可以节省一定的内存。通过 -XX:+UseCompressedOops

    写代码分别使得JVM的堆、栈和持久代发生内存溢出(栈溢出)

    简单谈谈堆外内存以及你的理解和认识

    JVM老年代和新生代的比例?

    栈是运行时的单位,而堆是存储的单位。

    栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;堆解决的是数据存储的问题,即数据怎么放、放在哪儿。

    在Java中一个线程就会相应有一个线程栈与之对应,这点很容易理解,因为不同的线程执行逻辑有所不同,因此需要一个独立的线程栈。而堆则是所有线程共享的。栈因为是运行单位,因此里面存储的信息都是跟当前线程(或程序)相关信息的。包括局部变量、程序运行状态、方法返回值等等;而堆只负责存储对象信息。

    为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗?

    1. 从软件设计的角度看,栈代表了处理逻辑,而堆代表了数据。这样分开,使得处理逻辑更为清晰。分而治之的思想。这种隔离、模块化的思想在软件设计的方方面面都有体现。
    2. 堆与栈的分离,使得堆中的内容可以被多个栈共享(也可以理解为多个线程访问同一个对象)。这种共享的收益是很多的。一方面这种共享提供了一种有效的数据交互方式(如:共享内存),另一方面,堆中的共享常量和缓存可以被所有栈访问,节省了空间。
    3. 栈因为运行时的需要,比如保存系统运行的上下文,需要进行地址段的划分。由于栈只能向上增长,因此就会限制住栈存储内容的能力。而堆不同,堆中的对象是可以根据需要动态增长的,因此栈和堆的拆分,使得动态增长成为可能,相应栈中只需记录堆中的一个地址即可。
    4. 面向对象就是堆和栈的完美结合。其实,面向对象方式的程序与以前结构化的程序在执行上没有任何区别。但是,面向对象的引入,使得对待问题的思考方式发生了改变,而更接近于自然方式的思考。当我们把对象拆开,你会发现,对象的属性其实就是数据,存放在堆中;而对象的行为(方法),就是运行逻辑,放在栈中。我们在编写对象的时候,其实即编写了数据结构,也编写的处理数据的逻辑。不得不承认,面向对象的设计,确实很美。

    为什么不把基本类型放堆中呢?

    因为其占用的空间一般是1~8个字节——需要空间比较少,而且因为是基本类型,所以不会出现动态增长的情况——长度固定,因此栈中存储就够了,如果把他存在堆中是没有什么意义的(还会浪费空间,后面说明)。可以这么说,基本类型和对象的引用都是存放在栈中,而且都是几个字节的一个数,因此在程序运行时,他们的处理方式是统一的。但是基本类型、对象引用和对象本身就有所区别了,因为一个是栈中的数据一个是堆中的数据。最常见的一个问题就是,Java中参数传递时的问题。

    堆中存什么?栈中存什么?

    堆中存的是对象。栈中存的是基本数据类型和堆中对象的引用。一个对象的大小是不可估计的,或者说是可以动态变化的,但是在栈中,一个对象只对应了一个4btye的引用(堆栈分离的好处:))。

    为什么不把基本类型放堆中呢?因为其占用的空间一般是1~8个字节——需要空间比较少,而且因为是基本类型,所以不会出现动态增长的情况——长度固定,因此栈中存储就够了,如果把他存在堆中是没有什么意义的(还会浪费空间,后面说明)。可以这么说,基本类型和对象的引用都是存放在栈中,而且都是几个字节的一个数,因此在程序运行时,他们的处理方式是统一的。但是基本类型、对象引用和对象本身就有所区别了,因为一个是栈中的数据一个是堆中的数据。最常见的一个问题就是,Java中参数传递时的问题。

    Java中的参数传递时传值呢?还是传引用?

    要说明这个问题,先要明确两点:

    1. 不要试图与C进行类比,Java中没有指针的概念

    2. 程序运行永远都是在栈中进行的,因而参数传递时,只存在传递基本类型和对象引用的问题。不会直接传对象本身。

    明确以上两点后。Java在方法调用传递参数时,因为没有指针,所以它都是进行传值调用(这点可以参考C的传值调用)。因此,很多书里面都说Java是进行传值调用,这点没有问题,而且也简化的C中复杂性。

    但是传引用的错觉是如何造成的呢?在运行栈中,基本类型和引用的处理是一样的,都是传值,所以,如果是传引用的方法调用,也同时可以理解为“传引用值”的传值调用,即引用的处理跟基本类型是完全一样的。但是当进入被调用方法时,被传递的这个引用的值,被程序解释(或者查找)到堆中的对象,这个时候才对应到真正的对象。如果此时进行修改,修改的是引用对应的对象,而不是引用本身,即:修改的是堆中的数据。所以这个修改是可以保持的了。

    对象,从某种意义上说,是由基本类型组成的。可以把一个对象看作为一棵树,对象的属性如果还是对象,则还是一颗树(即非叶子节点),基本类型则为树的叶子节点。程序参数传递时,被传递的值本身都是不能进行修改的,但是,如果这个值是一个非叶子节点(即一个对象引用),则可以修改这个节点下面的所有内容。

    堆和栈中,栈是程序运行最根本的东西。程序运行可以没有堆,但是不能没有栈。而堆是为栈进行数据存储服务,说白了堆就是一块共享的内存。不过,正是因为堆和栈的分离的思想,才使得Java的垃圾回收成为可能。

    Java中,栈的大小通过-Xss来设置,当栈中存储数据比较多时,需要适当调大这个值,否则会出现java.lang.StackOverflowError异常。常见的出现这个异常的是无法返回的递归,因为此时栈中保存的信息都是方法返回的记录点

    对象引用类型分为哪几类?

    讲一讲内存分代及生命周期。

    什么情况下触发垃圾回收?

    如何选择合适的垃圾收集算法?

    JVM给了三种选择:串行收集器、并行收集器、并发收集器 ,但是串行收集器只适用于小数据量的情况,所以这里的选择主要针对并行收集器和并发收集器。默认情况下,JDK5.0以前都是使用串行收集器,如果想使用其他收集器需要在启动时加入相应参数。JDK5.0以后,JVM会根据当前系统配置 进行判断。

    吞吐量优先的并行收集器

    如上文所述,并行收集器主要以到达一定的吞吐量为目标,适用于科学技术和后台处理等。

    -XX:+UseParallelGC :选择垃圾收集器为并行收集器。 此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。 -XX:ParallelGCThreads=20 :配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。 -XX:+UseParallelOldGC :配置年老代垃圾收集方式为并行收集。JDK6.0支持对年老代并行收集。 -XX:MaxGCPauseMillis=100 : 设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值。 -XX:+UseAdaptiveSizePolicy :设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开。

    响应时间优先的并发收集器

    如上文所述,并发收集器主要是保证系统的响应时间,减少垃圾收集时的停顿时间。适用于应用服务器、电信领域等。

    :设置年老代为并发收集。测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明。所以,此时年轻代大小最好用-Xmn设置。 -XX:+UseParNewGC :设置年轻代为并行收集。可与CMS收集同时使用。JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值。 -XX:CMSFullGCsBeforeCompaction :由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。

    JVM中最大堆大小有没有限制?

    如何进行JVM调优?有哪些方法?

    如何理解内存泄漏问题?有哪些情况会导致内存泄露?如何解决?

    spring框架中需要引用哪些jar包,以及这些jar包的用途

    spring注入的几种方式(循环注入)

    spring如何实现事务管理的

    回答为什么要用什么方法这种问题的时候,通常首先要回答两个问题,第一个就是,我要做什么事情,第二个就是,不同方法的优劣是什么。

    首先,我要做什么事情。

    这里的回答比较简单,就是代理Java类/接口。那么,两者在完成这件事情上,有什么差别呢

    以继承的方式完成代理,不能代理被final修饰的类

    实际上,大部分的Java类都会以接口-实现的方式来完成,因此,在这个方面上,JDK Proxy实际上是比Cglib Proxy要更胜一筹的。因为如果一个类被final修饰,则Cglib Proxy无法进行代理。

    其次,两种方法的优劣又在什么地方呢?

    我们可以参考一下来自bytebuddy的数据,这个是在代理一个实现了具有18个方法的接口的类,时间单位为ns。

    不难看出,其实Cglib代理的性能是要远远好于JDK代理的。

    其实从原理也能理解,直接通过类的方法调用,肯定要比通过反射调用的时间更短。但是从来源来看的话,一个是JDK原生代码,而另一个则是第三方的开源库。JDK原生代码无疑使用的人会更多范围也更广,会更佳稳定,而且还有可能在未来的JDK版本中不断优化性能。

    而Cglib更新频率相对来说比较低了,一方面是因为这个代码库已经渐趋稳定,另一方面也表明后续这个库可能相对来说不会有大动作的优化维护。

    对比完之后,再来回看这个问题,为什么要使用两种方式呢?

    在功能上讲,实际上Cglib代理并不如JDK代理(如果大家都按接口-实现的方式来设计类)。但是从效率上将,Cglib远胜JDK代理啊!所以,为了提高效率,同时又保有在未来,当JDK代理的性能也能够同样好的时候,使用更佳稳定靠谱的JDK代码,这种可能,于是采取了这种设计。

    hibernate中的1级和2级缓存的使用方式以及区别原理(Lazy-Load的理解)

    Hibernate的原理体系架构,五大核心接口,Hibernate对象的三种状态转换,事务管理。

    Spring Boot设置有效时间和自动刷新缓存,时间支持在配置文件中配置

    spring中用到哪些设计模式?

    用redis做过什么;

    redis集群如何同步;

    redis的数据添加过程是怎样的:哈希槽;

    redis的淘汰策略有哪些;

    redis有哪些数据结构;

    redis的单线程模型

    • 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
    • 节点的fail是通过集群中超过半数的master节点检测失效时才生效.
    • 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
    • 如果进群超过半数以上master挂掉,无论是否有slave集群进入fail状态,所以集群中至少应该有奇数个节点,所以至少有三个节点,每个节点至少有一个备份节点,
    • redis cluster 为了保证数据的高可用性,加入了主从模式,一个主节点对应一个或多个从节点,主节点提供数据存取,从节点则是从主节点拉取数据备份,当这个主节点挂掉后,就会有这个从节点选取一个来充当主节点,从而保证集群不会挂掉。

    你们的zookeeper的节点加密是用的什么方式

    • At most once:消息可能会丢,但绝不会重复传递。
    • At least once:消息绝不会丢,但可能会重复传递。

    当生产者向Kafka发送消息,且正常得到响应的时候,可以确保生产者不会产生重复的消息。但是,如果生产者发送消息后,遇到网络问题,无法获取响应,生产者就无法判断该消息是否成功提交给了Kafka。根据生产者的机制,我们知道,当出现异常时,会进行消息重传,这就可能出现“At least one”语义。为了实现“Exactly once”语义,这里提供两个可选方案:

    • 每个分区只有一个生产者写入消息,当出现异常或超时的情况时,生产者就要查询此分区的最后一个消息,用来决定后续操作是消息重传还是继续发送。
    • 为每个消息添加一个全局唯一主键,生产者不做其他特殊处理,按照之前分析方式进行重传,由消费者对消息进行去重,实现“Exactly once”语义。

    如果业务数据产生消息可以找到合适的字段作为主键,或是有一个全局ID生成器,可以优先考虑选用第二种方案。

    为了实现消费者的“Exactly once”语义,在这里提供一种方案,供读者参考:消费者将关闭自动提交offset的功能且不再手动提交offset,这样就不使用Offsets Topic这个内部Topic记录其offset,而是由消费者自己保存offset。这里利用事务的原子性来实现“Exactly once”语义,我们将offset和消息处理结果放在一个事务中,事务执行成功则认为此消息被消费,否则事务回滚需要重新消费。当出现消费者宕机重启或Rebalance操作时,消费者可以从关系型数据库中找到对应的offset,然后调用KafkaConsumer.seek()方法手动设置消费位置,从此offset处开始继续消费。

    ISR(In-SyncReplica)集合表示的是目前“可用”(alive)且消息量与Leader相差不多的副本集合,这是整个副本集合的一个子集。“可用”和“相差不多”都是很模糊的描述,其实际含义是ISR集合中的副本必须满足下面两个条件:

    1. 副本所在节点必须维持着与ZooKeeper的连接。
    2. 副本最后一条消息的offset与Leader副本的最后一条消息的offset之间的差值不能超出指定的阈值。

    每个分区中的Leader副本都会维护此分区的ISR集合。写请求首先由Leader副本处理,之后Follower副本会从Leader上拉取写入的消息,这个过程会有一定的延迟,导致Follower副本中保存的消息略少于Leader副本,只要未超出阈值都是可以容忍的。如果一个Follower副本出现异常,比如:宕机,发生长时间GC而导致Kafka僵死或是网络断开连接导致长时间没有拉取消息进行同步,就会违反上面的两个条件,从而被Leader副本踢出ISR集合。当Follower副本从异常中恢复之后,会继续与Leader副本进行同步,当Follower副本“追上”(即最后一条消息的offset的差值小于指定阈值)Leader副本的时候,此Follower副本会被Leader副本重新加入到ISR中。

    Apache Kafka是由Apache开发的一种发布订阅消息系统,它是一个分布式的、分区的和重复的日志服务。

    请说明什么是传统的消息传递方法?

    传统的消息传递方法包括两种:

    • 排队:在队列中,一组用户可以从服务器中读取消息,每条消息都发送给其中一个人。

    • 发布-订阅:在这个模型中,消息被广播给所有的用户。

    请说明Kafka相对传统技术有什么优势?

    Apache Kafka与传统的消息传递技术相比优势之处在于:

    • 快速:单一的Kafka代理可以处理成千上万的客户端,每秒处理数兆字节的读写操作。

    • 可伸缩:在一组机器上对数据进行分区和简化,以支持更大的数据

    • 持久:消息是持久性的,并在集群中进行复制,以防止数据丢失

    • 设计:它提供了容错保证和持久性

    在Kafka集群中,broker术语用于引用服务器。

    Kafka服务器能接收到的最大信息是多少?

    Kafka服务器可以接收到的消息的最大大小是1000000字节。

    Zookeeper是一个开放源码的、高性能的协调服务,它用于Kafka的分布式应用。

    不,不可能越过Zookeeper,直接联系Kafka broker。一旦Zookeeper停止工作,它就不能服务客户端请求。

    Zookeeper主要用于在集群中不同节点之间进行通信

    在Kafka中,它被用于提交偏移量,因此如果节点在任何情况下都失败了,它都可以从之前提交的偏移量中获取

    除此之外,它还执行其他活动,如: leader检测、分布式同步、配置管理、识别新节点何时离开或连接、集群、节点实时状态等等。

    解释Kafka的用户如何消费信息?

    在Kafka中传递消息是通过使用sendfile API完成的。它支持将字节从套接口转移到磁盘,通过内核空间保存副本,并在内核用户之间调用内核。

    解释如何提高远程用户的吞吐量?

    如果用户位于与broker不同的数据中心,则可能需要调优套接口缓冲区大小,以对长网络延迟进行摊销。

    解释一下,在数据制作过程中,你如何能从Kafka得到准确的信息?

    在数据中,为了精确地获得Kafka的消息,你必须遵循两件事: 在数据消耗期间避免重复,在数据生产过程中避免重复。

    这里有两种方法,可以在数据生成时准确地获得一个语义:

    • 每个分区使用一个单独的写入器,每当你发现一个网络错误,检查该分区中的最后一条消息,以查看您的最后一次写入是否成功

    • 在消息中包含一个主键(UUID或其他),并在用户中进行反复制

    解释如何减少ISR中的扰动?broker什么时候离开ISR?

    ISR是一组与leaders完全同步的消息副本,也就是说ISR中包含了所有提交的消息。ISR应该总是包含所有的副本,直到出现真正的故障。如果一个副本从leader中脱离出来,将会从ISR中删除。

    Kafka为什么需要复制?

    Kafka的信息复制确保了任何已发布的消息不会丢失,并且可以在机器错误、程序错误或更常见些的软件升级中使用。

    如果副本在ISR中停留了很长时间表明什么?

    如果一个副本在ISR中保留了很长一段时间,那么它就表明,跟踪器无法像在leader收集数据那样快速地获取数据。

    请说明如果首选的副本不在ISR中会发生什么?

    如果首选的副本不在ISR中,控制器将无法将leadership转移到首选的副本。

    有可能在生产后发生消息偏移吗?

    在大多数队列系统中,作为生产者的类无法做到这一点,它的作用是触发并忘记消息。broker将完成剩下的工作,比如使用id进行适当的元数据处理、偏移量等。

    作为消息的用户,你可以从Kafka broker中获得补偿。如果你注视SimpleConsumer类,你会注意到它会获取包括偏移量作为列表的MultiFetchResponse对象。此外,当你对Kafka消息进行迭代时,你会拥有包括偏移量和消息发送的MessageAndOffset对象。

    kafka与传统的消息中间件对比

    KAFKA:如何做到1秒发布百万级条消息

    据kafka官网吹,如果随机写入磁盘,速度就只有100KB每秒。顺序写入的话,7200转/s的磁盘就能达到惊人的600MB每秒!

    操作系统对文件访问做了优化,文件会在内核空间分页做缓存(pageCache)。写入时先写入pageCache。由操作系统来决定何时统一写入磁盘。操作系统会使用顺序写入。

    默认使用的是什么通信框架,还有别的选择吗?

    默认也推荐使用netty框架,还有mina。

    默认是阻塞的,可以异步调用,没有返回值的可以这么做。

    一般使用什么注册中心?还有别的选择吗?

    推荐使用zookeeper注册中心,还有redis等不推荐。

    默认使用什么序列化框架,你知道的还有哪些?

    服务提供者能实现失效踢出是什么原理?

    服务失效踢出基于zookeeper的临时节点原理。

    服务上线怎么不影响旧版本?

    采用多版本开发,不影响旧版本。

    如何解决服务调用链过长的问题?

    可以结合zipkin实现分布式服务追踪。

    说说核心的配置有哪些?

    dubbo推荐用什么协议?

    默认使用dubbo协议。

    同一个服务多个注册的情况下可以直连某一个服务吗?

    可以直连,修改配置即可,也可以通过telnet直接某个服务。

    画一画服务注册与发现的流程图

    Dubbo集群容错怎么做?

    读操作建议使用Failover失败自动切换,默认重试两次其他服务器。写操作建议使用Failfast快速失败,发一次调用失败就立即报错。

    在使用过程中都遇到了些什么问题?

    使用过程中的问题可以百度

    dubbox是当当网基于dubbo上做了一些扩展,如加了服务可restful调用,更新了开源组件等。

    你还了解别的分布式框架吗?

    使用随机算法产生一个数,要求把1-1000W之间这些数全部生成。(考察高效率,解决产生冲突的问题)

    两个有序数组的合并排序

    计算一个正整数的正平方根

    说白了就是常见的那些查找、排序算法以及各自的时间复杂度

    比较重要的数据结构,如链表,队列,栈的基本理解及大致实现。

    排序算法与时空复杂度(快排为什么不稳定,为什么你的项目还在用)

    如何给100亿个数字排序?

    统计海量数据中出现次数最多的前10个IP

    重构过代码没有?说说经验;

    一千万的用户实时排名如何实现;

    五万人并发抢票怎么实现;

    有个每秒钟5k个请求,查询手机号所属地的笔试题(记得不完整,没列出),如何设计算法?请求再多,比如5w,如何设计整个系统?

    高并发情况下,我们系统是如何支撑大量的请求的

    如果有一个特别大的访问量,到数据库上,怎么做优化(DB设计,DBIO,SQL优化,Java优化)

    如果出现大面积并发,在不增加服务器的基础上,如何解决服务器响应不及时问题“。

    假如你的项目出现性能瓶颈了,你觉得可能会是哪些方面,怎么解决问题。

    如何查找 造成 性能瓶颈出现的位置,是哪个位置照成性能瓶颈。

    你的项目中使用过缓存机制吗?有没用用户非本地缓存

    http是无状态通信,http的请求方式有哪些,可以自己定义新的请求方式么。

    socket通信,以及长连接,分包,连接异常断开的处理。

    socket框架netty的使用,以及NIO的实现原理,为什么是异步非阻塞。

    同步和异步,阻塞和非阻塞。

    OSI七层模型,包括TCP,IP的一些基本知识

    • get: 从服务器上获取数据,也就是所谓的查,仅仅是获取服务器资源,不进行修改。
    • post: 向服务器提交数据,这就涉及到了数据的更新,也就是更改服务器的数据。
    • 请求方式的区别: get 请求的数据会附加在URL之后,特定的浏览器和服务器对URL的长度有限制. post 更加安全数据不会暴漏在url上,而且长度没有限制.

    说说浏览器访问,经历了怎样的过程。

    HTTP协议、 HTTPS协议,SSL协议及完整交互过程;

    tcp的拥塞,快回传,ip的报文丢弃

    https处理的一个过程,对称加密和非对称加密

    head各个特点和区别

    Http会话的四个过程

    建立连接,发送请求,返回响应,关闭连接。

    MySql的存储引擎的不同

    单个索引、联合索引、主键索引

    Mysql怎么分表,以及分表后如果想按条件分页查询怎么办(如果不是按分表字段来查询的话,几乎效率低下,无解)

    如果按时间排序查询,使用limit n (不要使用limit m, n 页数多了之后效率低)然后记录最后一条的时间,下次从最后一条的时间开始查询

    分表之后想让一个id多个表是自增的,效率实现

    MySql的主从实时备份同步的配置,以及原理(从库读主库的binlog),读写分离

    事务的四个特性,以及各自的特点(原子、隔离)等等,项目怎么解决这些问题

    数据库的锁:行锁,表锁;乐观锁,悲观锁

    数据库事务的几种粒度;

    关系型和非关系型数据库区别

    • 关系型数据库:是指采用了关系模型(二维表格模型)来组织数据的数据库。
    • 非关系型数据库:以键值对存储,且结构不固定.

    kill的用法,某个进程杀不掉的原因(进入内核态,忽略kill信号)

    进程间的通信,共享内存方式的优缺点

    取值为0,系统在为应用进程分配虚拟地址空间时,会判断当前申请的虚拟地址空间大小是否超过剩余内存大小,如果超过,则虚拟地址空间分配失败。因此,也就是如果进程本身占用的虚拟地址空间比较大或者剩余内存比较小时,fork、malloc等调用可能会失败。

    取值为1,系统在为应用进程分配虚拟地址空间时,完全不进行限制,这种情况下,避免了fork可能产生的失败,但由于malloc是先分配虚拟地址空间,而后通过异常陷入内核分配真正的物理内存,在内存不足的情况下,这相当于完全屏蔽了应用进程对系统内存状态的感知,即malloc总是能成功,一旦内存不足,会引起系统OOM杀进程,应用程序对于这种后果是无法预测的

    取值为2,则是根据系统内存状态确定了虚拟地址空间的上限,由于很多情况下,进程的虚拟地址空间占用远大小其实际占用的物理内存,这样一旦内存使用量上去以后,对于一些动态产生的进程(需要复制父进程地址空间)则很容易创建失败,如果业务过程没有过多的这种动态申请内存或者创建子进程,则影响不大,否则会产生比较大的影响

    linux系统下查看CPU、内存负载情况


我要回帖

更多关于 c程序for循环怎么写 的文章

 

随机推荐