这两个区别在于,不可重复读重点在一行,幻读的重点 ,返回的集合不一样
不可重复读重点在于update和delete,而幻读的重点在于insert。
innoDB可重复读怎么实现的?
详情
读已提交
在可重复读级别下,每一个语句执行前都会重新算出一个新的视图
如何解决幻读
在RR级别下,快照读是通过MVCC(多版本控制)和undo log来实现的,当前读是通过加record lock(记录锁)和gap lock(间隙锁)来实现的。在mysql中通过MVCC快照读和next-key当前读两种模式解决幻读问题。
关于MVCC
MySQL InnoDB存储引擎,实现的是基于多版本的并发控制协议——MVCC (Multi-Version Concurrency Control)
MVCC最大的好处:读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能,现阶段几乎所有的RDBMS,都支持了MVCC。
LBCC:Lock-Based Concurrency Control,基于锁的并发控制
MVCC:Multi-Version Concurrency Control
基于多版本的并发控制协议。纯粹基于锁的并发机制并发量低,MVCC是在基于锁的并发控制上的改进,主要是在读操作上提高了并发量。
快照读 (snapshot read):读取的是记录的可见版本 (有可能是历史版本),不用加锁(共享读锁s锁也不加,所以不会阻塞其他事务的写)
当前读 (current read):读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录
关于间隙锁
当我们用范围条件,而不是使用相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据进行加锁; 对于键值在条件范围内但并不存在的记录,叫做 “间隙(GAP)” , InnoDB也会对这个 “间隙” 加锁,这种锁机制就是所谓的 间隙锁 。
锁 | 事务 | 索引 | 场景 | 外键 | |
---|---|---|---|---|---|
MyISAM | 表级锁 | 不支持 | 不支持全~ | 大量查询速度快,小型 | 不支持 |
InnoDB | 行级锁 | 支持且安全 | 支持全文索引 | 支持事务,增删改更好 | 支持 |
索引的类型分类、区别、优缺点
对数据进行频繁查询进建立索引,如果要频繁更改数据不建议使用索引。
索引 | 区别 |
---|---|
聚集索引 | 数据按索引顺序存储,中子结点存储真实的物理数据 |
非聚集索引 | 存储指向真正数据行的指针 |
树 | 区别 |
---|---|
红黑树 | 增加,删除,红黑树会进行频繁的调整,来保证红黑树的性质,浪费时间 |
B树也就是B-树 | B树,查询性能不稳定,查询结果高度不致,每个结点保存指向真实数据的指针,相比B+树每一层每屋存储的元素更多,显得更高一点。 |
B+树 | 1.B+树相比较于另外两种树,显得更矮更宽,查询层次更浅 2.非叶子结点不存放数据,只存放索引,结点更小,所以能存放更多的查找关键字 3.数据都在根节点,每条查询的效率一致 4.只需遍历叶子结点就可以遍历整个树 |
哈希索引 | 1、哈希索引数据并不是按照索引列的值顺序存储的,故无法用于排序。2、哈希索引只支持等值比较查询,如:=、in()、<=>(安全比较运算符,用来做 NULL 值的关系运算),不支持任何范围查询 |
索引的原理
1. 添加PRIMARY KEY(主键索引)
alter table `table_name` add primary key(`column`);
2.添加UNIQUE(唯一索引)
alter table `table_name` add unique(`column`);
3.添加普通索引
alter table `table_name` add index index_name(`column`);
4.添加全文索引
alter table `table_name` add fulltext(`column`);
5.添加多列索引
alter table `table_name` add index index_name(`column1`,`column2`,`column3`);
创建一个简单的索引,名为 "PersonIndex",在 Person 表的 LastName 列:
CREATE INDEX PersonIndex ON Person (LastName)
通过查询索引列来观察
1、如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)
注意:要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引
2、如果是包含> 或者 < 的 想解决 其他索引不失效 就把其他条件放到前面
3、对于多列索引,不是使用的第一部分,则不会使用索引
4、like查询是以%开头,索引失效;以%结尾,索引有效
5、如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
6、如果mysql估计使用全表扫描要比使用索引快,则不使用索引
级别 | 概念 |
---|---|
1NF | 属性不可分 |
2NF | 非主键属性,完全依赖于主键属性 |
3NF | 非主键属性无传递依赖 |
1、使用键值对存储数据;
2、分布式;
不提供sql支持
锁 | 概念 |
---|---|
乐观锁 | 自己实现,通过版本号 |
悲观锁 | 共享锁,多个事务,只能读不能写,加 lock in share mode |
排它锁 | 一个事务,只能写,for update |
行锁 | 作用于数据行 |
表锁 | 作于用表 |
——————————————————————————————————————————————————————
详情
mysql 共享锁 (lock in share mode)
共享锁,事务都加,都能读。修改是惟一的,必须等待前一个事务 commit,才可
排他锁 (for update)
不允许其它事务增加共享或排他锁读取。修改是惟一的,必须等待前一个事务 commit,才可
详情
(Data Query Language):数据查询语言
多表查询、连接查询:
select 查询列表
from 表
join type join 表2
on 连接条件
where 筛选条件
group by 分组字段
having 分组后的筛选
order by 排序的字段】
limit 【offset,】size;
sql99:(sql92使用where仅支持内连接)
分类:
内连接(★):inner
外连接
左外(★):left 【outer】
右外(★):right 【outer】
全外:full【outer】
交叉连接:cross
左右外连接的例子
(Data Manipulate Language):数据操作语言
delete pk truncate Pk drop【面试题★】
/*
1.delete 可以加where 条件,truncate不能加
2.truncate删除,效率高一丢丢
3.假如要删除的表中有自增长列,
如果用delete删除后,再插入数据,自增长列的值从断点开始,
而truncate删除后,再插入数据,自增长列的值从1开始。
4.truncate删除没有返回值,delete删除有返回值
5.truncate删除不能回滚,delete删除可以回滚.
6. drop删除更彻底,表的内容和结构都删除,delete和truncate都保留表的结构
*/
(Data Define Languge):数据定义语言
create table 表名(
列名 列的类型【(长度) 约束】,
列名 列的类型【(长度) 约束】,
列名 列的类型【(长度) 约束】,
…
列名 列的类型【(长度) 约束】)
alter table 表名 add|drop|modify|change column 列名 【列类型 约束】;
DROP TABLE IF EXISTS book_author;
(Transaction Control Language):事务控制语言
RDB和AOF详解
RDB(Redis Database) 持久化
AOF(Append Only File) 持久化
将写命令添加到 AOF 文件的末尾。
使用 AOF 持久化需要设置同步选项,从而确保写命令同步到磁盘文件上的时机。这是因为对文件进行写入并不会马上将内容同步到磁盘上,而是先存储到缓冲区,然后由操作系统决定什么时候同步到磁盘。有以下同步选项:
选项 | 同步频率 |
---|---|
always | 每个写命令都同步 |
everysec | 每秒同步一次 |
no | 让操作系统来决定何时同步 |
详情
原生批命令是原子性,pipeline是非原子性
(原子性概念:一个事务是一个不可分割的最小工作单位,要么都成功要么都失败。原子操作是指你的一个业务逻辑必须是不可拆分的. 处理一件事情要么都成功,要么都失败,原子不可拆分)
原生批命令一命令多个key, 但pipeline支持多命令(存在事务),非原子性
原生批命令是服务端实现,而pipeline需要服务端与客户端共同完成
详情
详情语法
知识点
1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
2.注册url,用户名密码,建立数据库连接
Connection con = DriverManager.getConnection(url , username , password);
3.准备 SQL 语句,获取 SQL 语句发送器(Statement)
静态sql:Statement stmt = con.createStatement();
动态sql:PreparedStatement pstmt = con.prepareStatement(sql);
4.发送并执行 SQL 语句, 得到结果集(ResultSet)
ResultSet rs = stmt.executeQuery("SELECT * FROM ...");
5.处理结果集
while(rs.next()) {
String name = rs.getString("name");
String pass = rs.getString(1); // 此方法比较高效
}
6.关闭资源(ResultSet, Statement, Connection)
一、DriverManager.registerDriver(new com.microsoft.sqlserver.jdbc.SQLServerDriver());
jdbc是使用桥的模式进行连接的。DriverManager就是管理数据库驱动的一个类,java.sql.Driver就是一个提供注册数据库驱动的接口,而com.microsoft.sqlserver.jdbc.SQLServerDriver()是java.sql.Driver接口的一个具体实现。
二、System.setProperty(“jdbc.drivers”, “com.microsoft.sqlserver.jdbc.SQLServerDriver”);
多个驱动使用冒号分隔开,在连接时JDBC会按顺序搜索,直到找到第一个能成功连接指定URL的驱动程序。
三、Class.forName(“com.microsoft.sqlserver.jdbc.SQLServerDriver”);
第一种与第二种注册的方法看起来更加的直接与好理解。第三种方法是通过Class把类先装载到java的虚拟机中,并没有创建Driver类的实例。
1.PreparedStatement 继承于 Statement
2.Statement 一般用于执行固定的没有参数的SQL
3.PreparedStatement 一般用于执行有?参数预编译的SQL语句。
4.PreparedStatement支持?操作参数,相对于Statement更加灵活。
5.PreparedStatement可以防止SQL注入,安全性高于Statement。
因为sql语句是预编译的,而且语句中使用了占位符,规定了sql语句的结构。用户可以设置"?"的值,但是不能改变sql语句的结构,因此想在sql语句后面加上如“or 1=1”实现sql注入是行不通的。
实际开发中,一般采用PreparedStatement访问数据库,它不仅能防止sql注入,还是预编译的(不用改变一次参数就要重新编译整个sql语句,效率高),此外,它执行查询语句得到的结果集是离线的,连接关闭后,仍然可以访问结果集。
PreparedStatement的一个缺点是,我们不能直接用它来执行in条件语句;需要执行IN条件语句的话,下面有一些解决方案:
事务是作为单个逻辑工作单元执行的一系列操作,四个属性,称为原子性、一致性、隔离性和持久性 (ACID) 属性,只有这样才能成为一个事务。
Connection类中提供了4个事务处理方法:
注意:savepoint不会结束当前事务,普通提交和回滚都会结束当前事务的