Java常见问题
- 一、Mybatis部分
- 1. 什么是 Mybatis?
- 2. Mybaits 的优点
- 3. MyBatis 框架的缺点
- 4. MyBatis 框架适用场合
- 5. MyBatis与Hibernate有哪些不同?
- 6. #{}和${}的区别是什么?
- 7. 当实体类中的属性名和表中的字段名不一样,怎么办?
- 8. 模糊查询 like 语句该怎么写?
- 9. 通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应,请问,这个 Dao 接口的工作原理是什么?Dao 接口里的方法,参数不同时,方法能重载吗?
- 10. Mybatis 是如何进行分页的?分页插件的原理是什么?
- 11. Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
- 12. 如何执行批量插入?
- 13. 如何获取自动生成的(主)键值?
- 14. 在 mapper 中如何传递多个参数?
- 15. Mybatis 动态 sql 有什么用?执行原理?有哪些动态 sql?
- 16. Xml 映射文件中,除了常见的 select | insert | updae | delete 标签之外,还有哪些标签?
- 17. Mybatis 的 Xml 映射文件中,不同的 Xml 映射文件,id 是否可以重复?
- 18. 为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?
- 19. 一对一、一对多的关联查询 ?
- 20. MyBatis 实现一对一有几种方式?具体怎么操作的?
- 21. MyBatis 实现一对多有几种方式,怎么操作的?
- 22. Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么?
- 23. Mybatis 的一级、二级缓存
- 24. 什么是 MyBatis 的接口绑定?有哪些实现方式?
- 24. 使用 MyBatis 的 mapper 接口调用时有哪些要求?
- 25. Mapper 编写有哪几种方式?
- 27. 简述 Mybatis 的插件运行原理,以及如何编写一个插件。
- 二、Zookeeper部分
- 三、Dubbo部分
- 四、Elasticsearch部分
- 五、Memcached部分
- 六、Redis部分
- 1. 什么是 Redis?
- 2. Redis 的数据类型?
- 3. 使用 Redis 有哪些好处?
- 4. Redis 相比 Memcache 有哪些优势?
- 5. Memcache 与 Redis 的区别都有哪些?
- 6. Redis 是单进程单线程的?
- 7. 一个字符串类型的值能存储最大容量是多少?
- 8. Redis 的持久化机制是什么?各自的优缺点?
- 9. Redis 常见性能问题和解决方案
- 10. redis 过期键的删除策略?
- 11. Redis 的回收策略(淘汰策略)?
- 12. 为什么 Redis 需要把所有数据放到内存中?
- 13. Redis 的同步机制了解么?
- 14. Pipeline 有什么好处,为什么要用 pipeline?
- 15. 是否使用过 Redis 集群,集群的原理是什么?
- 16. Redis 集群方案什么情况下会导致整个集群不可用?
- 17. Redis 支持的 Java 客户端都有哪些?官方推荐用哪个?
- 18. Jedis 与 Redisson 对比有什么优缺点?
- 19. Redis 如何设置密码及验证密码?
- 20. 说说 Redis 哈希槽的概念?
- 21. Redis 集群的主从复制模型是怎样的?
- 22. Redis 集群会有写操作丢失吗?为什么?
- 23. Redis 集群之间是如何复制的?
- 七、MySQL部分
- 八、Java并发编程1
- 九、Java并发编程2
- 十、Java基础1
- 十一、Java基础2
- 十二、Spring部分1
- 十三、Spring部分2
- 十四、微服务部分
- 十五、Linux部分
- 十六、SpringBoot部分
- 十七、SpringCloud部分
- 十八、RabbitMQ部分
- 十九、Kafka部分
一、Mybatis部分
1. 什么是 Mybatis?
Mybatis
是一个半ORM
(对象关系映射)框架,它内部封装了JDBC
,开发时只需要关注SQL
语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement
等繁杂的过程。程序员直接编写原生态sql
,可以严格控制sql
执行性能,灵活度高。MyBatis
可以使用XML
或注解来配置和映射原生信息,将POJO
映射成数据库中的记录,避免了几乎所有的JDBC
代码和手动设置参数以及获取结果集。- 通过
xml
文件或注解的方式将要执行的各种statement
配置起来,并通过java
对象和statement
中sql
的动态参数进行映射生成最终执行的sql
语句,最后由mybatis
框架执行sql
并将结果映射为java
对象并返回。(从执行sql
到返回result
的过程)。
2. Mybaits 的优点
- 基于
SQL
语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL
写在XML
里,解除sql
与程序代码的耦合,便于统一管理;提供 XML标签,支持编写动态SQL
语句,并可重用。 - 与
JDBC
相比,减少了 50%以上的代码量,消除了JDBC
大量冗余的代码,不需要手动开关连接。 - 很好的与各种数据库兼容(因为
MyBatis
使用JDBC
来连接数据库,所以只要JDBC
支持的数据库MyBatis
都支持)。 - 能够与
Spring
很好的集成。 - 提供映射标签,支持对象与数据库的
ORM
字段关系映射;提供对象关系映射标签,支持对象关系组件维护。
3. MyBatis 框架的缺点
SQL
语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL
语句的功底有一定要求。SQL
语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
4. MyBatis 框架适用场合
MyBatis
专注于SQL
本身,是一个足够灵活的DAO
层解决方案。- 对性能的要求很高,或者需求变化较多的项目,如互联网项目,
MyBatis
将是不错的选择。
5. MyBatis与Hibernate有哪些不同?
Mybatis
和hibernate
不同,它不完全是一个ORM
框架,因为MyBatis
需要程序员自己编写Sql
语句。Mybatis
直接编写原生态sql
,可以严格控制sql
执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是mybatis
无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql
映射文件,工作量大。Hibernate
对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate
开发可以节省很多代码,提高效率。
6. #{}和${}的区别是什么?
- #{}是预编译处理,${}是字符串替换。
Mybatis
在处理#{}时,会将sql
中的#{}替换为?号,调用PreparedStatement
的set
方法来赋值。Mybatis
在处理 时 , 就 是 把 {}时,就是把 时,就是把{}替换成变量的值。- 使用#{}可以有效的防止
SQL
注入,提高系统安全性。
7. 当实体类中的属性名和表中的字段名不一样,怎么办?
- 通过在查询的
sql
语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。
<select id=”selectorder” parametertype=”int” resultetype=”me.gacl.domain.order”>
select order_id id, order_no orderno ,order_price price
form orders
where order_id=#{id};
</select>
- 通过
<resultMap>
来映射字段名和实体类属性名的一一对应的关系。
<select id="getOrder" parameterType="int" resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>
<resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
<!-- 用 id 属性来映射主键字段 -->
<id property=”id” column=”order_id”>
<!-- result 属性来映射非主键字段,property 为实体类属性名,column为数据表中的属性 -->
<result property = “orderno” column =”order_no”/>
<result property=”price” column=”order_price” />
</reslutMap>
8. 模糊查询 like 语句该怎么写?
- 在
Java
代码中添加sql
通配符。
String wildcardname = "%smi%";
List<Name> names = mapper.selectlike(wildcardname);
<select id=”selectlike”>
select * from foo where bar like #{value}
</select>
- 在
sql
语句中拼接通配符,会引起sql
注入。
String wildcardname = "smi";
List<Name> names = mapper.selectlike(wildcardname);
<select id=”selectlike”>
select * from foo where bar like "%"#{value}"%"
</select>
9. 通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应,请问,这个 Dao 接口的工作原理是什么?Dao 接口里的方法,参数不同时,方法能重载吗?
Dao
接口即Mapper
接口。接口的全限名,就是映射文件中的namespace
的值;接口的方法名,就是映射文件中Mapper
的Statement
的id
值;接口方法内的参数,就是传递给sql
的参数。Mapper
接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key
值,可唯一定位一个MapperStatement
。在Mybatis
中,每一个< select>
、< insert>
、< update>
、< delete>
标签,都会被解析为一个MapperStatement
对象。Mapper
接口里的方法,是不能重载的,因为是使用 全限名+方法名 的保存和寻找策略。Mapper
接口的工作原理是JDK
动态代理,Mybatis
运行时会使用JDK
动态代理为Mapper
接口生成代理对象proxy
,代理对象会拦截接口方法,转而执行MapperStatement
所代表的sql
,然后将sql
执行结果返回。
10. Mybatis 是如何进行分页的?分页插件的原理是什么?
Mybatis
使用RowBounds
对象进行分页,它是针对ResultSet
结果集执行的内存分页,而非物理分页。可以在sql
内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。- 分页插件的基本原理是使用
Mybatis
提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql
,然后重写sql
,根据dialect
方言,添加对应的物理分页语句和物理分页参数。
11. Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
- 使用
<resultMap>
标签,逐一定义数据库列名和对象属性名之间的映射关系。 - 使用
sql
列的别名功能,将列的别名书写为对象属性名。 - 有了列名与属性名的映射关系后,
Mybatis
通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
12. 如何执行批量插入?
- 创建一个简单的
insert
语句:
<insert id=”insertname”>
insert into names (name) values (#{value})
</insert>
- 在
java
代码中执行批处理插入:
List<String> names = new ArrayList();
names.add("fred");
names.add("barney");
names.add("betty");
names.add("wilma");
// 注意这里 ExecutorType.BATCH
SqlSession session = getSqlSessionFactory().openSession(ExecutorType.BATCH);
try {
Namemapper mapper = sqlsession.getmapper(Namemapper.class);
for (String name : names) {
mapper.insertname(name);
}
sqlsession.commit();
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
sqlsession.close();
}
13. 如何获取自动生成的(主)键值?
insert
方法总是返回一个int
值 ,这个值代表的是插入的行数。- 如果采用自增长策略,自动生成的键值在
insert
方法执行完后可以被设置到传入
的参数对象中。
<insert id="insertName" useGeneratedKeys="true" keyProperty="id">
insert into names (name) values (#{name})
</insert>
Names name = new Names();
name.setName("fred");
int rows = mapper.insertName(name);
//完成后,id 已经被设置到对象中
System.out.println("rows inserted = " + rows);
System.out.println("generated key value = " + name.getId());
14. 在 mapper 中如何传递多个参数?
DAO
层的函数(实验未成功)。
<!--对应的 xml,#{0}代表接收的是 dao 层中的第一个参数,#{1}代表 dao 层中第二
参数,更多参数一致往后加即可。-->
<select id="selectUser" resultType="com.cy.entity.User">
select * from user
where username=#{0} and address = #{1}
</select>
User selectUser(String name,String address);
- 使用
@Param
注解。
<select id="selectUser2" resultType="com.cy.entity.User">
select * from user
where username=#{username} and address = #{address}
</select>
User selectUser2(@Param("username") String username, @Param("address") String address);
- 多个参数封装成
map
。
<select id="findRolesByMap" parameterType="map" resultType="role">
select id,role_name as roleName,note
from t_role
where role_name like concat('%',#{roleName},'%')
and note like concat('%',#{note},'%')
</select>
//测试
RoleMapper roleMapper=sqlSession.getMapper(RoleMapper.class);
Map<String,Object> paramenterMap=new HashMap<String,Object>();
parameterMap.put("roleName","1");
parameterMap.put("note","1");
List<Role> roles=roleMapper.findRolesByMap(parameterMap);
//DAO
List findRolesByMap(Map<String,Object> paramenterMap);
15. Mybatis 动态 sql 有什么用?执行原理?有哪些动态 sql?
Mybatis
动态sql
可以在Xml
映射文件内,以标签的形式编写动态sql
,执行原理
是根据表达式的值 完成逻辑判断并动态拼接sql
的功能。Mybatis
提供了 9 种动态sql
标签:trim
|where
|set
|foreach
|if
|choose
|when
|otherwise
|bind
。
16. Xml 映射文件中,除了常见的 select | insert | updae | delete 标签之外,还有哪些标签?
<resultMap>
、<parameterMap>
、<sql>
、<include>
、<selectKey>
,加上动态 sql
的 9 个标签,其中<sql>
为 sql
片段标签,通过<include>
标签引入 sql
片段,<selectKey>
为不支持自增的主键生成策略标签。
17. Mybatis 的 Xml 映射文件中,不同的 Xml 映射文件,id 是否可以重复?
- 不同的
Xml
映射文件,如果配置了namespace
,那么id
可以重复;如果没有配置namespace
,那么id
不能重复。 - 原因就是
namespace+id
是作为Map<String, MapperStatement>
的key
使用的,如果没有namespace
,就剩下id
,那么,id
重复会导致数据互相覆盖。有了namespace
,自然id
就可以重复namespace
不同,namespace+id
自然也就不同。
18. 为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?
Hibernate
属于全自动ORM
映射工具,使用Hibernate
查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。- 而
Mybatis
在查询关联对象或关联集合对象时,需要手动编写sql
来完成,所以,称之为半自动ORM
映射工具。
19. 一对一、一对多的关联查询 ?
<!--association 一对一关联查询 -->
<!-- 建立对应关系 -->
<resultMap type="account" id="accountMap">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
<!-- 它是用于指定从表方的引用实体属性的 -->
<association property="user" javaType="user">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<result column="address" property="address"/>
</association>
</resultMap>
<!-- 配置查询所有操作-->
<select id="findAll" resultType="accountuser">
select a.*,u.username,u.address from account a,user u where a.uid =u.id;
</select>
<!--collection 一对多关联查询 -->
<!-- 建立对应关系 -->
<resultMap type="user" id="userMap">
<id column="id" property="id"></id>
<result column="username" property="username"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<!-- collection 是用于建立一对多中集合属性的对应关系
ofType 用于指定集合元素的数据类型
-->
<collection property="accounts" ofType="account">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
</collection>
</resultMap>
<!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">
select u.*,a.id as aid ,a.uid,a.money from user u left outer join account
a on u.id =a.uid
</select>
20. MyBatis 实现一对一有几种方式?具体怎么操作的?
- 有联合查询和嵌套查询。
- 联合查询是几个表联合查询,只查询一次, 通过在
resultMap
里面配置 association 节点配置一对一的类就可以完成; - 嵌套查询是先查一个表,根据这个表里面的结果的外键
id
,去再另外一个表里面查询数据,也是通过association
配置,但另外一个表的查询通过select
属性配置。
21. MyBatis 实现一对多有几种方式,怎么操作的?
- 有联合查询和嵌套查询。
- 联合查询是几个表联合查询,只查询一次,通过在
resultMap
里面的collection
节点配置一对多的类就可以完成。 - 嵌套查询是先查一个表,根据这个表里面的结果的外键
id
,去再另外一个表里面查询数据,也是通过配置collection
,但另外一个表的查询通过select
节点配置。
22. Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么?
Mybatis
仅支持association
关联对象和collection
关联集合对象的延迟加载,association
指的就是一对一,collection
指的就是一对多查询。在Mybatis
配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false
。- 它的原理是,使用
CGLIB
创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName()
,拦截器invoke()
方法发现a.getB()
是null
值,那么就会单独发送事先保存好的查询关联B
对象的sql
,把B
查询出来,然后调用a.setB(b)
,于是a
的对象b
属性就有值了,接着完成a.getB().getName()
方法的调用。这就是延迟加载的基本原理。 - 当然了,不光是
Mybatis
,几乎所有的包括Hibernate
,支持延迟加载的原理都是一样的。
23. Mybatis 的一级、二级缓存
- 一级缓存: 基于
PerpetualCache
的HashMap
本地缓存,其存储作用域为Session
,当Session flush
或close
之后,该Session
中的所有Cache
就将清空,默认打开一级缓存。 - 二级缓存与一级缓存其机制相同,默认也是采用
PerpetualCache
,HashMap
存储,不同在于其存储作用域为Mapper(Namespace)
,并且可自定义存储源,如Ehcache
。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable
序列化接口(可用来保存对象的状态),可在它的映射文件中配置<cache/>
。 - 对于缓存数据更新机制,当某一个作用域(一级缓存
Session
/二级缓存Namespaces
)的进行了 C/U/D 操作后,默认该作用域下所有select
中的缓存将被clear
。
24. 什么是 MyBatis 的接口绑定?有哪些实现方式?
- 接口绑定,就是在
MyBatis
中任意定义接口,然后把接口里面的方法和SQL
语句绑定, 我们直接调用接口方法就可以,这样比起原来了SqlSession
提供的方法我们可以有更加灵活的选择和设置。 - 接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加上
@Select
、@Update
等注解,里面包含Sql
语句来绑定;另外一种就是通过xml
里面写SQL
来绑定, 在这种情况下,要指定xml
映射文件里面的namespace
必须为接口的全路径名。当Sql
语句比较简单时候,用注解绑定, 当SQL
语句比较复杂时候,用xml
绑定,一般用xml
绑定的比较多。
24. 使用 MyBatis 的 mapper 接口调用时有哪些要求?
Mapper
接口方法名和mapper.xml
中定义的每个sql
的id
相同。Mapper
接口方法的输入参数类型和mapper.xml
中定义的每个sql
的parameterType
的类型相同。Mapper
接口方法的输出参数类型和mapper.xml
中定义的每个sql
的resultType
的类型相同。Mapper.xml
文件中的namespace
即是mapper
接口的类路径。
25. Mapper 编写有哪几种方式?
-
接口实现类继承
SqlSessionDaoSupport
:使用此种方法需要编写mapper
接口,mapper
接口实现类、mapper.xml
文件。
a. 在sqlMapConfig.xml
中配置mapper.xml
的位置。<mappers> <mapper resource="mapper.xml 文件的地址" /> <mapper resource="mapper.xml 文件的地址" /> </mappers>
b. 定义
mapper
接口。
c. 实现类集成SqlSessionDaoSupport
。
d.mapper
方法中可以this.getSqlSession()
进行数据增删改查。
e.spring
配置。<bean id=" " class="mapper 接口的实现"> <property name="sqlSessionFactory" ref="sqlSessionFactory"></property> </bean>
-
使用
org.mybatis.spring.mapper.MapperFactoryBean
。
a. 在sqlMapConfig.xml
中配置mapper.xml
的位置,如果mapper.xml
和mapper
接口的名称相同且在同一个目录,这里可以不用配置。<mappers> <mapper resource="mapper.xml 文件的地址" /> <mapper resource="mapper.xml 文件的地址" /> </mappers>
b. 定义
mappe
r 接口,mapper.xml
中的namespace
为mapper
接口的地址,mapper
接口中的方法名和mapper.xml
中的定义的statement
的id
保持一致。
c. Spring 中定义。<bean id="" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="mapper 接口地址" /> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean>
-
使用
mapper
扫描器。
a.mapper.xml
文件编写mapper.xml 中的 namespace 为 mapper 接口的地址; mapper 接口中的方法名和 mapper.xml 中的定义的 statement 的 id 保持一致; 如果将 mapper.xml 和 mapper 接口的名称保持一致则不用在 sqlMapConfig.xml中进行配置。
b. 定义
mapper
接口:mapper.xml
的文件名和mapper
的接口名称保持一致,且放在同一个目录。
c. 配置mapper
扫描器:<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="mapper 接口包地址"></property> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean>
d. 使用扫描器后从
spring
容器中获取mapper
的实现对象。
27. 简述 Mybatis 的插件运行原理,以及如何编写一个插件。
Mybatis
仅可以编写针对ParameterHandler
、ResultSetHandler
、StatementHandler
、Executor
这 4 种接口的插件,Mybatis
使用JDK
的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler
的invoke()
方法,当然,只会拦截那些你指定需要拦截的方法。- 编写插件:实现
Mybatis
的Interceptor
接口并复写intercept()
方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。
二、Zookeeper部分
1. 什么是Zookeeper?
ZooKeeper
是一个开放源码的分布式协调服务,它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供给用户。- 分布式应用程序可以基于
Zookeeper
实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master
选举、分布式锁和分布式队列等功能。 Zookeeper
保证了如下分布式一致性特性:- ① 顺序一致性(有序性)
从同一个客户端发起的事务请求,最终将会严格地按照其发起顺序被应用到 Zookeeper 中去。 有序性是 Zookeeper 中非常重要的一个特性。 所有的更新都是全局有序的,每个更新都有一个唯一的时间戳,这个时间戳称为 zxid(Zookeeper Transaction Id)。 而读请求只会相对于更新有序,也就是读请求的返回结果中会带有这个 Zookeeper 最新的 zxid 。
- ② 原子性:所有事务请求的处理结果,在整个集群中所有机器上的应用情况是一致的,即整个集群要么都成功应用了某个事务,要么都没有应用。
- ③ 单一视图:无论客户端连接的是哪个
Zookeeper
服务器,其看到的服务端数据模型都是一致的。 - ④ 可靠性:一旦服务端成功地应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更将会一直被保留,除非有另一个事务对其进行了变更。
- ⑤ 实时性:
Zookeeper
保证在一定的时间段内,客户端最终一定能够从服务端上读取到最新的数据状态。
- ① 顺序一致性(有序性)
2. ZooKeeper 提供了什么?
- 文件系统
- 通知机制
3. Zookeeper 文件系统
Zookeeper
提供一个多层级的节点命名空间(节点称为znode
)。与文件系统不同的是,这些节点都可以设置关联的数据,而文件系统中只有文件节点可以存放数据而目录节点不行。Zookeeper
为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性使得Zookeeper
不能用于存放大量的数据,每个节点的存放数据上限为1M
。
4. ZAB 协议?
ZAB
协议是为分布式协调服务Zookeeper
专门设计的一种支持崩溃恢复的原子广播协议。ZAB
协议包括两种基本的模式:崩溃恢复和消息广播。- 当整个
zookeeper
集群刚刚启动或者 Leader 服务器宕机、重启或者网络故障导致不存在过半的服务器与Leader
服务器保持正常通信时,所有进程(服务器)进入崩溃恢复模式,首先选举产生新的Leader
服务器,然后集群中Follower
服务器开始与新的Leader
服务器进行数据同步,当集群中超过半数机器与该Leader
服务器完成数据同步之后,退出恢复模式进入消息广播模式,Leader
服务器开始接收客户端的事务请求生成事物提案来进行事务请求处理。
5. 四种类型的数据节点 Znode
PERSISTENT
-持久节点:
除非手动删除,否则节点一直存在于Zookeeper
上。EPHEMERAL
-临时节点:
临时节点的生命周期与客户端会话绑定,一旦客户端会话失效(客户端与zookeeper
连接断开不一定会话失效),那么这个客户端创建的所有临时节点都会被移除。PERSISTENT_SEQUENTIAL
-持久顺序节点:
基本特性同持久节点,只是增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。EPHEMERAL_SEQUENTIAL
-临时顺序节点:
基本特性同临时节点,增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。
6. Zookeeper Watcher 机制 – 数据变更通知
7. 客户端注册 Watcher 实现
8. 服务端处理 Watcher 实现
9. 客户端回调 Watcher
10. ACL 权限控制机制
11. Chroot 特性
12. 会话管理
13. 服务器角色
Leader
- 事务请求的唯一调度和处理者,保证集群事务处理的顺序性。
- 集群内部各服务的调度者。
Follower
- 处理客户端的非事务请求,转发事务请求给
Leader
服务器。 - 参与事务请求
Proposal
的投票。 - 参与
Leader
选举投票。
- 处理客户端的非事务请求,转发事务请求给
Observer
- 3.0 版本以后引入的一个服务器角色,在不影响集群事务处理能力的基础上提升集群的非事务处理能力。
- 处理客户端的非事务请求,转发事务请求给
Leader
服务器。 - 不参与任何形式的投票。
14. Zookeeper 下 Server 工作状态
服务器具有四种状态,分别是 LOOKING、FOLLOWING、LEADING、OBSERVING。
LOOKING
:寻找Leader
状态。当服务器处于该状态时,它会认为当前集群中没有Leader
,因此需要进入Leader
选举状态。FOLLOWING
:跟随者状态。表明当前服务器角色是Follower
。LEADING
:领导者状态。表明当前服务器角色是Leader
。OBSERVING
:观察者状态。表明当前服务器角色是Observer
。
三、Dubbo部分
四、Elasticsearch部分
五、Memcached部分
六、Redis部分
1. 什么是 Redis?
-
Redis
是完全开源免费的,遵守BSD
协议,是一个高性能的key-value
数据库。 -
Redis
与其他key - value
缓存产品有以下三个特点:Redis
支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。Redis
不仅仅支持简单的key-value
类型的数据,同时还提供list
,set
,zset
,hash
等数据结构的存储。Redis
支持数据的备份,即master-slave
模式的数据备份。
-
Redis
优势:- 性能极高 –
Redis
能读的速度是 110000 次/s,写的速度是 81000 次/s 。 - 丰富的数据类型 –
Redis
支持二进制案例的Strings
,Lists
,Hashes
,Sets
及Ordered Sets
数据类型操作。 - 原子 –
Redis
的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI
和EXEC
指令包起来。 - 丰富的特性 –
Redis
还支持publish/subscribe
, 通知,key
过期等等特性。
- 性能极高 –
-
Redis
与其他key-value
存储有什么不同?Redis
有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其
他数据库的进化路径。Redis
的数据类型都是基于基本数据结构的同时对程序员透
明,无需进行额外的抽象。Redis
运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时
需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点
是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis
可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。
2. Redis 的数据类型?
Redis
支持五种数据类型:String
(字符串),Hash
(哈希),List
(列表),
Set
(集合)及Zset
(sorted set
:有序集合)。- 我们实际项目中比较常用的是
String
,Hash
如果你是Redis
中高级用户,还需要加上下面几种数据结构HyperLogLog
、Geo
、Pub/Sub
。 - 如果你说还玩过
Redis Module
,像BloomFilter
,RedisSearch
,Redis-ML
,面试官得眼睛就开始发亮了。
3. 使用 Redis 有哪些好处?
- 速度快,因为数据存在内存中,类似于
HashMap
,HashMap
的优势就是查找和操作的时间复杂度都是O(1)
。 - 支持丰富数据类型,支持
String
,List
,Set
,Zset
,Hash
等 。 - 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行。
- 丰富的特性:可用于缓存,消息,按
key
设置过期时间,过期后将会自动删除。
4. Redis 相比 Memcache 有哪些优势?
Memcached
所有的值均是简单的字符串,redis
作为其替代者,支持更为丰富的数据类。Redis
的速度比Memcached
快。Redis
可以持久化其数据。
5. Memcache 与 Redis 的区别都有哪些?
- 存储方式
Memecache
把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。Redis
有部份存在硬盘上,这样能保证数据的持久性。 - 数据支持类型
Memcache
对数据类型支持相对简单。Redis
有复杂的数据类型。 - 使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。
Redis
直接自己构建了VM
机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
6. Redis 是单进程单线程的?
Redis
是单进程单线程的,redis
利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。
7. 一个字符串类型的值能存储最大容量是多少?
- 512M
8. Redis 的持久化机制是什么?各自的优缺点?
-
RDB
(Redis DataBase
)持久化方式: 是指用数据集快照的方式(半持久化模式)记录redis
数据库的所有键值对,在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。
优点:- 只有一个文件
dump.rdb
,方便持久化。 - 容灾性好,一个文件可以保存到安全的磁盘。
- 性能最大化,
fork
子进程来完成写操作,让主进程继续处理命令,所以是IO
最大化。使用单独子进程来进行持久化,主进程不会进行任何IO
操作,保证了redis
的高性能。 - 相对于数据集大时,比
AOF
的启动效率更高。
缺点:
- 数据安全性低。
RDB
是间隔一段时间进行持久化,如果持久化之间redis
发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候。
- 只有一个文件
-
AOF
(Append-only file
)持久化方式: 是指所有的命令行记录以 redis 命令请求协议的格式完全持久化存储保存为 aof 文件。
优点:- 数据安全,
aof
持久化可以配置appendfsync
属性,有always
,每进行一次命令操作就记录到aof
文件中一次。 - 通过
append
模式写文件,即使中途服务器宕机,可以通过redis-check-aof
工具解决数据一致性问题。 AOF
机制的rewrite
模式。AOF
文件没被rewrite
之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的flushall
)。
缺点:
AOF
文件比RDB
文件大,且恢复速度慢。- 数据集大的时候,比
rdb
启动效率低。
- 数据安全,
9. Redis 常见性能问题和解决方案
10. redis 过期键的删除策略?
11. Redis 的回收策略(淘汰策略)?
12. 为什么 Redis 需要把所有数据放到内存中?
Redis
为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以redis
具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O
速度为严重影响redis
的性能。在内存越来越便宜的今天,redis
将会越来越受欢迎。如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。
13. Redis 的同步机制了解么?
Redis
可以使用主从同步,从从同步。第一次同步时,主节点做一次bgsave
,并同时将后续修改操作记录到内存buffer
,待完成后将rdb
文件全量同步到复制节点,复制节点接受完成后将rdb
镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。
14. Pipeline 有什么好处,为什么要用 pipeline?
15. 是否使用过 Redis 集群,集群的原理是什么?
Redis Sentinal
着眼于高可用,在master
宕机时会自动将slave
提升为master
,继续提供服务。Redis Cluster
着眼于扩展性,在单个redis
内存不足时,使用Cluster
进行分片存储。
16. Redis 集群方案什么情况下会导致整个集群不可用?
- 有
A
,B
,C
三个节点的集群,在没有复制模型的情况下,如果节点B
失败了,那么整个集群就会以为缺少 5501-11000 这个范围的槽而不可用。
17. Redis 支持的 Java 客户端都有哪些?官方推荐用哪个?
Redisson
、Jedis
、lettuce
等等,官方推荐使用Redisson
。
18. Jedis 与 Redisson 对比有什么优缺点?
Jedis
是Redis
的Java
实现的客户端,其API
提供了比较全面的Redis
命令的支持。Redisson
实现了分布式和可扩展的Java
数据结构,和Jedis
相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等Redis
特性。Redisson
的宗旨是促进使用者对Redis
的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。
19. Redis 如何设置密码及验证密码?
- 设置密码:
config set requirepass 123456
。 - 授权密码:
auth 123456
。
20. 说说 Redis 哈希槽的概念?
Redis
集群没有使用一致性hash
,而是引入了哈希槽的概念,Redis
集群有16384 个哈希槽,每个key
通过CRC16
校验后对16384
取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。
21. Redis 集群的主从复制模型是怎样的?
- 为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有 N-1 个复制品。
22. Redis 集群会有写操作丢失吗?为什么?
Redis
并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操作。
23. Redis 集群之间是如何复制的?
- 异步复制
七、MySQL部分
1. MySQL 中有哪几种锁?
- 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最
高,并发度最低。 - 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最
低,并发度也最高。 - 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表
锁和行锁之间,并发度一般。
2. MySQL 中有哪些不同的表格?
共有 5 种类型的表格:
MyISAM
Heap
Merge
INNODB
ISAM
3. 简述在 MySQL 数据库中 MyISAM 和 InnoDB 的区别
MyISAM
:
- 不支持事务,但是每次查询都是原子的;
- 支持表级锁,即每次操作是对整个表加锁;
- 存储表的总行数;
- 一个
MYISAM
表有三个文件:索引文件、表结构文件、数据文件; - 采用非聚集索引,索引文件的数据域存储指向数据文件的指针。辅索引与主索引基本一致,但是辅索引不用保证唯一性。
InnoDb
: - 支持
ACID
的事务,支持事务的四种隔离级别; - 支持行级锁及外键约束:因此可以支持写并发;
- 不存储总行数;
- 一个
InnoDb
引擎存储在一个文件空间(共享表空间,表大小不受操作系统控制,一个表可能分布在多个文件里),也有可能为多个(设置为独立表空,表大小受操作系统文件大小限制,一般为 2G),受操作系统文件大小的限制; - 主键索引采用聚集索引(索引的数据域存储数据文件本身),辅索引的数据域存储主键的值;因此从辅索引查找数据,需要先通过辅索引找到主键值,再访问辅索引;最好使用自增主键,防止插入数据时,为维持
B+
树结构,文件的大调整。
4. MySQL 中 InnoDB 支持的四种事务隔离级别名称,以及逐级之间的区别?
SQL 标准定义的四个隔离级别为:
read uncommited
:读到未提交数据。read committed
:脏读,不可重复读。repeatable read
:可重读。serializable
:串行化。
5. CHAR 和 VARCHAR 的区别?
CHAR
和VARCHAR
类型在存储和检索方面有所不同CHAR
列长度固定为创建表时声明的长度,长度值范围是 1 到 255 当CHAR
值被存储时,它们被用空格填充到特定长度,检索CHAR
值时需删除尾随空格。
6. myisamchk 是用来做什么的?
- 它用来压缩
MyISAM
表,这减少了磁盘或内存使用。 MyISAM Static
和MyISAM Dynamic
有什么区别?- 在
MyISAM Static
上的所有字段有固定宽度。动态MyISAM
表将具有像TEXT
,BLOB
等字段,以适应不同长度的数据类型。 MyISAM Static
在受损情况下更容易恢复。
- 在
7. 主键和候选键有什么区别?
- 表格的每一行都由主键唯一标识,一个表只有一个主键。
- 主键也是候选键。按照惯例,候选键可以被指定为主键,并且可以用于任何外键
引用。
8. 如果一个表有一列定义为 TIMESTAMP,将发生什么?
- 每当行被更改时,时间戳字段将获取当前时间戳。
- 列设置为
AUTO INCREMENT
时,如果在表中达到最大值,会发生什么情况?- 它会停止递增,任何进一步的插入都将产生错误,因为密钥已被使用。
- 怎样才能找出最后一次插入时分配了哪个自动增量?
LAST_INSERT_ID
将返回由Auto_increment
分配的最后一个值,并且不需要指定表名称。
9. 你怎么看到为表格定义的所有索引?
- 索引是通过以下方式为表格定义的:
SHOW INDEX FROM <tablename>;
10. LIKE 声明中的%和_是什么意思?
%
对应于 0 个或更多字符,_
只是LIKE
语句中的一个字符。- 如何在
Unix
和MySQL
时间戳之间进行转换?UNIX_TIMESTAMP
是从MySQL
时间戳转换为Unix
时间戳的命令。FROM_UNIXTIME
是从Unix
时间戳转换为MySQL
时间戳的命令。
11. 列对比运算符是什么?
- 在 SELECT 语句的列比较中使用=,<>,<=,<,> =,>,<<,>>,<=>,AND,OR 或 LIKE 运算符。
12. BLOB 和 TEXT 有什么区别?
BLOB
是一个二进制对象,可以容纳可变数量的数据。TEXT
是一个不区分大小写的BLOB
。BLOB
和TEXT
类型之间的唯一区别在于对BLOB
值进行排序和比较时区分大小写,对TEXT
值不区分大小写。