JAVA知识点整理

JAVA面向对象特性

  • 继承:子类继承父类(遗产的继承)
  • 封装:将对象封装成一个高度自治和相对封闭的个体
  • 抽象:把现实生活中的对象抽象为类
  • 多态:通过父类的引用指向子类或者具体实现类的实例对象(在运行的时候决定)

事务的四大特性

  • 原子性:事务不可分割,要么都成功要么都失败
  • 一致性:要么都成功,要么都失败,后面失败了,需要对前面的操作进行回滚
  • 持久性:修改数据后,在数据库中生效是永久的:
  • 隔离性:一个事务开始后,不能被其他事务干扰,举例:对于A对B进行转账,A没把这个交易完成的时候,B是不知道A要给他转钱。

数据库隔离级别

  • 读未提交:
    事务中发生了修改,即使没有提交,其它事务也是可见的
    举例:一个数A原来50修改为100,但是我还没有提交修改,另一个事务看到这个修改,而这个时候原事务发生了回滚,这时候A还是50,但是另一个事务看到的A是100

  • 读已提交:
    对于一个事务从开始直到提交之前,所做的任何修改是其它事务不可见的
    举例:对于一个数A原来是50,然后提交修改成100,这个时候另一个事务在A提交修改之前,读取到了A是50,刚读取完,A就被修改成100了,这个时候另一个事务再进行读取发现A就突然变成100了

  • 可重复读:
    对于一个记录读取多次的记录是相同的,
    举例:就是对于一个数A读取的话一直是A,前后两次读取到的A是一致的

  • 串行化:
    在并发情况下,和串行化的读取的结果是一致的,没有什么不同
    举例:不会发生脏读和幻读

  • Mysql 默认:可重复读

  • Oracle 默认:读已提交

事务的传播特性

  • 保证同一个事务中
    propagion_required: 支持当前事务,如果不存在 就新建一个(默认)
    propagion_supports: 支持当前事务,如果不存在,就不使用事务
    propagion_mandatory: 支持当前事务,如果不存在,抛出异常

  • 保证没有在同一个事务中
    propagion_requires_new: 如果有事务存在,挂起当前事务,创建一个新的事务
    propagion_not_supported: 以非事务方式运行,如果有事务存在,挂起当前事务
    propagion_never: 以非事务方式运行,如果有事务存在,抛出异常
    propagion_nested: 如果当前事务存在,则嵌套事务执行

计算机网络分了哪七层

  • 物理层
  • 数据链路层
  • 网络层
  • 传输层 (tcp,udp)
  • 会话层
  • 表示层
  • 应用层(http)

数据库索引

  • 常规索引(INDEX)
  • 唯一索引(UNIQUE)
  • 主键索引(PRIMAY KEY)
  • 全文索引(FULLTEXT)

数据库引擎

  • Innodb引擎,Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。它的设计的目标就是处理大数据容量的数据库系统。
  • MyIASM引擎(原本Mysql的默认引擎),不提供事务的支持,也不支持行级锁和外键。
  • MEMORY引擎:所有的数据都在内存中,数据的处理速度快,但是安全性不高。

JAVA中的集合

Collection 是所有集合类的接口,List和Set都是继承自Collection接口,Collection 继承自Iterable接口(迭代器)

  1. List:有序(存储顺序和取出顺序一致),可重复
    • ArrayList
      • 底层数据结构是数组。
        线程不安全ArrayList的默认初始化容量是10,每次扩容时候增加原先容量的一半,也就是变为原来的1.5倍
    • LinkedList
      • 底层数据结构是链表。线程不安全
        底层实现是双向链表[双向链表方便实现往前遍历]
    • Vector
      • 底层数据结构是数组。线程安全,现在已少用,被ArrayList替代,原因有两个:
        Vector所有方法都是同步,有性能损失。
        Vector初始length是10 超过length时 以100%比率增长,相比于ArrayList更多消耗内存
  2. Set:无序,元素不可重复
    • HashSet集合
      • 底层数据结构是哈希表(是一个元素为链表的数组)
    • TreeSet集合
      • 底层数据结构是红黑树(是一个自平衡的二叉树)
      • 保证元素的排序方式
    • LinkedHashSet集合
      • 底层数据结构由哈希表和链表组成。
  3. Map:存储key-value形式的数据
    • hashMap
      • 数组+链表(散列表)+红黑树
    • LinkedHashMap
      • 遍历的是内部维护的双向链表,所以说初始容量对LinkedHashMap遍历是不受影响的
    • TreeMap
      • 实现了NavigableMap接口,而NavigableMap接口继承着SortedMap接口,致使我们的TreeMap是有序的
    • LinkedHashSet


      集合关系图

LinkList 和 ArrayList的区别

  • ArrayList:底层是数组

    • 查询特定元素比较快,而插入,删除和修改比较慢(在内存中是连续的,每次做插入或删除都需要 移动内存
  • LinkList:底层是链表

    • 不要求内存是连续的,在当前元素存放下一个或上一个元素的地址,查询时头部开始,一个个找,所以查询效率低,插入时不需要移动内存,只需要改变引用地址,所以插入和删除的效率比较高

HashMap和HashTable

  • HashMap:
    • 线程不安全的,效率较高,(多线程环境下,使用Hashmap进行put操作会引起死循环)
    • 允许null作为key
    • 是对map接口的实现
    • 初始容量为16,增长因子为0.75,扩容为2倍
    • hashMap计算hash对key的hashcode进行了二次hash,以获得更好的散列值,然后对table数组长度取模。
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);

static int hash(int h) {
        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
 
 static int indexFor(int h, int length) {
        return h & (length-1);
  • HashTable:
    • 线程安全,效率较低
    • 不允许null作为key
    • 实现的是map接口和Dictonary抽象类
    • 初始容量为11,增长因子为0.75,扩容时为容量翻倍+1
    • Hashtable计算hash是直接使用key的hashcode对table数组的长度直接进行取模
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;

想线程安全又想效率高,使用ConcurrentHashMap类,把一个大的map分为N个Segment(类似HashTable),每一段数据分别加锁,可以提供相同的线程安全,但效率提升n倍,默认为16倍

HashMap

  • HashMap实现了Map接口,是链表和数组的数据结构,在进行put操作时通过内部定义算法(hash算法) 寻址找到数组的下标,放入到此数组元素中,若通过算法得到的该数组已经有了元素(Hash碰撞),将会把这个元素上的链表进行遍历,将新的数组插入到链表末尾(jdk1.8 之前是插入到链表头部)。
  • 在jdk1.6中,HashMap中有个内置Entry类,它实现了Map.Entry接口;而在jdk1.8中,这个Entry类不见了,变成了Node类,也实现了Map.Entry接口)
  • hashmap的增长因子默认为0.75,默认大小为16,最大为2的30次方,在16 * 0.75 (数组长度*增长因子)时会进行 扩容,新数组长度 为原始数组长度两倍大小
    为了减少在hash碰撞冲突过多下,链表的get效率过低的情况,jdk1.8中新引入了红黑树数据结构,当链表元素长度 >8时会重组链表结构,形成红黑树结构,当链表元素=6时退回链表(泊松分布)

装箱和拆箱,为什么要使用拆装箱

Java是一个面向对象的语言,而基本类型,不具备面向对象的特性,没有封装一写好用的方法(如最大值、最小值、缓存值等)

  • 装箱:把基本数据类型转换为对应包装类型,在编译时调用Integer.valueOf() 方法装箱
  • 拆箱:把包装类型转换为基本数据类型,在编译时调用intValue() 方法拆箱

多线程实现方式

  1. 继承Thread类,重写run方法
  2. 实现runable接口,重写run方法

启动方式
Thread thread = new Thread(继承了 Thread的对象/实现了runnable的对象)
thread.setName("设置线程名称")
thread.start();

线程池作用

JAVA通过Executors提供四个静态方法创建四种线程池

  1. 限定线程个数,不会导致由于线程过多导致系统运行缓慢或崩溃
  2. 线程池不需要每次都去创建或销毁,节约了资源
  3. 线程池不需要每次都去创建,响应时间更快

Jsp四大作用域

  • request:用户端请求,此请求包含来自GET/POST的请求
  • response:网页回传用户端的回应
  • pageContext:网页属性在这里管理
  • session:与请求有关的会话期

SpringMVC

  1. 用户发送请求 被前端控制器DispatcherServlet捕获请求, 解析url
  2. 解析url找到 handler对象
  3. 根据获得的Handler,选择合适的HandlerAdapter,填充Handler入参(执行handler)
  4. 选择ViewResovler,通过ViewResovler渲染视图并返回

String,StringBuffer,StringBuilder

String:是不可变的字符串,因为底层使用了不可变的字符数组(用final修饰)
StringBuffer和StringBuilder:是内容可变的字符串,底层是内容可变的字符数组
StringBuffer:是线程安全的,但是效率较低
StringBuilder:是线程不安全的,但是效率高

对JDBC的理解

java只定义接口,让厂商自己实现接口,我们只需要导入对应厂商开发的实现即可,然后以接口方式调用(普通开发者只要 下载驱动,然后 导入即可使用)

"#{}"与"${}"的区别

  1. "#{}" 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符,一个 #{ } 被解析为一个参数占位符;而${}仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换。

  2. "#{}" 解析之后会将String类型的数据自动加上引号,其他数据类型不会;而${} 解析之后是什么就是什么,他不会当做字符串处理。

  3. "#{}" 很大程度上可以防止SQL注入(SQL注入是发生在编译的过程中,因为恶意注入了某些特殊字符,最后被编译成了恶意的执行操作);而${} 主要用于SQL拼接的时候,有很大的SQL注入隐患。

  4. 在某些特殊场合下只能用{},不能用#{}。例如:在使用排序时ORDER BY{id},如果使用#{id},则会被解析成ORDER BY “id”,这显然是一种错误的写法。

触发器

需要有触发条件,当条件满足以后做什么操作
关键字是trigger

  1. 创建语法
    create trigger trigger_name after/before insert/update on 表名 for each row begin sql语句 end;
  2. 删除
    drop trigger trigger_name
  3. 查询
    show triggers;
    show trigger like “%abc%”

数据库分表技术

  1. 垂直分表
    • 把不常用的大字段分离出去,通过外键关联
  2. 水平分表
    • 按时间分表
    • 按区间范围进行分表
  3. hash分表
    • 通过一个原始目标的ID或者名称通过一定的hash算法计算出数据库存储表的表名,然后访问相应的表

依赖注入和控制反转

IOC和DI其实是同一个概念的不同角度的描述(依赖注入是从程序的层面来描述的,控制反转是从容器的角度描述的)

  • 作用:如A类需要调用B类但是B类需要获取外部资源C类,如果没有控制反转那么我们就需要在A类中同时创建B类和C类,当有了IOC/DI容器后就不需要在A类中创建C类了,而是被动等待,等待容器获取C类的实例,然后反向注入到A类中
  • 控制反转:由spring来负责对象的生命周期和对象间的关系(相当于通过中介买房子,所有的房子都登记在中介处,而你问Spring这个中介你需要哪个房子,在你需要买房的时候,可以直接找中介,中介会给你推荐房子,而不是由自己直接去找房)
  • 依赖注入:组件之间的依赖关系由容器在运行时决定,动态的向某个对象提供它所需要的其他对象

JAVA内存区域

  • 堆(线程公有)
    所有对象实例及数组都要在堆上分配内存
    分为新生代(1/3堆空间)、老年代(2/3 堆空间)、元空间(jdk1.8以前的永久代,是方法区的实现,之前放在java虚拟机中jdk1.8以后用的是本地内存)
    • 新生代:分为两部分伊甸区和幸存者区,所有的类都是在伊甸区被new出来的,幸存区有两个0区和1区当伊甸区空间满了垃圾回收器会对伊甸区进行Minor GC,将伊甸区中不再被其他对象所引用的对象进行销毁,然后将伊甸园区的剩余对象移到幸存0区,若幸存0区也满了,会再对该去进行Minor GC,然后移到1区
    • 老年代:新生代进行多次Minor GC仍然存活的对象会移动到老年区,若老年区也满了,会产生FullGC,进行老年区的内存清理。若老年区执行了Full GC之后依然无法进行对象保存,就会产生内存溢出异常
      新生代中的eden->from->to 每熬过一次Minor GC,年龄会加1,当它的年龄增加到一定程度(默认为15岁),就会晋升为老年代
      -Xmx和-Xms参数表示最大堆和最小堆
  • 方法区(线程公有)
    用于存储已被虚拟机加载的类信息、常量、静态变量,如static修饰的变量加载类的时候就被加载到方法区中
  • 程序计数器(线程私有)
    程序计数器是一块很小的内存空间,它是线程私有的,可以认作为当前线程的行号指示器。(用来存储指向下一条指令的地址,也即是即将要执行的指令代码)
  • 虚拟机栈(线程私有)
    栈的算法是先进后出的
    每个方法被执行的时候都会创建一个栈帧用于存储局部变量表,操作栈,动态链接,方法出口等信息。每一个方法被调用的过程就对应一个栈帧在虚拟机栈中从入栈到出栈的过程。
  • 本地方法栈(线程私有)
    本地方法栈是与虚拟机栈发挥的作用十分相似,区别是虚拟机栈执行的是Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的native方法服务,可能底层调用的c或者c++,我们打开jdk安装目录可以看到也有很多用c编写的文件,可能就是native方法所调用的c代码。

类加载机制

  • 全盘负责委托机制
    当一个ClassLoader加载一个类时,除非显示的使用另一个ClassLoader,该类所依赖和引用的类也由这个ClassLoader载入
  • 双亲委派机制
    指先委托父类加载器寻找目标类,在找不到的情况下在自己的路径中查找并载入目标类
    优势:
    • 沙箱安全机制:自己写的String.class类不会被加载,这样可以防止核心API库被随意篡改
    • 避免类的被重复加载:当父亲已经加载了该类时,子加载器就没必要再加载一次
JVM调优工具
  • jps:查看jvm进程
  • jstat:
    • jstat -gc 28485 垃圾回收统计
    • jstat -class 28485
  • jinfo:查看内存信息
    • jinfo -flags 28485 (jvm运行时的参数)
  • jmap:实例个数即占用内存大小
    • jmap -histo 28485 查看运行时内存相关信息
    • jmap -heap 28485 查看堆的概况
  • jstack:死锁排查
  • jvisualvm JDK自带的可视化工具

垃圾回收算法

  1. 引用计数法
    给对象中添加一个引用计数器,没当有一个地方引用它,计数器就加1;当引用失效,计数器就减1;任何时候计数器为0的对象就认为可以被回收。(这个方法实现简单,效率高,但是目前主流虚拟机没有选择这个算法管理内存,主要原因是很难解决对象之间相互循环引用的问题。)
  2. 可达性分析算法
    以“GC Roots”的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连的话,则证明此对象时不可能用的
  3. finalize()方法最终判定对象是否存活
    即使在可达性分析算法中不可达的对象,需要经历再次标记过程才真正宣告一个对象死亡

垃圾收集算法

  1. 标记清除算法
    • 效率问题(会遍历内存)
    • 空间问题(标记清除后会产生大量不连续的碎片)
  2. 复制算法
  3. 标记整理算法
  4. 分代收集算法
    • 新生代适合复制算法
    • 老年代适合标记清除算法和标记整理算法

JVM调优指标

  • 停顿时间:垃圾收集器做垃圾回收中断应用执行的时间
  • 吞吐量: 垃圾收集的时间和总时间的占比:1/(1+n),吞吐量为1-1/(1+n)

调优步骤

  • 打印GC日志
  • 分析日志得到关键性指标
  • 分析GC原因,调优JVM参数

REDIS数据结构

  • String(字符串)
  • Hash(哈希)
  • List(列表)
  • set(集合)
  • zset(有序集合)

REDIS单线程为什么这么快

所有数据都在内存中,所有的运算都是内存级别的运算,而且单线程避免了多线程的切换性能损耗问题

REDIS单线程如何处理这么多的并发客户端连接

Redis的IO多路复用,redis利用epoll来实现IO多路复用,将连接信息和事件放在队列中,依次放到文件事件分派器,事件分派器将事件分发给事件处理器

REDIS持久化

  • RDB(快照)

在默认情况下,Redis将数据库快照保存在名字为dump.rdb的二进制文件中。可以对Redis进行设置,让它在N秒内数据至少有M个改动这一条件满足时快照备份,一下设置会让Redis在满足“60秒内有至少有1000个键被改动”这一条件时进行快照备份 #save 60 1000

  • AOF

记录的是操作命令,每次有新命令追加到AOF文件时就执行一次fsync,就执行当Redis重启时,程序会重新执行AOF文件中的命令,可以通过修改配置文件来打开AOF功能 #appendonly yes

  • Redis4.0混合持久化

本质也是一种AOF方式所以必须打开AOF配置,整合了RDB和AOF格式,对AOF文件进行重写
开启混合持久化方式:#aof-use-rdb-preamble yes
AOF手动重写命令:#bgrewriteafo
AOF重写配置:#auto-aof-rewrite-percentage 100 #auto-of-rewrite-min-size 64mb

REDIS缓存淘汰策略

当Redis内存超出物理内存限制时,内存的数据会开始和磁盘产生频繁的交换。交换会让Redis的性能急剧下降,为了限制最大使用内存,Redis提供了配置参数maxmemory来限制内存超出期望大小

  • noeviction:不会继续服务写请求,读请求可以继续进行,这样可以保证不会丢失数据,但会让线上的内存不能持续进行,这是默认的淘汰策略
  • volatile lru 尝试淘汰设置了过期时间的key,最少使用的key优先被淘汰。没有设置过期时间的key不会被淘汰(一般情况下会使用LRU策略)
  • 其他见redis.conf中的配置
ResponseBodyAdvice接口

ResponseBodyAdvice接口是在Controller执行return之后,在response返回给浏览器或者APP客户端之前,执行的对response的一些处理。可以实现对response数据的一些统一封装或者加密等操作。

@ControllerAdvice注解

@ControllerAdvice,是Spring3.2提供的新注解,它是一个Controller增强器,可对controller中被 @RequestMapping注解的方法加一些逻辑处理。最常用的就是异常处理

spring mvc 运行流程
如何保证mq消息不丢失

1 .生产者网络抖动,通讯异常:rockemq自带事务机制,使用事务机制传输消息
2 .rocket mq消息持久化到磁盘失败,或者磁盘损害:接收到 发送者的消息,采用同步落盘
3 .消费者宕机:mq在消费者中注册了一个监听器,消费成功会返回一个CONSUME_SUCCESS,生产者就会知道消息已经消费完了,如果没成功会重发,重试次数是16次,如果超过次数会进入死信,3天后会自动删除

分布式锁的三种实现方式:

1.基于数据库(创建一个表,基于唯一索引)
2.基于redis
3.redisson
4.ZooKeeper

分布式锁优化

类似currentHashMap的做法分段加锁如:在数据库里建20个库存字段,redis建20个key

CAS原理:

CAS全称Compare and Swap,比较和交换的意思,乐观锁就是CAS实现的(内部使用的是CAS无锁算法)
java并发包中许多Atomic的类的底层原理都是CAS

CAS的缺点:

1 . CPU开销过大 : 在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很到的压力。
2 . 不能保证代码块的原子性:CAS机制所保证的知识一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用synchronized了。
3 .ABA问题:如果内存地址V初次读取的值是A,在CAS等待期间它的值曾经被改成了B,后来又被改回为A,那CAS操作就会误认为它从来没有被改变过。

ABA问题以及解决:使用带版本号的原子引用AtomicStampedRefence<V>,或者叫时间戳的原子引用,类似于乐观锁。

分布式事务

分布式事务

  1. 2PC:两阶段提交(准备阶段-提交阶段)
    2PC(Two-phase commit protocol),中文叫二阶段提交。 二阶段提交是一种强一致性设计,2PC 引入一个事务协调者的角色来协调管理各参与者(也可称之为各本地资源)的提交和回滚,二阶段分别指的是准备(投票)和提交两个阶段。
    其中引入了协调者,2PC 是一种尽量保证强一致性的分布式事务,因此它是同步阻塞的,而同步阻塞就导致长久的资源锁定问题,总体而言效率低,并且存在单点故障问题,在极端条件下存在数据不一致的风险。

  2. 3PC:准备阶段、预提交阶段和提交阶段
    3PC 包含了三个阶段,分别是准备阶段、预提交阶段和提交阶段,对应的英文就是:CanCommit、PreCommit 和 DoCommit。
    看起来是把 2PC 的提交阶段变成了预提交阶段和提交阶段,但是 3PC 的准备阶段协调者只是询问参与者的自身状况,比如你现在还好吗?负载重不重?这类的。
    3PC 的出现是为了解决 2PC 的一些问题,相比于 2PC 它在参与者中也引入了超时机制,并且新增了一个阶段使得参与者可以利用这一个阶段统一各自的状态。

  1. TCC:(Try - Confirm - Cancel)
    Try 指的是预留,即资源的预留和锁定,注意是预留。
    Confirm 指的是确认操作,这一步其实就是真正的执行了。
    Cancel 指的是撤销操作,可以理解为把预留阶段的动作撤销了。

2PC 和 3PC 都是数据库层面的,而 TCC 是业务层面的分布式事务,就像我前面说的分布式事务不仅仅包括数据库的操作,还包括发送短信等,先试探性的执行,如果都可以那就真正的执行,如果不行就回滚。

  1. 消息事务
    第一步先给 Broker 发送事务消息即半消息,半消息不是说一半消息,而是这个消息对消费者来说不可见,然后发送成功后发送方再执行本地事务。
    再根据本地事务的结果向 Broker 发送 Commit 或者 RollBack 命令。
    并且 RocketMQ 的发送方会提供一个反查事务状态接口,如果一段时间内半消息没有收到任何操作请求,那么 Broker 会通过反查接口得知发送方事务是否执行成功,然后执行 Commit 或者 RollBack 命令。
    如果是 Commit 那么订阅方就能收到这条消息,然后再做对应的操作,做完了之后再消费这条消息即可。
    如果是 RollBack 那么订阅方收不到这条消息,等于事务就没执行过。
    可以看到通过 RocketMQ 还是比较容易实现的,RocketMQ 提供了事务消息的功能,我们只需要定义好事务反查接口即可。


    image.png
jdk各个版本特性

jdk1.8:Lambda表达式,流API,日期API
jdk1.9:模块化
jdk10: var,g1
jdk11:去除字符串首位空格方法
jdk12:switch多条件,同时可以省略break关键字,箭头语法
jdk15:zgc

Lock和synochronized的区别
image.png

synochronized:关键字 自动释放锁 ,采用悲观锁机制 ,非公平,不可中断
lock:一个类 手动释放锁 采用CAS乐观锁,具有公平锁功能,可中断

volatile和synchronized的区别
  1. volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
  2. volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
    volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
  3. volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
  4. volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化
PageHelper底层原理
  1. 调用startPage
  2. 将分页参数存入TreadLocal本地线程对象setLocalPage(将数据存起来)
  3. 设置分页后,会被拦截
  4. 执行分页查询
  5. 拼接分页sql语句
  6. 最后调用mybatis查询获取结果

总结:把分页参数存入到本地线程,执行查询时,会获取本地线程中的分页参数,通过拦截器在sql语句中拼接分页参数,实现分页查询,查询结束后,会在finally 语句中清除ThreadLocal中的查询参数

高并发解决方案
  1. 同一个账号一次性发送:在入口处一次一个账号只接收一个请求
  2. 多个账号一次性发送多个请求:检测指定机器IP请求频率
  3. 多个账号不同ip多个请求:通过账号行为的数据分析,分析出共同特征,适当提交参与门槛
千万数据查询优化
  1. 采用子查询方式,先定位id,再根据id查询数据(只适用于id递增的情况)
  2. 采用 id 限定方式,id必须是连续递增,而且还得计算id的范围,然后使用 between
  3. 禁用select *
MyISAM 和 InnoDB 存储引擎的对比
  • 锁粒度方面:由于锁粒度不同,InnoDB 比 MyISAM 支持更高的并发;InnoDB 的锁粒度为行锁、MyISAM 的锁粒度为表锁、行锁需要对每一行进行加锁,所以锁的开销更大,但是能解决脏读和不可重复读的问题,相对来说也更容易发生死锁
  • 可恢复性上:由于 InnoDB 是有事务日志的,所以在产生由于数据库崩溃等条件后,可以根据日志文件进行恢复。而 MyISAM 则没有事务日志。
  • 查询性能上:MyISAM 要优于 InnoDB,因为 InnoDB 在查询过程中,是需要维护数据缓存,而且查询过程是先定位到行所在的数据块,然后在从数据块中定位到要查找的行;而 MyISAM 可以直接定位到数据所在的内存地址,可以直接找到数据。
  • 表结构文件上: MyISAM 的表结构文件包括:.frm(表结构定义),.MYI(索引),.MYD(数据);而 InnoDB 的表数据文件为:.ibd和.frm(表结构定义);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容

  • 不足的地方请大家多多指正,如有其它没有想到的常问面试题请大家多多评论,一起成长,感谢!~ String可以被继承吗...
    启示录是真的阅读 2,935评论 3 3
  • Java SE 基础: 封装、继承、多态 封装: 概念:就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽...
    Jayden_Cao阅读 2,108评论 0 8
  • java基础 集合承继包含图 Collection vs Collections 首先,"Collection" ...
    onlyHalfSoul阅读 1,315评论 0 5
  • 九种基本数据类型的大小,以及他们的封装类。(1)九种基本数据类型和封装类 (2)自动装箱和自动拆箱 什么是自动装箱...
    关玮琳linSir阅读 1,883评论 0 47
  • 1、面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: -- 抽象:抽象是将一类对象的共同特征总结...
    ccc_74bd阅读 979评论 0 1