目录
- 数据库
- 缓存穿透是什么
- 常见的sql调优方法有哪些
- 使用表的别名为什么能优化查询性能
- MySQL事务特性是哪些
- 事务隔离级别有哪些
- Java基础
- StringBuffer和StringBuilder的区别
- String直接引号新建和new String新建的区别
- Java中继承和实现的各种关系
- 消息队列
- Redis
- 计算机常识
- 缓冲击穿是什么
- 布隆过滤器是什么
- 进程间通信的方式有几种
数据库
缓存穿透是什么
缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。解决缓存穿透的方法包括使用布隆过滤器,将可能访问的 key 存储在布隆过滤器中,不存在的 key 则直接被过滤掉,以及设置热点数据永远不过期等。
常见的sql调优方法有哪些
SQL调优的技巧和策略可以优化数据库查询性能,提高查询速度和效率。以下是一些常见的SQL调优技巧:
- 使用索引:使用索引可以大大提高查询速度,可以通过为表创建索引来优化查询性能。
- 避免使用having字句:having字句会在检索出所有记录之后才对结果集进行过滤,而使用WHERE字句可以在聚合前筛选记录,减少开销。
- 使用表的别名:当在SQL语句中连接多个表时,使用表的别名并把别名前缀于每个列名上,可以优化查询性能。
- 调整where子句中的连接顺序:DBMS一般采用自下而上的顺序解析where子句,根据这个原理,表连接最好写在其他where条件之前,可以过滤掉最大数量记录。
- 将多条SQL语句压缩到一句SQL中:每次执行SQL的时候都要建立网络连接、进行权限校验、进行SQL语句的查询优化、发送执行结果,这个过程是非常耗时的,因此应该尽量避免过多的执行SQL语句,能够压缩到一句SQL执行的语句就不要用多条来执行。
- 使用增量查询:使用SELECT name, age FROM user WHERE id > #{lastId} LIMIT 100;查询比上次id大的100条记录。
- 高效分页:可以使用SELECT id, name, age FROM user LIMIT 10000, 20;查询10020条记录,然后丢弃前面10000条记录,或者使用SELECT id, name, age FROM user WHERE id > 10000 LIMIT 20;找到上次分页最大id。
使用表的别名为什么能优化查询性能
- 表别名能够简化SQL语句,提高可读性。
- 表别名能够缓解查询优化器在执行查询时所需的开销。在复杂的查询中,如果没有使用别名,优化器可能需要执行更多的工作来确定如何最有效地执行查询。通过使用别名,可以为优化器提供更多的信息,帮助它更有效地生成查询执行计划。
- 表别名可以提高查询性能。在某些数据库系统(如MySQL)中,使用别名可以将表连接顺序提前确定,从而减少服务器需要解析查询表中字段及其相关值所需的时间,提高查询速度。
MySQL事务特性是哪些
MySQL事务具有以下四个特性:
- 原子性(Atomicity):事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
- 一致性(Consistency):事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
- 隔离性(Isolation):当多个用户并发访问数据库时,比如同时操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。关于事务的隔离性数据库提供了多种隔离级别,详见《MySQL事务隔离级别和实现原理》。
- 持久性(Durability):一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
这些特性确保了数据库的数据一致性和完整性,以及事务的可重复性和可靠性。
事务隔离级别有哪些
事务隔离级别有四种:
- Serializable (串行化):这是最严格的隔离级别,事务串行执行,资源消耗最大。
- Repeatable Read (重复读):保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。
- Read Committed (提交读):大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。
- Read Uncommitted (未提交读):事务中的修改,即使没有提交,其他事务也可以看得到,会导致“脏读”、“幻读”和“不可重复读取”。
这四种隔离级别是逐渐降低的,更高的隔离级别可以提供更多的数据一致性保证,但同时也会牺牲更多的性能。选择哪个隔离级别通常需要根据具体的应用需求和性能要求来决定。
Java基础
StringBuffer和StringBuilder的区别
StringBuffer和StringBuilder都是Java中用来处理字符串的类,它们的主要区别在于是否线程安全。StringBuffer是线程安全的,而StringBuilder不是。这意味着在多线程环境中,使用StringBuffer更加安全,因为它可以防止数据被并发修改。另一方面,由于StringBuilder不是线程安全的,所以它的性能通常会比StringBuffer更好。以下是StringBuffer和StringBuilder之间其他一些重要的区别:
- 缓冲区大小:StringBuffer的缓冲区大小是固定的,而StringBuilder的缓冲区大小则是动态的。
- 效率:对于大量的字符串操作,StringBuilder比StringBuffer更有效率,因为StringBuffer的所有方法都是同步的,这会在多线程环境下增加额外的开销。
- 适用场景:如果程序是多线程的,或者你需要频繁地修改字符串,那么使用StringBuffer更好。如果你只是进行单线程的字符串操作,或者需要频繁地创建和修改字符串,那么使用StringBuilder会更高效。
String直接引号新建和new String新建的区别
使用双引号定义字符串和使用new关键字创建字符串对象有一些区别,主要表现在内存分配和字符串池的使用上。
- 内存分配:当你使用双引号定义字符串时,如 String s = “abc”,Java会在字符串缓冲池中查找是否有一个存储着相同内容的字符串的对象,如果存在,那么Java就会返回该对象,如果不存在,就会在堆内存中创建一个新的字符串对象,并将该对象放入字符串缓冲池中。而当你使用new关键字创建字符串对象时,如 String s = new String(“abc”),Java会在堆内存中创建一个新的字符串对象,不论字符串缓冲池中是否存在相同内容的字符串对象。
- 字符串池的使用:使用双引号定义字符串时,Java会先在字符串池中查找是否存在相同的内容,如果存在就直接返回地址,如果不存在则在堆中创建一个新的对象,然后在字符串池中添加这个新的对象。使用new关键字创建字符串时,每次都会在堆内存中创建一个新的对象。
总的来说,使用双引号创建字符串更有效率,因为它能共享相同内容的对象。而使用new关键字创建的每个字符串对象都会占用独立的内存空间。因此,建议在实际编程中尽可能使用双引号来定义字符串。
Java中继承和实现的各种关系
在 Java 中,一个类只能继承一个类,这被称为单继承。但是,Java支持多重继承,即一个类可以实现多个接口,一个类可以实现任意数量的接口。
接口可以继承接口,抽象类可以实现接口,但不可以继承接口。接口可以继承多个接口public interface C extends A, B {}
。抽象类可以实现(implements)一个或多个接口public abstract class MyClass implements A, B {}
。抽象类不能继承一个具体的类,但可以继承一个抽象类或实现一个接口public abstract class MyClass extends AbstractClass implements A {}
。
抽象类中可以对方法进行实现。从Java 8开始,接口也可以定义默认方法和静态方法。抽象类可以实现方法,但这些方法只能被抽象类本身和其非抽象子类使用。
// 定义一个接口,其中包含默认方法和静态方法
public interface MyInterface { // 默认方法 default String defaultMethod() { return "This is a default method in the interface."; } // 静态方法 static String staticMethod() { return "This is a static method in the interface."; }
} // 实现接口的类
public class MyClass implements MyInterface { public static void main(String[] args) { // 调用接口的默认方法 System.out.println(MyInterface.defaultMethod()); // 调用接口的静态方法 System.out.println(MyInterface.staticMethod()); }
}// 定义一个抽象类,其中包含一个抽象方法和一个具体方法
public abstract class MyAbstractClass { // 抽象方法 public abstract void abstractMethod(); // 具体方法 public void concreteMethod() { System.out.println("This is a concrete method in the abstract class."); }
} // 实现抽象类的类
public class MyClass extends MyAbstractClass { // 实现抽象方法 @Override public void abstractMethod() { System.out.println("This is the implementation of the abstract method in the subclass."); }
}
消息队列
Redis
计算机常识
缓冲击穿是什么
缓冲击穿是电容器的故障现象之一,指的是电容器在运行过程中,由于长时间超过额定电压,导致电容器内部绝缘材料性能下降,电容器内部出现击穿短路的现象。为了避免这种情况发生,电容器通常会采用串联电抗器或放电电阻等保护装置,以限制电流和电压的幅值,避免电容器因过电压而损坏。
布隆过滤器是什么
布隆过滤器(Bloom Filter)是一种很长的二进制向量和一系列随机映射函数。它用于检索一个元素是否在一个集合中。布隆过滤器的主要优点是空间效率和查询时间都比一般的算法要好的多。它的主要缺点是有一定的误识别率和删除困难。
进程间通信的方式有几种
进程间通信的八种方式:
- 管道(pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。它分为无管道单工通信方式和有管道单工通信方式两种。此外,无名管道(pipe)也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
- 高级管道(pipe):高级管道是一种半双工的通信方式,数据只能单向流动,但是它可以在不同进程间传递。它分为发送端和接收端两个部分,通过将发送端和接收端连接起来实现通信。
- 信号(signal):信号是一种比较复杂的通信方式,它允许一个进程向另一个进程发送一个信号,通知该进程某个事件已经发生。接收到信号的进程可以根据信号的类型进行处理。
- 信号量(semaphore):信号量是一个计数器,可以用来控制多个线程对共享资源的访问,因此主要用于进程间或线程的同步。
- 消息队列(message queue):消息队列是一种消息的链表,存放在内核中并由消息队列标识符标识。它克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点,可以进行大量数据的传输。
- 套接字(socket):套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
- 共享内存(shared memory):共享内存是一种高效的进程间通信方式。多个进程可以通过共享内存来读写同一块物理内存空间,从而实现高效的通信。共享内存必须在具有亲缘关系的进程间使用。
- 消息信箱(message box):消息信箱是一种可以进行跨进程通信的数据结构。一个进程可以发送消息到消息信箱,而另一个进程可以从该消息信箱中接收消息。