大部分知识点来源于该博主——骆昊
知识点来源于网络,知道的可以在评论区贴上来源喔
《零散知识点总结1》
该文章涉及:Dubbo、HTTP和HTTPS、Mybatis、Hibernate、 Zookeeper、Kafka、Elasticsearch、Redis
《零散知识点总结2》
该文章涉及:MySQL、Java并发编程、Java IO 和 NIO、JUnit单元测试
《零散知识点总结3》
该文章涉及 :Java Web、spring、SpringMVC、springboot、springcloud、微服务
《零散知识点总结4》
该文章涉及:JVM和GC、Linux、Git、RabbitMQ
《零散知识点总结5》
该文章涉及:多线程、反射、对象拷贝、异常、容器
零散知识点总结2
- MySQL
-
- SQL常用语句
- 说说对 SQL 语句优化有哪些方法?
- 如何通俗地理解三个范式?
- 锁
- 说一下 MySQL 常用的引擎?(InnoDB 、MyIASM )
- MySQL 如何优化 DISTINCT?
- 什么是通用 SQL 函数?
- MySQL 事务
- MySQL和Oracle 区别?
- 左连接与右连接以及全连接的区别?
- MySQL 有关权限的表都有哪几个?
- MySQL 数据库作发布系统的存储,一天五万条以上的增量,预计运维三年,怎么优化?
- MySQL 索引
- 栈中如何优化 MySQL?
- 优化数据库的方法
- 主键、外键和索引的区别?
- SQL 注入漏洞产生的原因?如何防止?
- 存储时期
- 对于关系型数据库而言,索引是相当重要的概念,请回答有关索引的几个问题:
- MySQL 问题排查都有哪些手段?
- 如何做 MySQL 的性能优化?
- MySQL数据库和Redis的区别?
- 视图
- MySQL数据库CPU飙升怎么解决
- Java并发编程(一)
-
- 完整性约束包括哪些?
- 什么叫视图?游标是什么?
- 什么是存储过程?用什么来调用?
- 什么是基本表?什么是视图?
- 试述视图的优点?
- 你可以用什么来确保表格里的字段只接受特定范围里的值?
- 在 java 中守护线程和本地线程区别?
- 线程与进程的区别?
- 什么是多线程中的上下文切换?
- 死锁与活锁的区别,死锁与饥饿的区别?
- Java 中用到的线程调度算法是什么?
- 什么是线程组,为什么在 Java 中不推荐使用?
- 为什么使用 Executor 框架?
- 在 Java 中 Executor 和 Executors 的区别?
- 如何在 Windows 和 Linux 上查找哪个线程使用的 CPU 时间最长?
- 什么是原子操作?在 Java Concurrency API 中有哪些原子类(atomic classes)?
- Java Concurrency API 中的 Lock 接口(Lock interface)是什么?
- 什么是 Executors 框架?
- 什么是阻塞队列?阻塞队列的实现原理是什么?如何使用阻塞队列来实现生产者-消费者模型?
- 什么是 Callable 和 Future?
- 什么是 FutureTask?使用 ExecutorService 启动任务。
- 什么是并发容器的实现?
- 多线程同步和互斥有几种实现方法,都是什么?
- 什么是竞争条件?你怎样发现和解决竞争?
- 你将如何使用 thread dump?你将如何分析 Thread dump?
- 为什么我们调用 start()方法时会执行 run()方法,为什么我们不能直接调用 run()方法?
- Java 中你怎样唤醒一个阻塞的线程?
- 什么是不可变对象,它对写并发应用有什么帮助?
- 什么是多线程中的上下文切换
- Java 中用到的线程调度算法是什么?
- 什么是线程组,为什么在 Java 中不推荐使用?
- 为什么使用 Executor 框架比使用应用创建和管理线程好?
- java 中有几种方法可以实现一个线程?
- 如何停止一个正在运行的线程?
- notify()和 notifyAll()有什么区别?
- 什么是 Daemon 线程?它有什么意义?
- java 如何实现多线程之间的通讯和协作?
- 什么是可重入锁(ReentrantLock)?
- 当一个线程进入某个对象的一个 synchronized 的实例方法后,其它线程是否可进入此对象的其它方法?
- 乐观锁和悲观锁的理解及如何实现,有哪些实现方式?
- SynchronizedMap 和 ConcurrentHashMap 有什么区别?
- CopyOnWriteArrayList 可以用于什么应用场景?
- 什么叫线程安全?servlet 是线程安全吗?
- volatile 有什么用?能否用一句话说明下 volatile 的应用场景?
- 为什么代码会重排序?
- 在 java 中 wait 和 sleep 方法的不同?
- 用 Java 实现阻塞队列
- 一个线程运行时发生异常会怎样?
- 如何在两个线程间共享数据?
- 为什么 wait, notify 和 notifyAll 这些方法不在 thread 类里面?
- 什么是 ThreadLocal 变量?
- Java 中 interrupted 和 isInterrupted 方法的区别?
- 为什么 wait 和 notify 方法要在同步块中调用?
- 为什么你应该在循环中检查等待条件?
- Java 中的同步集合与并发集合有什么区别?
- 用哪两种方式来实现集合的排序?
- Java 中怎么打印数组?
- Java 中的 LinkedList 是单向链表还是双向链表?
- Java 中的 TreeMap 是采用什么树实现的?
- Hashtable 与 HashMap 有什么不同之处?
- 什么是线程池? 为什么要使用它?
- 怎么检测一个线程是否拥有锁?
- 你如何在 Java 中获取线程堆栈?
- Thread 类中的 yield 方法有什么作用?
- Java 中 ConcurrentHashMap 的并发度是什么?
- Java 中 Semaphore 是什么?
- Java 线程池中 submit() 和 execute()方法有什么区别?
- 什么是阻塞式方法?
- Java 中的 ReadWriteLock 是什么?
- volatile 变量和 atomic 变量有什么不同?
- 可以直接调用 Thread 类的 run ()方法么?
- 如何让正在运行的线程暂停一段时间?
- 你对线程优先级的理解是什么?
- 什 么 是 线 程 调 度 器 (Thread Scheduler) 和 时 间 分 片 (TimeSlicing )?
- 你如何确保 main()方法所在的线程是 Java 程序最后结束的线程?
- 线程之间是如何通信的?
- 为什么线程通信的方法 wait(), notify()和 notifyAll()被定义在Object 类里?
- 为什么 wait(), notify()和 notifyAll ()必须在同步方法或者同步块中被调用?
- 为什么 Thread 类的 sleep()和 yield ()方法是静态的?
- 如何确保线程安全?
- 同步方法和同步块,哪个是更好的选择?
- 如何创建守护线程?
- 什么是 Java Timer 类?如何创建一个有特定时间间隔的任务?
- Java并发编程(二)
-
- 并发编程三要素?
- 实现可见性的方法有哪些?
- 多线程的价值?
- 创建线程的方式有哪些?
- 创建线程的三种方式对比
- 线程状态流转图
- Java 线程具有五中基本状态
- 什么是线程池?有哪几种创建方式?
- 四种线程池的创建:
- 线程池的优点?
- 常用的并发工具类有哪些?
- synchronized 的作用?
- volatile 关键字的作用
- 什么是 CAS
- CAS 的问题
- 什么是 Future?
- 什么是 AQS
- AQS 支持两种同步方式:
- ReadWriteLock 是什么
- FutureTask 是什么
- synchronized 和 ReentrantLock 的区别
- 什么是乐观锁和悲观锁
- 线程 B 怎么知道线程 A 修改了变量
- synchronized、volatile、CAS 比较
- sleep 方法和 wait 方法有什么区别?
- ThreadLocal 是什么?有什么用?
- 为什么 wait()方法和 notify()/notifyAll()方法要在同步块中被调用
- 多线程同步有哪几种方法?
- 线程的调度策略
- ConcurrentHashMap 的并发度是什么
- Linux 环境下如何查找哪个线程使用 CPU 最长
- Java 死锁以及如何避免?
- 死锁的原因
- 怎么唤醒一个阻塞的线程
- 不可变对象对多线程有什么帮助
- 什么是多线程的上下文切换
- 如果你提交任务时,线程池队列已满,这时会发生什么
- Java 中用到的线程调度算法是什么
- 什么是线程调度器(Thread Scheduler)和时间分片(TimeSlicing)?
- 什么是自旋
- Java Concurrency API 中的 Lock 接口(Lock interface)是什么?对比同步它有什么优势?
- 单例模式的线程安全性
- 同步方法和同步块,哪个是更好的选择?
- Java 线程数过多会造成什么异常?
- 浅谈Java SE、Java EE、Java ME三者的区别
- Java
-
- “a==b”和”a.equals(b)”有什么区别?
- 面向对象的特征有哪些方面?
- 访问修饰符 public,private,protected,以及不写(默认)时的区别?
- String 是最基本的数据类型吗?
- float f=3.4;是否正确?
- short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?
- int 和 integer 有什么区别?
- &和&&的区别?
- Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?
- switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上?
- 数组有没有 length()方法?String 有没有 length()方法?
- 在 Java 中,如何跳出当前的多重嵌套循环?
- 构造器(constructor)是否可被重写override?
- 重载(Overload)和重写(override)的区别?重载的方法能否根据返回类型进行区分?
- **==为什么不能根据返回类型来区分重载?==**
- 是否可以继承string类?
- 抽象类(abstract class)和接口(interface)有什么异同?
- 静态嵌套类(Static Nested Class)和内部类(Inner Class)的不同?
- Java 中会存在内存泄漏吗,请简单描述。
- 阐述静态变量和实例变量的区别
- 是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?
- 如何实现对象克隆?
- GC 是什么?为什么要有 GC?
- String s=new String("xxc"),创建了几个字符串对象?
- 关于接口、抽象类和具体类之间的继承(extends)和实现(implements)问题
- 一个”.java”源文件中是否可以包含多个类(不是内部类)?有什么限制?
- Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口?
- 内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制?
- Java 中的final关键字有哪些用法?
- 数据类型之间的转换
- 如何实现字符串的反转及替换?
- 怎样将 GB2312 编码的字符串转换为 ISO-8859-1 编码的字符串?
- 日期和时间:
- 比较Java和JavaScript
- Error 和 Exception 有什么区别?
- try{}里有一个 return 语句,那么紧跟在这个 try 后的finally{}里的代码会不会被执行,什么时候被执行,在 return前还是后?
- Java 语言如何进行异常处理,关键字:throws、throw、try、catch、finally 分别如何使用?
- 列出一些你常见的运行时异常?
- 阐述 final、finally、finalize 的区别
- List、Set、Map 和 Queue 之间的区别
- List 、Set 、Map 是否继承自Collection接口?三个接口存取元素时各有什么特点?
- Collection 和 Collections 的区别?
- 举例说明同步和异步。
- 启动一个线程用的是run()还是start()方法?
- Java 中如何实现序列化,有什么意义?
- Java 中有几种类型的流?
- 写一个方法,输入一个文件名和一个字符串,统计这个字符串在这个文件中出现的次数
- 如何用 Java 代码列出一个目录下所有的文件?
- 你在项目中哪些地方用到了 XML?
- 阐述 JDBC 操作数据库的步骤。
- 使用 JDBC 操作数据库时,如何提升读取数据的性能?如何提升更新数据的性能?
- 在进行数据库编程时,连接池有什么作用?
- 什么是DAO模式?
- poll() 方法和 remove() 方法的区别?
- ArrayList 与 LinkedList 的不区别?
- 简述正则表达式及其用途。
- Java 中是如何支持正则表达式操作的?
- 获得一个类的类对象有哪些方式?
- 简述一下面向对象的”六原则一法则
- 简述一下你了解的设计模式。
- 用 Java 写一个冒泡排序。
- 冒泡排序算法
- 用 Java 写一个折半查找。(二分法)
- Java 中应该使用什么数据类型来代表价格?
- 怎么将 byte 转换为 String?将 bytes 转换为 long 类型?
- 我们能将 int 强制转换为 byte 类型的变量吗?如果该值大于 byte 类型的范围,将会出现什么现象?
- 存在两个类,B 继承 A,C 继承 B,我们能将 B 转换为C 么?如 C = (C) B;
- Java 中 ++ 操作符是线程安全的吗?
- 我能在不进行强制转换的情况下将一个 double 值赋值给long 类型的变量吗?
- 3*0.1 == 0.3 将会返回什么?true 还是 false?
- int 和 Integer 哪个会占用更多的内存?
- 为什么 Java 中的 String 是不可变的(Immutable)?
- Java 中的 HashSet,内部是如何工作的?
- 写一段代码在遍历 ArrayList 时移除一个元素?
- 我们能自己写一个容器类,然后使用 for-each 循环码?
- 有没有可能两个不相等的对象有有相同的 hashcode?
- 我们可以在hashcode()中使用随机数字吗 ?
- Java 中,Comparator 与 Comparable 有什么不同?
- 为什么在重写 equals 方法的时候需要重写 hashCode 方法?
- Java IO 和 NIO
- JUnit单元测试
-
- 如何测试静态方法?
- 怎么利用 JUnit 来测试一个方法的异常?
- 你使用过哪个单元测试库来测试你的 Java 程序?
- @Before 和 @BeforeClass 有什么区别?
- 怎么检查一个字符串只包含数字?
- Java 中如何利用泛型写一个 LRU 缓存?
- 写一段 Java 程序将 byte 转换为 long?
- Java中如何将字符串转换为整数?
- 在没有使用临时变量的情况如何交换两个整数变量的值?
- 接口是什么?为什么要使用接口而不是直接使用具体类?
- Java 中,抽象类与接口之间有什么不同?
- 你能解释一下里氏替换原则吗?
- 什么情况下会违反迪米特法则?为什么会有这个问题?
- 适配器模式是什么?什么时候使用?
- 什么是“依赖注入(IOC)”和“控制反转(DI)”?为什么有人使用?
- 抽象类是什么?它与接口有什么区别?你为什么要使用过抽象类?
- 构造器注入和 setter 依赖注入,那种方式更好?
- 依赖注入和工程模式之间有什么不同?
- 适配器模式和装饰器模式有什么区别?
- 适配器模式和代理模式之前有什么不同?
- 什么是模板方法模式?
- 什么时候使用访问者模式?
- 什么时候使用组合模式?
- 继承和组合之间有什么不同?
- 描述 Java 中的重载和重写?
- Java 中,嵌套公共静态类与顶级类有什么不同?
- OOP 中的 组合、聚合和关联有什么区别?
- 给我一个符合开闭原则的设计模式的例子?
- 抽象工厂模式和原型模式之间的区别?
- 什么时候使用享元模式?
- 嵌套静态类与顶级类有什么区别?
- 你能写出一个正则表达式来判断一个字符串是否是一个数字吗?
- Java 中,受检查异常 和 不受检查异常的区别?
- Java 中,throw 和 throws 有什么区别
- Java 中,Serializable 与 Externalizable 的区别?
- Java 中,DOM 和 SAX 解析器有什么不同?
- 说出 JDK 1.7 中的三个新特性?
- 说出 5 个 JDK 1.8 引入的新特性?
- Java 中,Maven 和 ANT 有什么区别?
MySQL
什么是MySQL?
MySQL是一个开源的关系型数据管理系统,用于存取数据、查询、更新和管理数据。
对MySQL数据库去重的关键字是什么?
select distinct 字段名 from 表名
数据库自带的distinct这个关键字来过滤掉多余的重复记录只保留一条,但往往只用它来返回不重复记录的条数,而不是用它来返回不重复记录的所有值。其原因是 distinct只能返回它的目标字段,而无法返回其它字段。
SQL常用语句
新增表:
Create table 表名{
字段 类型 限制(主键/是否自增/是否允许为空) //主键:PRIMARY KEY ; 自增:AUTO_INCREMENT ;不允许为空:NOT NULL
}
MySQL的约束有哪些?
NOT NULL: 约束字段的内容一定不能为NULL。
UNIQUE: 约束字段唯一性,一个表允许有多个Unique约束。
PRIMARY KEY(主键): 约束字段唯一,不可重复,一个表只允许存在一个。
FOREIGN KEY(外键): 用于预防破坏表之间连接的动作,也能防止非法数据插入外键。
CHECK: 用于控制字段的值范围。
删除表:
delete from 表名 where 字段名=字段值
每次删除一行,可回滚数据 rollbacktruncate table 表名
清空表中数据,保留表的数据结构(删表数据不可以回滚)drop table 表名
删除表数据跟表结构,不可回滚
新增数据:insert into 表名 列名1,2,... values(1,2,...)
删除数据:delete from 表名 where 过滤条件
查询数据:select 字段名 from 表名 where 字段名=字段值 order by 字段值 asc(升序)/desc(降序)
select 字段名 from 表名 where 字段名=字段值 order by 字段值 asc(升序)/desc(降序)
select * from 表/表达式 where 过滤条件/group by 分组内容/having 组内条件/order by 字段 排序方式(asc/desc)
1. Having 和where 的区别:having是在分组后对数据进行过滤
where是在分组前对数据进行过滤
having后面可以使用聚合函数
where后面不可以使用聚合
在查询过程中执行顺序:from>where>group(含聚合)>having>order>select。
2. 聚合语句:sum、min、max、avg、count
having的作用和where的作用类似,但是where不能和聚合函数(max,min,sum,avg等)一起使用,因此需要having。
Eg:select * from table having max(column_name);
注意:where …… group by …… having ……
模糊查询:select 字段 from 表名 where条件 like ‘模糊查询内容’
查询内容例如:姓苏的 like ‘苏%’;姓苏且长度为3 的 like ‘苏__’ 这_代表占用一个字位置
字段名 like '%字段值%'
字段名 like '%李_%' 表示查询以李字开头的
字段名 like '%_李%' 表示查询以李字结尾的
字段名 like '[张李王]三' 表示将会查询出张三、李三、王三
修改数据:update 表名 set 字段名=新值 where id=5
MySQL多表连接有哪些方式?怎么用的?这些连接都有什么区别?
连接方式:左连接、右连接、内连接
使用方法:
-
左连接:
select * from A left join B on A.id=B.id;
-
右连接:
select * from A right join B on A.id=B.id;
-
内连接:
select * from A inner join B on a.xx=b.xx;
(其中inner可以省略)
写作 :select * from A join B on a.xx=b.xx;
区别:
-
Inner join 内连接,在两张表进行连接查询时,只保留两张表中完全匹配的结果集
-
left join 在两张表进行连接查询时,会返回左表所有的行,即使在右表中没有匹配的记录。
-
right join 在两张表进行连接查询时,会返回右表所有的行,即使在左表中没有匹配的记录。
如何显示前 50 行?
在 MySQL 中,使用以下代码查询显示前 50 行:select * from 表名 where limit 0,50
SQL 语言包括哪几部分?每部分都有哪些操作关键字?
SQL 语言包括数据定义(DDL)、数据操纵(DML),数据控制(DCL)和数据查询(DQL)四个部分。
- 数据定义:
Create Table,Alter Table,Drop Table, Craete/Drop Index
等 - 数据操纵:
Select ,insert,update,delete,
- 数据控制:
grant(授予),revoke(撤销)
- 数据查询:
select
列对比运算符是什么?
在 SELECT 语句的列比较中使用=,<>,<=,<,> =,>,<<,>>,<=>,AND,OR 或 LIKE
运算符。
说说对 SQL 语句优化有哪些方法?
可以从这几个维度回答这个问题:加索引、避免返回不必要的数据、适当分批量进行、优化sql结构、分库分表、读写分离
- Where 子句中:where 表之间的连接必须写在其他 Where 条件之前,那些可以过滤掉最大数量记录的条件必须写在 Where 子句的末尾 having 最后。
- 用exists替代 in、用 not exists替代 not in。
- 避免在索引列上使用计算
- 避免在索引列上使用
is null
和is not null
- 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
select * from 表 改为 select 字段1,字段2 from 表 - 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描
- 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描
如何通俗地理解三个范式?
- 第一范式(列的原子性):1NF 是对属性的原子性约束,要求属性具有原子性,不可再分解;
- 第二范式(行的唯一区分,由主键决定):2NF 是对记录的惟一性约束,要求记录有惟一标识,即实体的惟一性;
- 第三范式:3NF 是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余。【表的非主属性不能依赖与他表的非主属性 外键约束】
范式化设计优缺点:
优点:可以尽量得减少数据冗余,使得更新快,体积小
缺点: 对于查询需要多个表进行关联,减少写的效率增加读的效率,更难进行索引优化
反范式化:
优点:可以减少表得关联,可以更好得进行索引优化
缺点:数据冗余以及数据异常,数据的修改需要更多的成本
MySQL数据库和Redis的区别?
MySQL和Redis都可以存放数据,但MySQL里的数据是永久的,而Redis里的数据是缓存并有缓存机制,新的数据过来,老的数据会根据缓存机制失效。但是从Redis中读取数据比较快方便,而MySQL里的逻辑复杂,数据量大,读取数据耗时长。
UNION和UNION ALL的区别?
- Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;
- Union All:对两个结果集进行并集操作,包括重复行,不进行排序;UNION的效率高于UNION ALL
锁
什么是锁?
数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。
加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对象进行操作前,先向系统发出请求,对其加锁。加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前,其他的事务不能对此数据对象进行更新操作。
MySQL 中的锁
基本锁类型:锁包括行级锁和表级锁
- 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
- 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
- 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
锁的优化策略
- 读写分离
- 分段加锁
- 减少锁持有的时间
- 多个线程尽量以相同的顺序去获取资源
不能将锁的粒度过于细化,不然可能会出现线程的加锁和释放次数过多,反而效率不如一次加一把大锁。
说一下 MySQL 的行锁和表锁?
MyISAM 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁。
- 表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低。
- 行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高。
说一下乐观锁和悲观锁?
-
乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。
-
悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻止,直到这个锁被释放。
数据库的乐观锁需要自己实现,在表里面添加一个 version 字段,每次修改成功值加 1,这样每次修改的时候先对比一下,自己拥有的 version 和数据库现在的 version 是否一致,如果不一致就不修改,这样就实现了乐观锁。
什么是死锁?怎么解决?
死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。
有四个必要条件:互斥条件,请求和保持条件,环路等待条件,不剥夺条件。
- 解决死锁思路,一般就是切断环路,尽量避免并发形成环路。
- 如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会;
- 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
- 对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;
- 如果业务处理不好可以用分布式事务锁或者使用乐观锁;
- 死锁与索引密不可分,解决索引问题,需要合理优化索引。
MySQL 中有哪些不同的表格?
共有 5 种类型的表格: MyISAM、Heap、Merge、INNODB、ISAM
说一下 MySQL 常用的引擎?(InnoDB 、MyIASM )
引擎 | 特点 |
---|---|
MyIASM 引擎 | 不提供事务的支持,也不支持行级锁和外键。因此当执行插入和更新语句时,即执行写操作的时候需要锁定这个表,所以会导致效率会降低。不过和 InnoDB 不同的是,MyIASM 引擎是保存了表的行数,于是当进行 select count(*) from table 语句时,可以直接的读取已经保存的值而不需要进行扫描全表。所以,如果表的读操作远远多于写操作时,并且不需要事务的支持的,可以将 MyIASM 作为数据库引擎的首选 |
InnoDB 引擎 | mysql 5.1 后默认的数据库引擎,提供了对数据库 ACID事务的支持,并且还提供了行级锁和外键的约束,它的设计的目标就是处理大数据容量的数据库系统。MySQL 运行的时候,InnoDB 会在内存中建立缓冲池,用于缓冲数据和索引。但是该引擎是不支持全文搜索,同时启动也比较的慢,它是不会保存表的行数的,所以当进行 select count(*) from table 指令的时候,需要进行扫描全表。由于锁的粒度小,写操作是不会锁定全表的,所以在并发度较高的场景下使用会提升效率的。 |
MySQL 中 InnoDB 支持的四种事务隔离级别名称,以及逐级之间的区别?
SQL 标准中定义了 4 种隔离级别,每一种级别都规定了一个事务中所做的修改,哪些是在事务内和事务间可见的,哪些是不可见的。
较低级别的隔离通常可以执行更高的并发,系统的开销也更低。
SQL 标准定义的四个隔离级别为:
Read Uncommitted ( 未提交读 ) 、
Read Committed (提交读)、
Repeatable Read (可重复读)、
Serializable (可串行化) ,
不同的隔离级别有不同的现象,并有不同的锁 和 并发机制,隔离级别越高,数据库的并发性 能 就越差, 4 种事 隔离级别与并发性能的关系:
一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 MySQL 数据库,又插入了一条数据,此时 id 是几?
- 表类型如果是 MyISAM ,那 id 就是 8。【MyISAM 记录表的总条数】
- 表类型如果是 InnoDB,那 id 就是 6。
InnoDB 表只会把自增主键的最大 id 记录在内存中,所以重启之后会导致最大 id 丢失。
如何获取当前数据库版本?
使用 select version()
获取当前 MySQL 数据库版本。
char 和 varchar 的区别?
- 在存储和检索方面不同
- char 列长度固定为创建表时声明的长度,长度值范围是 1 到 255 当 char 值被存储时,它们被用空格填充到特定长度,检索 char 值时需删除尾随空格。
主键和候选键有什么区别?
表格的每一行都由主键唯一标识,一个表只有一个主键。
主键也是候选键。按照惯例,候选键可以被指定为主键,并且可以用于任何外键引用
如果一个表有一列定义为 TIMESTAMP,将发生什么?
每当行被更改时,时间戳字段将获取当前时间戳。
列设置为 AUTO INCREMENT 时,如果在表中达到最大值,会发生什么情况?
它会停止递增,任何进一步的插入都将产生错误,因为密钥已被使用。
怎样才能找出最后一次插入时分配了哪个自动增量?
LAST_INSERT_ID 将返回由 Auto_increment 分配的最后一个值,并且不需要指定表名称
怎么看到为表格定义的所有索引?
索引是通过以下方式为表格定义的:SHOW INDEX FROM <tablename>;
LIKE 声明中的
%
和_
是什么意思?
%
对应于 0 个或更多字符,_
只是 LIKE 语句中的一个字符。
如何在 Unix 和 MySQL 时间戳之间进行转换?
UNIX_TIMESTAMP 是从 MySQL 时间戳转换为 Unix 时间戳的命令
FROM_UNIXTIME 是从 Unix 时间戳转换为 MySQL 时间戳的命令
BLOB 和 TEXT 有什么区别?
BLOB 是一个二进制对象,可以容纳可变数量的数据。TEXT 是一个不区分大小写的 BLOB。
BLOB 和 TEXT 类型之间的唯一区别在于对 BLOB 值进行排序和比较时区分大小写,对 TEXT 值不区分大小写。
MySQL 如何优化 DISTINCT?
distinct 在所有列上转换为group by,并与 order by子句结合使用。
SELECT DISTINCT t1.a FROM t1,t2 where t1.a=t2.a;
NOW()和 CURRENT_DATE()有什么区别?
- now() 命令用于显示当前 年月日时分秒;
- current_date()仅显示当前 年月日
什么是非标准字符串类型?
- TINYTEXT (tinytext:非常小的文本串)
- TEXT (文本)
- MEDIUMTEXT(mediumtext:中等文本串)
- LONGTEXT(大型/长文本类型)
什么是通用 SQL 函数?
- CONCAT(A, B) – 连接两个字符串值以创建单个字符串输出。通常用于将两个或多个字段合并为一个字段。
- FORMAT(X, D)- 格式化数字 X 到 D 有效数字。
- CURRDATE(), CURRTIME()- 返回当前日期或时间。
- NOW() – 将当前日期和时间作为一个值返回。
- MONTH(),DAY(),YEAR(),WEEK(),WEEKDAY() – 从日期值中提取给定数据。
- HOUR(),MINUTE(),SECOND() – 从时间值中提取给定数据。
- DATEDIFF(A,B) – 确定两个日期之间的差异,通常用于计算年龄
- SUBTIMES(A,B) – 确定两次之间的差异。
- FROMDAYS(INT) – 将整数天数转换为日期值。
MySQL 事务
数据库中的事务是什么?
事务(transaction)是作为一个单元的一组有序的数据库操作。如果组中的所有操作都成功,则认为事务成功,即使只有一个操作失败,事务也不成功。如果所有操作完成,事务则提交,其修改将作用于所有其他数据库进程。如果一个操作失败,则事务将回滚,该事务所有操作的影响都将取消。
事务特性(ACID):
-
Atomicity(原子性):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
-
Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
-
Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
-
Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
或者这样理解:
事务就是被绑定在一起作为一个逻辑工作单元的 SQL 语句分组,如果任何一个语句操作失败那么整个操作就被失败,以后操作就会回滚到操作前状态,或者是上有个节点。为了确保要么执行,要么不执行,就可以使用事务。要将有组语句作为事务考虑,就需要通过 ACID 测试,即原子性,一致性,隔离性和持久性。
MySQL 支持事务吗?
在缺省模式下,MySQL 是 autocommit
模式的,所有的数据库更新操作都会即时提交,所以在缺省情况下,MySQL 是不支持事务的。
但是如果你的 MySQL 表类型是使用 InnoDB Tables
或 BDB tables
的话,你的MySQL 就可以使用事务处理,使用 SETAUTOCOMMIT=0
就可以使 MySQL 允许在非 autocommit
模式
在非autocommit
模式下,你必须使用 COMMIT
来提交你的更改,或者用 ROLLBACK
来回滚你的更改。
Myql 中的事务回滚机制概述
事务:是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合(工作逻辑单元)
事务回滚:在同一个事务中,但凡有一个异常了,就所有的操作都回滚到未修改的状态(包括该事务中已经完成的部分都回到未修改状态)
MySQL 里记录货币用什么字段类型好?
NUMERIC (数值型)和 DECIMAL(小数,十进制数) 类型被 MySQL 实现为同样的类型,这在 SQL92 标准允许。他们被用于保存值,该值的准确精度是极其重要的值,例如与金钱有关的数据。当声明一个类是这些类型之一时,精度和规模的能被(并且通常是)指定。
例如:salary DECIMAL(9,2)
在这个例子中,9(precision)代表将被用于存储值的总的小数位数,而 2(scale)代表将被用于存储小数点后的位数。
因此,在这种情况下,能被存储在 salary 列中的值的范围是从-9999999.99 到9999999.99。
【MYSQL】金额(金钱)相关的数据存储类型
-
int
对于游戏币等代币,一般存储为int类型是可行的。
问题在于越界,int类型长度为11位。
在存储人民币相关的金额的时候,则只能存储到9长度的人民币,也就是说,最大只能存储999999999,不到10亿的数值,如果业务增长很快的话,就会给自己留下隐患。 -
Decimal(十进制数)
Decimal为专门为财务相关问题设计的数据类型。
DECIMAL从MySQL 5.1引入,列的声明语法是DECIMAL(M,D)。在MySQL 5.1中,参量的取值范围如下:- M是数字的最大数(精度)。其范围为1~65(在较旧的MySQL版本中,允许的范围是1~254),M 的默认 值是10。
- D是小数点右侧数字的数目(标度)。其范围是0~30,但不得超过M。
说明:float占4个字节,double占8个字节,decimail(M,D)占M+2个字节。
如DECIMAL(5,2) 的最大值为9 9 9 9 . 9 9,因为有7 个字节可用。
能够解决数据的范围和精度的问题。
总结:这两种方式都是可行的解决方案,我们可以根据具体情况使用合适的方案。
sqlyog是工具还是数据库?
MySQL,oracle是数据库,SQLyog是连接MySQL的可视化客户端软件(数据库管理工具,数据库软件)。SQLyog 可以快速直观地让用户完成对数据库的操作
MySQL和Oracle 区别?
区别:
Oracle数据库收费的 MySQL开源的免费
Oracle是大型数据库 Mysql是中小型数据库,
类型的区别
mysql:
- mysql没有number、varchar2()类型;
- mysql可以声明自增长:auto_increment;
- mysql有double,float类型;
oracle:
- oracle没有double类型、有int类型但多数会用number来代替int;
- oracle不可以声明自增长:auto_increment,主键自带自增长;
- oracle小数只有float类型;
sql查询语句的区别
oracle sql语句和mysql sql语句有一定的区别:
一、Oracle语法:
-
oracle 左连接、右连接可以使用
(+)
来实现【这个(+)
可以这样理解:(+)
表示补充,哪个表有(+)
那它就是匹配表】
关于使用(+)的一些注意事项:
1.1.(+)
操作符只能出现在WHERE
子句中,并且不能与OUTER JOIN
语法同时使用。
1.2. 当使用(+)
操作符执行外连接时,如果在WHERE子句中包含有多个条件,则必须在所有条件中都包含(+)
操作符。
1.3.(+)
操作符只适用于列,而不能用在表达式上。
1.4.(+)
操作符不能与OR和IN操作符一起使用。
1.5.(+)
操作符只能用于实现左外连接和右外连接,而不能用于实现完全外连接。 -
左连接(
left outer join
/left join
)
left join(左连接):左表为主表,右表为匹配表
查询语句:select * from A表 a left join B表 b on a.id=b.id;
或:select * from A表 a left outer join B表 b on a.id=b.id;
用(+)来实现:select * from A表 a ,B表 b where a.id=b.id(+);
-
右外连接(
right outer join
/right join
)right join(右连接):右表为主表,左表为匹配表
查询语句:select * from A表 a right join B表 b on a.id=b.id;
或:select * from A表 a right outer join B表 b on a.id=b.id;
用(+)来实现:select * from A表 a ,B表 b where a.id(+)=b.id;
-
全外连接(
full outer join
/full join
)
全外连接又可以称全连接,左表和右表都不做限制,所有的记录都显示,两表不足的地方均为NULL
,全外连接不支持(+)
写法
查询语句:select * from A表 a full join B表 b on a.id=b.id;
或:select * from A表 a full outer join B表 b on a.id=b.id;
补充:select * from A表 a, B表 b where a.id=b.id;
或select * from A表 a join B表 b on a.id=b.id;
二、Mysql只能使用left join 、right join
等关键字.
空字符串问题
Oracle中空字符串''
就是null
(也就是说,只有null,没有空字符),而MySQL是区分null
和''
的。
NULL 是什么意思
NULL 这个值表示 UNKNOWN
(未知):它不表示""
(空字符串)。对 NULL 这个值的任何比较都会生产一个 NULL 值。您不能把任何值与一个 NULL 值进行比较,并在逻辑上希望获得一个答案。使用 IS NULL 来进行 NULL 判断
左连接与右连接以及全连接的区别?
-
左连接:left join 左表主表,右表是匹配表,左表存在数据右表不存在时显示的是左表字段有数据右表null
-
右连接:right join
-
内连接:inner join 显示左右表共有的数据
-
全连接:union
注意:使用union进行拼接查询的时候,表中字段要一致的数才可以进行查询,要不容易出错
union会自动将完全重复的数据去除掉;union all会保留那些重复的数据
MySQL 有关权限的表都有哪几个?
MySQL 服务器通过权限表来控制用户对数据库的访问,权限表存放在 MySQL 数据库里,由 MySQL_install_db
脚本初始化。这些权限表分别 user,db,table_priv,columns_priv 和 host。
列的字符串类型可以是什么?
字符串类型是:SET、BLOB、ENUM、CHAR、TEXT
MySQL 数据库作发布系统的存储,一天五万条以上的增量,预计运维三年,怎么优化?
- 设计良好的数据库结构,允许部分数据冗余,尽量避免 join 查询,提高效率。
- 选择合适的表字段数据类型和存储引擎,适当的添加索引。
- MySQL 库主从读写分离。
- 找规律分表,减少单表中的数据量提高查询速度。
- 添加缓存机制,比如 memcached,apc 等。
- 不经常改动的页面,生成静态页面。
- 书写高效率的 SQL。比如
SELECT * FROM TABEL 改为 SELECT field_1,field_2, field_3 FROM TABLE
MySQL 索引
什么是数据库索引?
数据库索引是数据库系统中一个重要的概念,索引也叫做 key ,是一种用于提升数据库查询效率的数据结构。索引是满足某种特定查找算法的数据结构,而这些数据结构会以某种方式指向数据,从而实现高效查找数据。我们可以把索引理解成一本书的目录,通过目录我们可以快速找到对应章节的内容,同样的,通过数据库索引,我们可以快速找到数据表中对应的记录。
具体来说 MySQL 中的索引,不同的数据引擎实现有所不同,但目前主流的数据库引擎的索引都是 B+ 树实现的,B+ 树的搜索效率,可以到达二分法的性能,找到数据区域之后就找到了完整的数据结构了,所有索引的性能也是更好的。
总而言之,索引就像给数据表建了一个目录一样。
索引的设计原则
- 适合索引的列是出现在where子句中的列,或者连接子句中指定的列,还有排序的字段;
- 基数较小的类,索引效果较差,没有必要在此列建立索引,比如性别;
- 使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间(这种也极少使用,一般都是用搜索引擎替代)
- 不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改表内容的时候,索引会进行更新甚至重构,索引列越多,这个时间就会越长。所以只保持需要的索引有利于查询即可。
为什么在使用索引?
- 使用索引大大减少了存储引擎需要扫描的数据量,如果没有使用索引的话,每查询一行数据都要对数据表进行扫描,这样的话会非常慢。
- 由于索引已经排好序的,所以对数据表进行
ORDER BY
和GROUP BY
等操作时,可以很快得到结果。 - 索引可以将随机的 I/O 转为顺序的 I/O ,避免高昂的磁盘 IO 成本,提升查询效率。
数据库索引的优点和缺点
优点:
-
建立索引能够加快表与表之间的连接
-
创建唯一性索引,保证数据库表中每一行数据的唯一性
-
为用来排序或者分组的字段添加索引能够加快分组和排序顺序
-
能够有效的加快数据的检索速度,缩短数据的检索时间
-
查询的过程中使用优化隐藏器,提高系统的性能
缺点:
-
会导致表的增删改的效率降低(因为索引也要动态的维护)
-
创建索引和维护索引需要时间成本
-
创建索引和维护索引需要空间成本越大 (索引需要占物理空间,除了数据表占用数据空间之外,每一个索引还要占用一定的物理空间)
MySQL索引在哪个模块中实现的?
MySQL 的索引是在存储引擎这一层实现的,因此每一种存储引擎都有不同的实现方式,对同一种索引的处理方式也完成不同。
为什么设置了索引却不起作用?(索引失效的情况)
- 以
%
开头的LIKE
语句,模糊匹配SELECT * FROM users WHERE name LIKE '%小张%'; SELECT * FROM users WHERE name LIKE '%小张'; 不过以 % 为结尾则可以使用索引,如: SELECT * FROM users WHERE name LIKE '张%';
OR
语句前后没有同时使用索引
比如下面的语句, 字段id 有索引,而 字段name 没有创建索引,那么下面的语句只能全表扫描,无法用到索引:
SELECT * FROM users id = 10 or name='test'
- 数据类型出现隐式转化(如
varchar
不加单引号的话可能会自动转换为 int 型)
MySQL索引底层使用什么数据结构?
在 MySQL 中,大部分情况下,索引都是使用 B-Tree 作为底层数据结构, B-Tree 只是一种泛称,实际上不同的存储引擎使用 B-Tree 时,有不同的变种,比如 InnoDB 使用的是 B+Tree 。
另外也有一些特殊的索引结构,比如哈希索引,哈希索引底层则使用的是哈希表,在 MySQL中,只有 Memory 存储引擎支持哈希索引。
什么情况下不要使用索引
既然索引是有代价的,那么就不要在不应该使用索引的情况下去使用它。
-
数据唯一性差的字段不要使用索引
比如性别,只有两种可能数据。意味着索引的二叉树级别少,多是平级。这样的二叉树查找无异于全表扫描。 -
频繁更新的字段不要使用索引
比如logincount登录次数,频繁变化导致索引也频繁变化,增大数据库工作量,降低效率。 -
字段不在where语句出现时不要添加索引
只有在where语句出现,mysql才会去使用索引 -
数据量少的表不要使用索引
使用了改善也不大
另外,如果mysql估计使用全表扫描要比使用索引快,则不会使用索引。
什么是回表?
回表是对Innodb存储引擎而言的,在 InnoDB 存储引擎中,主键索引的叶子节点存储的记录的数据,而普通索引的叶子节点存储的主键索引的地点。
当我们通过主键查询时,只需要搜索主键索引的搜索树,直接可以得到记录的数据。
当我们通过普通索引进行查询时,通过搜索普通索引的搜索树得到主键的地址之后,还要再使用该主键对主键搜索树进行搜索,这个过程称为回表。
聚簇索引与非聚簇索引的区别?
-
聚簇索引:聚簇索引的顺序就是数据的物理存储顺序,并且索引与数据放在一块,通过索引可以直接获取数据,一个数据表中仅有一个聚簇索引。
-
非聚簇索引:索引顺序与数据物理排列顺序无关,索引文件与数据是分开存放。
MySQL主键索引、唯一索引与普通索引的区别?
设置为主键索引的字段不允许为 NULL ,而且一张数据表只能有一个主键索引。
设置为唯一索引的字段,其字段值不允许重要。
普通索引可以包含重复的值,也可以为 NULL
索引可以提高查询性能,那是不是索引创建越多越好?
索引作为一个数据表的目录,本身的存储就需要消耗很多的磁盘和内存存储空间。
并助在写入数据表数据时,每次都需要更新索引,所以索引越多,写入就越慢。
尤其是糟糕的索引,建得越多对数据库的性能影响越大。
MyISAM与InnoDB在处理索引上有什么不同?
MyISAM 存储引擎是非聚族索引,索引与数据是分开存储的,索引文件中记录了数据的指针
而 InnoDB 存储引擎是聚族索引,即索引跟数据是放在一块的, InnoDB 一般将主键与数据放在一块,如果没有主键,则将 unique key 作为主键,如果没有 unique key ,则自动创建一个 rowid 作为主键,其他二级索引叶子指针存储的是主键的位置。
什么是索引的最左前缀原则?
MySQL 数据库不单可以为单个数据列创建索引,也可以为多个数据列创建一个联合索引,比如:
CREATE TABLE test(
a INT NOT NOT,
b INT NOT NOT,
KEY(a,b)
);
当我们使用下面的查询语句时,由于 WHERE 语句中查询的条件就是联合索引,所以可以很快查询到数据。
SELECT * FROM test WHERE a=1 AND b=1;
同样,下面的语句也会利用上面创建的联合索引,这是因为 MySQL 会按照索引创建的顺序进行排序,然后根据查询条件从索引最左边开始检测查询条件是否满足该索引,由于字段 a 在最左边,所以满足索引。
SELECT * FROM test WHERE a=1;
而使用 字段b 进行查询时,则为满足,因为从最左边匹配到的是 字段a ,所以 MySQL 判断为不满足索引条件。
SELECT * FROM test WHERE b=1;
什么是覆盖索引?
如果一个索引中包含查询所要的字段时,此时不需要再回表查询,我们就称该索引为覆盖索引。
比如下面的查询中,字段id是主键索引,所以可以直接返回索引的值,显著提升了查询的性能。
SELECT id FROM users WHERE id BETWEEN 10 AND 20;
可以使用多少列创建索引?
任何标准表最多可以创建 16 个索引列。
索引的底层实现原理和优化
B+树,经过优化的 B+树
主要是在所有的叶子结点中增加了指向下一个叶子节点的指针,因此 InnoDB 建议为大部分表使用默认自增的主键作为主索引。
怎么验证 MySQL 的索引是否满足需求?
使用 explain 查看 SQL 是如何执行查询语句的,从而分析你的索引是否满足需求。
explain 语法:explain select * from table where type=1
。
栈中如何优化 MySQL?
最好是按照以下顺序优化:
- SQL 语句及索引的优化
- 数据库表结构的优化
- 系统配置的优化
- 硬件的优化
优化数据库的方法
- 选取最适用的字段属性,尽可能减少定义字段宽度,尽量把字段设置
NOTNULL
,例如’省份’、’性别’最好适用ENUM
- 使用连接(JOIN)来代替子查询
- 适用联合(UNION)来代替手动创建的临时表
- 事务处理
- 锁定表、优化事务处理
- 适用外键,优化锁定表
- 建立索引
- 优化查询语句
主键、外键和索引的区别?
主键 | 外键 | 索引 | |
---|---|---|---|
定义 | 唯一标识一条记录,不能有重复的,不允许为空 | 表的外键是另一表的主键, 外键可以有重复的, 可以是空值 | 该字段没有重复值,但可以有一个空值 |
作用 | 用来保证数据完整性 | 用来和其他表建立联系用的 | 是提高查询排序的速度 |
个数 | 主键只能有一个 | 一个表可以有多个外键 | 一个表可以有多个唯一索引 |
简单描述 MySQL 中,索引,主键,唯一索引,联合索引的区别,对数据库的性能有什么影响(从读写两方面)
索引是一种特殊的文件(InnoDB 数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。
普通索引(由关键字 KEY 或 INDEX 定义的索引)的唯一任务是加快对数据的访问速度。
普通索引允许被索引的数据列包含重复的值。如果能确定某个数据列将只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该用关键字 UNIQUE
把它定义为一个唯一索引。也就是说,唯一索引可以保证数据记录的唯一性。
主键,是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使用关键字 PRIMARY KEY
来创建。
索引可以覆盖多个数据列,如像 INDEX(columnA, columnB)
索引,这就是联合索引。
索引可以极大的提高数据的查询速度,但是会降低插入、删除、更新表的速度,因为在执行这些写操作时,还要操作索引文件。
SQL 注入漏洞产生的原因?如何防止?
SQL 注入产生的原因:程序开发过程中不注意规范书写 sql 语句和对特殊字符进行过滤,导致客户端可以通过全局变量 POST 和 GET 提交一些 sql 语句正常执行。
防止 SQL 注入的方式:
- 开启配置文件中的
magic_quotes_gpc 和 magic_quotes_runtime
- 设置执行 sql 语句时使用
addslashes
进行 sql 语句转换Sql 语句书写 - 尽量不要省略 双引号和单引号。
- 过滤掉 sql 语句中的一些关键词:
update、insert、delete、select、 *
。 - 提高数据库表和字段的命名技巧,对一些重要的字段根据程序的特点命名,取不易被猜到的。
为表中得字段选择合适得数据类型
字段类型优先级:
整形int>date,
time>enum,
char>varchar>blob,
text 优先考虑数字类型,其次是日期或者二进制类型,最后是字符串类型,同级别的数据类型,应该优先选择占用空间小的数据类型
存储时期
datatime
:以 yyyy-MM-dd HH:mm:ss
格式存储时期时间,精确到秒,占用 8 个字节得存储空间,datatime 类型与时区无关
关于yyyy-MM-dd HH:mm:ss (年-月-日 时:分:秒) 的大小写说明:
MM与mm 大写是为了区分“ 月 ”与“ 分 ”
HH 是为了区分 12小时制 与 24小时制 。小写的h是12小时制,大写的H是24小时制。
-
Timestamp:以时间戳格式存储,占用 4 个字节,范围小 1970-1-1 到 2038-1-19,显示依赖于所指定得时区,默认在第一个列行的数据修改时可以自动得修改
timestamp
列得值 -
Date:(生日)占用得字节数比使用字符串.datatime.int 储存要少,使用 date 只需要 3 个字节,存储日期月份,还可以利用日期时间函数进行日期间得计算
-
Time:存储时间部分得数据
注意:不要使用字符串类型来存储日期时间数据(通常比字符串占用得储存空间小,在进行查找过滤可以利用日期得函数)使用 int 存储日期时间不如使用 timestamp 类型
对于关系型数据库而言,索引是相当重要的概念,请回答有关索引的几个问题:
1、索引的目的是什么?
- 快速访问数据表中的特定信息,提高检索速度
- 创建唯一性索引,保证数据库表中每一行数据的唯一性。
- 加速表和表之间的连接
- 使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间
2、索引对数据库系统的负面影响是什么?
负面影响:创建索引和维护索引需要耗费时间,这个时间随着数据量的增加而增加;索引需要占用物理空间,不光是表需要占用数据空间,每个索引也需要占用物理空间;当对表进行增、删、改、的时候索引也要动态维护,这样就降低了数据的维护速度。
3、为数据表建立索引的原则有哪些?
在最频繁使用的、用以缩小查询范围的字段上建立索引。
在频繁使用的、需要排序的字段上建立索引
4、什么情况下不宜建立索引?
对于查询中很少涉及的列或者重复值比较多的列,不宜建立索引。
对于一些特殊的数据类型,不宜建立索引,比如文本字段(text)等
说一下数据库的事务隔离?
MySQL 的事务隔离是在 MySQL. ini 配置文件里添加的,在文件的最后添加:
transaction-isolation = REPEATABLE-READ
可用的配置值:READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE
。
-
READ-UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读)。
-
READ-COMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读)。
-
REPEATABLE-READ:可重复读,默认级别,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读)。
-
SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。
脏读 :表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录 A,此时该事务还未提交,然后另一个事务尝试读取到了记录 A。
不可重复读 :是指在一个事务内,多次读同一数据。
幻读 :指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或者变少了。
MySQL 问题排查都有哪些手段?
使用 show processlist
命令查看当前所有连接信息。
使用 explain
命令查询 SQL 语句执行计划。
开启慢查询日志,查看慢查询的 SQL。
如何做 MySQL 的性能优化?
为搜索字段创建索引。
避免使用 select *
,列出需要查询的字段。
垂直分割分表。
选择正确的存储引擎。
MySQL数据库和Redis的区别?
MySQL和Redis都可以存放数据,但MySQL里的数据是永久的,而Redis里的数据是缓存并有缓存机制,新的数据过来,老的数据会根据缓存机制失效。
但是从Redis中读取数据比较快方便,而MySQL里的逻辑复杂,数据量大,读取数据耗时长。
视图
什么是视图?为什么要使用视图?
视图是一个虚拟的表,是一个表中的数据经过某种筛选后的显示方式,视图由一个预定义的查询select语句组成。为了提高复杂SQL语句的复用性和表操作的安全性,MySQL数据库管理系统提供了视图特性。
视图有哪些特点?使用场景有哪些?
-
视图特点:
1、视图的列可以来自不同的表,是表的抽象和在逻辑意义上建立的新关系。 2、视图是由基本表(实表)产生的表(虚表)。 3、视图的建立和删除不影响基本表。 4、对视图内容的更新(添加,删除和修改)直接影响基本表。 5、当视图来自多个基本表时,不允许添加和删除数据。
-
视图用途:简化sql查询,提高开发效率,兼容老的表结构。
-
视图的常见使用场景:
1、重用SQL语句;
2、简化复杂的SQL操作。
3、使用表的组成部分而不是整个表;
4、保护数据
5、更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据。
讲一下视图的优缺点?
- 查询简单化。视图能简化用户的操作
- 数据安全性。视图使用者能以多种角度看待同一数据,能够对机密数据提供安全保护
- 逻辑数据独立性。视图对重构数据库提供了一定程度的逻辑独立性
创建视图
创建视图是指在已经存在的 MySQL 数据库表上建立视图。视图可以建立在一张表中,也可以建立在多张表中。
基本语法:可以使用 CREATE VIEW 语句来创建视图。CREATE VIEW <视图名> AS <SELECT语句>
语法说明如下:
- <视图名>:指定视图的名称。该名称在数据库中必须是唯一的,不能与其他表或视图同名。
- <SELECT语句>:指定创建视图的 SELECT 语句,可用于查询多个基础表或源视图。
对于创建视图中的 SELECT 语句的指定存在以下限制:
- 用户除了拥有 CREATE VIEW 权限外,还具有操作中涉及的基础表和其他视图的相关权限。
- SELECT 语句不能引用系统或用户变量。
- SELECT 语句不能包含 FROM 子句中的子查询。
- SELECT 语句不能引用预处理语句参数。
视图定义中引用的表或视图必须存在。但是,创建完视图后,可以删除定义引用的表或视图。可使用check table 语句检查视图定义是否存在这类问题。
视图定义中允许使用 order by语句,但是若从特定视图进行选择,而该视图使用了自己的order by 语句,则视图定义中的 order by将被忽略。
视图定义中不能引用 temporary表(临时表),不能创建 temporary 视图。
with check option的意思是,修改视图时,检查插入的数据是否符合 where 设置的条件。
MySQL数据库CPU飙升怎么解决
- 排查过程:
使用top命令观察,确定是mysqld导致还是其他原因。
如果是mysqld导致的,show processlist
,查看session情况,确定是不是有消耗资源的sql在运行。
找出消耗高的 sql,看看执行计划是否准确, 索引是否缺失,数据量是否太大。 - 处理:
kill掉这些线程(同时观察cpu使用率是否下降),
进行相应的调整(比如说加索引、改sql、改内存参数)
重新跑SQL。 - 其他情况:
也有可能是每个sql消耗资源并不多,但是突然之间,有大量的session 连进来导致cpu飙升,这种情况就需要跟应用一起来分析为何连接数会激增,再做出相应的调整,比如说限制连接数等。
了解什么是表分区吗?表分区的好处有哪些?
表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。
-
存储更多数据。分区表的数据可以分布在不同的物理设备上,从而高效地利用多个硬件设备。和单个磁盘或者文件系统相比,可以存储更多数据。
-
优化查询。在where语句中包含分区条件时,可以只扫描一个或多个分区表来提高查询效率;涉及sum和count语句时,也可以在多个分区上并行处理,最后汇总结果。
-
分区表更容易维护。例如:想批量删除大量数据可以清除整个分区。
-
避免某些特殊的瓶颈,例如InnoDB的单个索引的互斥访问。
Java并发编程(一)
完整性约束包括哪些?
数据完整性(Data Integrity)是指数据的精确(Accuracy)和可靠性(Reliability)。
分为以下四类:
- 实体完整性:规定表的每一行在表中是惟一的实体。
- 域完整性:是指表中的列必须满足某种特定的数据类型约束,其中约束又包括取值范围、精度等规定。
- 参照完整性:是指两个表的主关键字和外关键字的数据应一致,保证了表之间的数据的一致性,防止了数据丢失或无意义的数据在数据库中扩散。
- 用户定义的完整性:不同的关系数据库系统根据其应用环境的不同,往往还需要一些特殊的约束条件。用户定义的完整性即是针对某个特定关系数据库的约束条件,它反映某一具体应用必须满足的语义要求。
与表有关的约束:包括列约束(NOT NULL
(非空约束))和表约束(PRIMARY KEY、foreign key、check、UNIQUE
) 。
什么叫视图?游标是什么?
-
视图是一种虚拟的表,具有和物理表相同的功能。可以对视图进行增,改,查,操作,视图通常是有一个表或者多个表的行或列的子集。对视图的修改不影响基本表。它使得我们获取数据更容易,相比多表查询。
-
游标:是对查询出来的结果集作为一个单元来有效的处理。游标可以定在该单元中的特定行,从结果集的当前行检索一行或多行。可以对结果集当前行做修改。一般不使用游标,但是需要逐条处理数据的时候,游标显得十分重要。
什么是存储过程?用什么来调用?
存储过程是一个预编译的 SQL 语句,优点是允许模块化的设计,就是说只需创建一次,以后在该程序中就可以调用多次。如果某次操作需要执行多次 SQL,使用存储过程比单纯 SQL 语句执行要快。可以用一个命令对象来调用存储过程。
什么是基本表?什么是视图?
基本表是本身独立存在的表,在 SQL 中一个关系就对应一个表。 视图是从
一个或几个基本表导出的表。视图本身不独立存储在数据库中,是一个虚表
试述视图的优点?
(1) 视图能够简化用户的操作
(2) 视图使用户能以多种角度看待同一数据;
(3) 视图为数据库提供了一定程度的逻辑独立性;
(4) 视图能够对机密数据提供安全保护
你可以用什么来确保表格里的字段只接受特定范围里的值?
Check 限制,它在数据库表格里被定义,用来限制输入该列的值。
触发器也可以被用来限制数据库表格里的字段能够接受的值,但是这种办法要求触发器在表格里被定义,这可能会在某些情况下影响到性能。
在 java 中守护线程和本地线程区别?
java 中的线程分为两种:守护线程(Daemon)和用户线程(User)。
任何线程都可以设置为守护线程和用户线程,通过方法 Thread.setDaemon(boolon);true 则把该线程设置为守护线程,反之则为用户线程。Thread.setDaemon() 必须在 Thread.start()之前调用,否则运行时会抛出异常。
两者的区别:
唯一的区别是判断虚拟机(JVM)何时离开,Daemon 是为其他线程提供服务,如果全部的 User Thread 已经撤离,Daemon 没有可服务的线程,JVM 撤离。也可以理解为守护线程是 JVM 自动创建的线程(但不一定),用户线程是程序创建的线程;比如 JVM 的垃圾回收线程是一个守护线程,当所有线程已经撤离,不再产生垃圾,守护线程自然就没事可干了,当垃圾回收线程是 Java 虚拟机上仅剩的线程时,Java 虚拟机会自动离开。
(守护线程为本地线程服务,当所有的本地线程撤离后,JVM离开,此时剩下的线程就是守护线程)
扩展:Thread Dump 打印出来的线程信息,含有 daemon 字样的线程即为守护进程,可能会有:服务守护进程、编译守护进程、windows 下的监听 Ctrl+break的守护进程、Finalizer 守护进程、引用处理守护进程、GC 守护进程。
线程与进程的区别?
进程是操作系统分配资源的最小单元,线程是操作系统调度的最小单元。
一个程序至少有一个进程,一个进程至少有一个线程。
什么是多线程中的上下文切换?
多线程会共同使用一组计算机上的 CPU,而线程数大于给程序分配的 CPU 数量时,为了让各个线程都有执行的机会,就需要轮转使用 CPU。不同的线程切换使用 CPU发生的切换数据等就是上下文切换。
死锁与活锁的区别,死锁与饥饿的区别?
死锁:是指两个或两个以上的进程(或线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
产生死锁的必要条件:
1、互斥条件:所谓互斥就是进程在某一时间内独占资源。
2、请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3、不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
4、循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
活锁:任务或者执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试,失败,尝试,失败。
活锁和死锁的区别在于,处于活锁的实体是在不断的改变状态,所谓的“活”, 而处于死锁的实体表现为等待;活锁有可能自行解开,死锁则不能。
饥饿:一个或者多个线程因为种种原因无法获得所需要的资源,导致一直无法执行的状态。
Java 中导致饥饿的原因:
1、高优先级线程吞噬所有的低优先级线程的 CPU 时间。
2、线程被永久堵塞在一个等待进入同步块的状态,因为其他线程总是能在它之前持续地对该同步块进行访问。
3、线程在等待一个本身也处于永久等待完成的对象(比如调用这个对象的 wait 方法),因为其他线程总是被持续地获得唤醒。
Java 中用到的线程调度算法是什么?
采用时间片轮转的方式。可以设置线程的优先级,会映射到下层的系统上面的优先级上,如非特别需要,尽量不要用,防止线程饥饿。
什么是线程组,为什么在 Java 中不推荐使用?
ThreadGroup 类,可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程,这样的组织结构有点类似于树的形式。为什么不推荐使用?因为使用有很多的安全隐患吧,没有具体追究,如果需要使用,推荐使用线程池。
【线程池就是线程的集合,线程池集中管理线程,以实现线程的重用,降低资源消耗,提高响应速度等】
为什么使用 Executor 框架?
推荐:Executor框架详解
为什么使用 Executor 框架
- 每次执行任务创建线程 new Thread()比较消耗性能,创建一个线程是比较耗时、耗资源的。
- 调用 new Thread()创建的线程缺乏管理,被称为野线程,而且可以无限制的创建,线程之间的相互竞争会导致过多占用系统资源而导致系统瘫痪,还有线程之间的频繁交替也会消耗很多系统资源。
使用 new Thread() 启动的线程不利于扩展,比如定时执行、定期执行、定时
定期执行、线程中断等都不便实现。
在 Java 中 Executor 和 Executors 的区别?
Executors 工具类的不同方法按照我们的需求创建了不同的线程池,来满足业务的需求。
Executor 接口对象能执行我们的线程任务。
ExecutorService 接口继承了 Executor 接口并进行了扩展,提供了更多的方法我们能获得任务执行的状态并且可以获取任务的返回值。
使用 ThreadPoolExecutor 可以创建自定义线程池。
Future 表示异步计算的结果,他提供了检查计算是否完成的方法,以等待计算的完成,并可以使用 get()方法获取计算的结果。
如何在 Windows 和 Linux 上查找哪个线程使用的 CPU 时间最长?
使用 jstack 找出消耗 CPU 最多的线程代码
windows上面用任务管理器看,linux下可以用top 这个工具看。 当然如果你要查找具体的进程,可以用ps命令 ,比如
查找java:(1) ps -ef |grep java (获取项目的pid)
(2)top -H -p pid,顺序不能改变
打印出当前的项目,每条线程占用CPU时间的百分比。注意这里打出的是LWP(十进制),也就是操作系统原生线程的线程号
使用”top -H -p pid”+”jps pid”可以很容易地找到某条占用CPU高的线程的线程堆栈,从而定位占用CPU高的原因,一般是因为不当的代码操作导致了死循环。
注意;”top -H -p pid”打出来的LWP是十进制的,”jps pid”打出来的本地线程号是十六进制的,转换一下,就能定位到占用CPU高的线程的当前线程堆栈了。
Linux上查找线程使用的CPU时间最长
什么是原子操作?在 Java Concurrency API 中有哪些原子类(atomic classes)?
原子操作(atomic operation)意为”不可被中断的一个或一系列操作” 。
处理器使用基于对缓存加锁或总线加锁的方式来实现多处理器之间的原子操作。在 Java 中可以通过锁和循环 CAS 的方式来实现原子操作。 CAS 操作——Compare & Set,或是 Compare & Swap,现在几乎所有的 CPU 指令都支持 CAS的原子操作。
原子操作是指一个不受其他操作影响的操作任务单元。原子操作是在多线程环境下避免数据不一致必须的手段。
int++并不是一个原子操作,所以当一个线程读取它的值并加 1 时,另外一个线程有可能会读到之前的值,这就会引发错误。
为了解决这个问题,必须保证增加操作是原子的,在 JDK1.5 之前我们可以使用同步技术来做到这一点。到 JDK1.5,java.util.concurrent.atomic 包提供了 int 和long 类型的原子包装类,它们可以自动的保证对于他们的操作是原子的并且不需要使用同步。
java.util.concurrent 这个包里面提供了一组原子类。其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由 JVM 从等待队列中选择一个另一个线程进入,这只是一种逻辑上的理解。
原子类:AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference
原子数组:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
原子属性更新器:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,
AtomicReferenceFieldUpdater
解决 ABA 问题的原子类:AtomicMarkableReference(通过引入一个 boolean
来反映中间有没有变过),AtomicStampedReference(通过引入一个 int 来累加来反映中间有没有变过)
Java Concurrency API 中的 Lock 接口(Lock interface)是什么?
Lock 接口比同步方法和同步块提供了更具扩展性的锁操作。
他们允许更灵活的结构,可以具有完全不同的性质,并且可以支持多个相关类的条件对象。
它的优势有:
- 可以使锁更公平
- 可以使线程在等待锁的时候响应中断
- 可以让线程尝试获取锁,并在无法获取锁的时候立即返回或者等待一段时间
- 可以在不同的范围,以不同的顺序获取和释放锁
整体上来说 Lock 是 synchronized (同步的)的扩展版,Lock 提供了无条件的、可轮询的(tryLock 方法)、定时的(tryLock 带参方法)、可中断的(lockInterruptibly)、可多条件队列的(newCondition 方法)锁操作。另外 Lock 的实现类基本都支持非公平锁(默认)和公平锁,synchronized 只支持非公平锁,当然,在大部分情况下,非公平锁是高效的选择。
什么是 Executors 框架?
Executor 框架是一个根据一组执行策略调用,调度,执行和控制的异步任务的框架。
无限制的创建线程会引起应用程序内存溢出。所以创建一个线程池是个更好的的解决方案,因为可以限制线程的数量并且可以回收再利用这些线程。利用Executors 框架可以非常方便的创建一个线程池。
什么是阻塞队列?阻塞队列的实现原理是什么?如何使用阻塞队列来实现生产者-消费者模型?
阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。
这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。
阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。
JDK7 提供了 7 个阻塞队列。分别是:
ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列。
SynchronousQueue:一个不存储元素的阻塞队列。
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
Java 5 之前实现同步存取时,可以使用普通的一个集合,然后在使用线程的协作和线程同步可以实现生产者,消费者模式,主要的技术就是用好,
wait ,notify,notifyAll,sychronized 这些关键字。而在 java 5 之后,可以使用阻
塞队列来实现,此方式大大简少了代码量,使得多线程编程更加容易,安全方面也有保障。
BlockingQueue 接口是 Queue 的子接口,它的主要用途并不是作为容器,而是作为线程同步的的工具,因此他具有一个很明显的特性,当生产者线程试图向BlockingQueue 放入元素时,如果队列已满,则线程被阻塞,当消费者线程试图从中取出一个元素时,如果队列为空,则该线程会被阻塞,正是因为它所具有这个特性,所以在程序中多个线程交替向 BlockingQueue 中放入元素,取出元素,它可以很好的控制线程之间的通信。
阻塞队列使用最经典的场景就是 socket 客户端数据的读取和解析,读取数据的线程不断将数据放入队列,然后解析线程不断从队列取数据解析。
什么是 Callable 和 Future?
Callable 接口类似于 Runnable,从名字就可以看出来了,但是 Runnable 不会返回结果,并且无法抛出返回结果的异常,而 Callable 功能更强大一些,被线程执行后,可以返回值,这个返回值可以被 Future 拿到,也就是说,Future 可以拿到异步执行任务的返回值。可以认为是带有回调的 Runnable。
Future 接口表示异步任务,是还没有完成的任务给出的未来结果。所以说 Callable用于产生结果,Future 用于获取结果。
什么是 FutureTask?使用 ExecutorService 启动任务。
在 Java 并发程序中 FutureTask 表示一个可以取消的异步运算。它有启动和取消运算、查询运算是否完成和取回运算结果等方法。只有当运算完成的时候结果才能取回,如果运算尚未完成 get 方法将会阻塞。一个 FutureTask 对象可以对调用了 Callable 和 Runnable 的对象进行包装,由于 FutureTask 也是调用了 Runnable接口所以它可以提交给 Executor 来执行。
什么是并发容器的实现?
何为同步容器:可以简单地理解为通过 synchronized 来实现同步的容器,如果有多个线程调用同步容器的方法,它们将会串行执行。比如 Vector,Hashtable,以及 Collections.synchronizedSet,synchronizedList 等方法返回的容器。
可以通过查看 Vector,Hashtable 等这些同步容器的实现代码,可以看到这些容器实现线程安全的方式就是将它们的状态封装起来,并在需要同步的方法上加上关键字 synchronized。
并发容器使用了与同步容器完全不同的加锁策略来提供更高的并发性和伸缩性,例如在 ConcurrentHashMap 中采用了一种粒度更细的加锁机制,可以称为分段锁,在这种锁机制下,允许任意数量的读线程并发地访问 map,并且执行读操作的线程和写操作的线程也可以并发的访问 map,同时允许一定数量的写操作线程并发地修改 map,所以它可以在并发环境下实现更高的吞吐量。
多线程同步和互斥有几种实现方法,都是什么?
线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥可以看成是一种特殊的线程同步。
线程间的同步方法大体可分为两类:用户模式和内核模式。顾名思义,内核模式就是指利用系统内核对象的单一性来进行同步,使用时需要切换内核态与用户态,而用户模式就是不需要切换到内核态,只在用户态完成操作。
用户模式下的方法有:原子操作(例如一个单一的全局变量),临界区。内核模式下的方法有:事件,信号量,互斥量。
什么是竞争条件?你怎样发现和解决竞争?
当多个进程都企图对共享数据进行某种处理,而最后的结果又取决于进程运行的顺序时,则我们认为这发生了竞争条件(race condition)。
你将如何使用 thread dump?你将如何分析 Thread dump?
新建状态(New)
用 new 语句创建的线程处于新建状态,此时它和其他 Java 对象一样,仅仅在堆区中被分配了内存。
就绪状态(Runnable)
当一个线程对象创建后,其他线程调用它的 start()方法,该线程就进入就绪状态,Java 虚拟机会为它创建方法调用栈和程序计数器。处于这个状态的线程位于可运行池中,等待获得 CPU 的使用权。
运行状态(Running)
处于这个状态的线程占用 CPU,执行程序代码。只有处于就绪状态的线程才有机会转到运行状态。
阻塞状态(Blocked)
阻塞状态是指线程因为某些原因放弃 CPU,暂时停止运行。当线程处于阻塞状态时,Java 虚拟机不会给线程分配 CPU。直到线程重新进入就绪状态,它才有机会转到运行状态。
阻塞状态可分为以下 3 种:
- 位于对象等待池中的阻塞状态(Blocked in object’s wait pool):
当线程处于运行状态时,如果执行了某个对象的 wait()方法,Java 虚拟机就会把线程放到这个对象的等待池中,这涉及到“线程通信”的内容。
- 位于对象锁池中的阻塞状态(Blocked in object’s lock pool):
当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,Java 虚拟机就会把这个线程放到这个对象的锁池中,这涉及到“线程同步”的内容。
- 其他阻塞状态(Otherwise Blocked):
当前线程执行了 sleep()方法,或者调用了其他线程的 join()方法,或者发出了 I/O请求时,就会进入这个状态
死亡状态(Dead)
当线程退出 run()方法时,就进入死亡状态,该线程结束生命周期。
我们运行之前的那个死锁代码 SimpleDeadLock.java,然后尝试输出信息(
/* 时间,jvm 信息 */
2017-11-01 17:36:28
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed
mode):
/* 线程名称:DestroyJavaVM
编号:#13
优先级:5
系统优先级:0
jvm 内部线程 id:0x0000000001c88800
对应系统线程 id(NativeThread ID):0x1c18
线程状态: waiting on condition [0x0000000000000000] (等待某个条件)
线程详细状态:java.lang.Thread.State: RUNNABLE 及之后所有*/
"DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x0000000001c88800
nid=0x1c18 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Thread-1" #12 prio=5 os_prio=0 tid=0x0000000018d49000
nid=0x17b8 waiting for monitor entry [0x0000000019d7f000]
/* 线程状态:阻塞(在对象同步上)
代码位置:at
com.leo.interview.SimpleDeadLock$B.run(SimpleDeadLock.java:56)
等待锁:0x00000000d629b4d8
已经获得锁:0x00000000d629b4e8*/
java.lang.Thread.State: BLOCKED (on object monitor)
at
com.leo.interview.SimpleDeadLock$B.run(SimpleDeadLock.java:56)
- waiting to lock <0x00000000d629b4d8> (a java.lang.Object)
- locked <0x00000000d629b4e8> (a java.lang.Object)
"Thread-0" #11 prio=5 os_prio=0 tid=0x0000000018d44000 nid=0x1ebc
waiting for monitor entry [0x000000001907f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at
com.leo.interview.SimpleDeadLock$A.run(SimpleDeadLock.java:34)
- waiting to lock <0x00000000d629b4e8> (a java.lang.Object)
- locked <0x00000000d629b4d8> (a java.lang.Object)
"Service Thread" #10 daemon prio=9 os_prio=0
tid=0x0000000018ca5000 nid=0x1264 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread2" #9 daemon prio=9 os_prio=2
tid=0x0000000018c46000 nid=0xb8c waiting on condition
[0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #8 daemon prio=9 os_prio=2
tid=0x0000000018be4800 nid=0x1db4 waiting on condition
[0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #7 daemon prio=9 os_prio=2
tid=0x0000000018be3800 nid=0x810 waiting on condition
[0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0
tid=0x0000000018bcc800 nid=0x1c24 runnable [0x00000000193ce000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at
java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
- locked <0x00000000d632b928> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.<