0%

什么是索引?

索引(Index)是帮助MySQL高效获取数据的数据结构

索引的分类

  • 主键索引(primary key)
    • 唯一的标识,主键不可重复,只能有一个列作为主键
  • 唯一索引(unique key)
    • 避免重复的列出现,唯一索引可以重复,多个列都可标识唯一索引
  • 常规索引(key/index)
    • 默认的,index。key关键字设置
  • 全文索引(fulltext)
    • 在特定数据库引擎下,MyISAM
    • 快速定位数据

索引原则

  • 索引不是越多越好
  • 不要对进程变动数据加索引
  • 小数据量的表不需要加索引
  • 索引一般加在常用来查询的字段上

索引的数据结构

什么是事务?

要么都成功,要么都失败

将一组SQL放在一个批次执行

事务原则:ACID原则

原子性,一致性,隔离性,持久性

原子性(Atomicity)

原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

一致性(Consistency)

事务前后数据的完整性必须保持一致。

隔离性(Isolation)

事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

持久性(Durability)

事务提交不可逆

持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

事务的隔离级别

脏读:

指一个事务读取了另外一个事务未提交的数据

不可重复读:

在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)

虚读(幻读):

是指在一个事务内读取到了别的事务插入的数据,导致前后读取数量总量不一致。
(一般是行影响)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-- mysql 是默认开启事务自动提交的
set autocommit = 0 -- 关闭
set autocommit = 1 -- 开启

-- 手动处理事务
set autocommit = 0 -- 第一步 关闭自动提交
-- 事务开启
start transaction -- 标记一个事务开始,从这之后的sql都在一个事务内
-- 两种情况
-- 提交: 持久化(成功)
commit
-- 回滚: 回到原来的样子(失败)
rollback
-- 事务结束
set autocommit = 1 -- 开启自动提交

savepoint 名称 -- 设置事务保存点
rollback to savepoint 名称 -- 回滚到保存点
release savepoint 名称 -- 撤销保存点

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 时间日期函数
select current_date() -- 获取当前日期
select curdate() -- 获取当前日期
select now() -- 获取当前日期时间
select localtime() -- 获取本地时间
select sysdate() -- 系统时间

select year(now())
select month(now())
select day(now())
select hour(now())
select minute(now())
select second(now())
1
2
3
-- 聚合函数
select count([]) from [] -- 会忽略null
select sum() avg() max() min()
1
2
3
4
-- 分组
group by [] -- 通过什么字段分组
-- 过滤
having -- 分组后过滤

1
2
3
4
-- 排序 升序asc 降序desc
order by [] {asc || desc}

-- 分页 limit 想要第几页, 页面大小
1
2
3
-- 嵌套查询
select [] from []
where [] = (select [] from [] where [])

1
2
3
4
5
6
-- 模糊查询
-- like结合 %(代表0到任意个字符) _(代表一个字符)
select [] from [] where xxx like '刘%'

-- in
select [] from [] where xxx in (a, b, c);
1
2
3
4
5
6
7
-- join
-- join on 连接查询
-- where 等值查询
select A.a, b, c, d
from xxx as A
inner join yyy as B
on A.a = B.a

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
select [all || distinct]
{* | table.* | [table.field1[as alias1][, table.field2[as alias2]][,...]]}
from table_name [as table_alias]
[left | right | inner join table_name2] -- 联合查询
[where ...] -- 指定结果需满足条件‘
[group by ...] -- 指定结果按照哪几个字段分组
[having] -- 过滤分组的记录必须满足的次要条件
[order by ...] -- 指定查询记录按一个或多个条件排序
[limit {[offset,]row_count | row_countOFFSET offset}];

-- 查询所有字段
select * from [表]

-- 查询指定字段
select [字段名], [字段名] from [表]

-- 别名,给结果起名
select [字段名] as [别名] from [表]

-- 函数 concat(a, b) 拼接字符串
select concat('姓名:', [字段名]) as [别名] from [表]
1
2
3
4
5
6
7
8
9
-- 去重
select distinct [] from []

-- select 其他用法
select version() -- 查询系统版本
select [表达式] -- 计算结果
select @@auto_increment_increment -- 查询自增步长(变量)

select [] + 1 from [] -- 结果加一

1
2
3
4
5
6
7
-- update 表名 set colnum_name = value, [colnum_name = value...] where [条件]

-- 条件 between...and... 在两者时间
-- AND &&
-- OR ||

-- delete from 表名 where [条件]

delete 与 truncate

  • 相同点:都能删除数据,都不会删表结构
  • 不同: truncate重新设置自增列,计数器会归零,在innodb中delete需要重启数据库才会归零,因为存在内存中。truncate不会影响事务

  • Map中的key:无序,不可重复,使用Set存储
  • Map中的value:无序,可重复,使用Collection存储
  • 一个key-value键值对构成一个Entry对象(JDK7),Node(JDK8)
  • 键值对无序,不可重复,使用Set存储

HashMap底层实现

JDK8相较于JDK7在底层实现方面不同
  • new HashMap():底层没有创建一个长度为16的数组
  • jdk8底层数组是:Node[]
  • 首次使用put(),创建长度为16数组
  • 数组+链表+红黑树
  • 当数组中某一索引位置元素以链表形式存在的数据个数 > 8,且当前数据长度 > 64时,此索引位置上改为红黑树存储
HashMap源码中重要常量
  • DEFAULT_INITIAL_CAPACITY:HashMap的默认容量,16
  • MAXIMUM_CAPACITY:HashMap的最大支持容量,2^30
  • DEFAULT_LOAD_FACTOR:HashMap的默认加载因子,0.75
  • TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树
  • UNTREEIFY_THRESHOLD:Bucket中红黑树存储的Node小于该默认值,转化为链表
  • MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量(当桶中Node的数量大到需要变红黑树时,若hash表容量小于MIN_TREEIFY_CAPACITY时,此时应执行resize扩容操作,这个MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4倍)
  • table:存储元素的数组,总是2的n次幂
  • entrySet:存储具体元素的集
  • size:HashMap中存储键值对的数量
  • modCount:HashMap扩容和结构改变次数
  • threshold:扩容临界值 = 容量 * 填充因子
  • loadFactor:填充因子

ArrayList

JDK7
  • 无参:底层创建长度为10的Object[]数组elementData
  • 扩容:扩容为原来的1.5倍
JDK8
  • 无参:空的Object[]数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA
  • 首次添加:minCapacity = min(10, 添加长度)
  • 扩容:扩容为原来的1.5倍

LinkedList

  • 内部声明名为Node类型的first和last属性,值为null
  • 双向链表

  • 先看看常量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //默认初始容量,必须是2的幂
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
    //最大容量
    static final int MAXIMUM_CAPACITY = 1 << 30;
    //负载因子,0.75符合泊松分布
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    //树的阈值,链表长度达到8就转为红黑树
    static final int TREEIFY_THRESHOLD = 8;
    //链表阈值
    static final int UNTREEIFY_THRESHOLD = 6;
    //元素至少一共有这么多,才允许树化链表
    static final int MIN_TREEIFY_CAPACITY = 64;
  • ```java
    /一个Node节点
    四个成员变量:哈希值,Key名,value值,next指针
    构造函数
    获取键
    获取值
    toString()
    获取hashcode,是键和值的按位与
    覆盖值
    比较值是否一致
    /
    static class Node implements Map.Entry {

    final int hash;
    final K key;
    V value;
    Node<K,V> next;
    
    Node(int hash, K key, V value, Node<K,V> next) {
        this.hash = hash;
        this.key = key;
        this.value = value;
        this.next = next;
    }
    
    public final K getKey()        { return key; }
    public final V getValue()      { return value; }
    public final String toString() { return key + "=" + value; }
    
    public final int hashCode() {
        return Objects.hashCode(key) ^ Objects.hashCode(value);
    }
    
    public final V setValue(V newValue) {
        V oldValue = value;
        value = newValue;
        return oldValue;
    }
    
    public final boolean equals(Object o) {
        if (o == this)
            return true;
        if (o instanceof Map.Entry) {
            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
            if (Objects.equals(key, e.getKey()) &&
                Objects.equals(value, e.getValue()))
                return true;
        }
        return false;
    }
    

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

    - ```java
    //当前负载因子
    final float loadFactor;
    /*两个参数的构造
    (大小,负载因子)
    */
    public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
    throw new IllegalArgumentException("Illegal initial capacity: " +
    initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
    initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
    throw new IllegalArgumentException("Illegal load factor: " +
    loadFactor);
    this.loadFactor = loadFactor;
    this.threshold = tableSizeFor(initialCapacity);
    }
    public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
    public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }
  • /*
    如果HashMap不为空,且存在该key的节点
    总是先检查第一个是否匹配
    若是链表,遍历比较
    若是树,进入getTreeNode
    */
    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }