HashMap的底层实现原理?以jdk7为例说明:
HashMap map = new HashMap();
在实例化以后,底层创建了长度是16的一维数组Entry[] table
。 可能已经执行过多次put
, map.put(key1,value1)
:
key1
所在类的hashCode()
计算key1
哈希值,此哈希值经过某种算法计算以后,得到在Entry
数组中的存放位置。
key1-value1
添加成功。 ----情况1key1
和已经存在的一个或多个数据的哈希值:
key1
的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1
添加成功。----情况2key1
的哈希值和已经存在的某一个数据(key2-value2)
的哈希值相同,继续比较:调用key1
所在类的equals(key2)
方法,比较:
equals()
返回false
:此时key1-value1
添加成功。----情况3equals()
返回true
:使用value1
替换value2
。key1-value1
和原来的数据以链表的方式存储。在不断的添加过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空)时,扩容。默认的扩容方式:扩容为原来容量的2倍,并将原有的数据复制过来。
jdk8
相较于jdk7
在底层实现方面的不同:
new HashMap()
:jdk8
底层没有创建一个长度为16的数组jdk8
底层的数组是:Node[]
,而非Entry[]
put()
方法时,底层创建长度为16的数组jdk8
中底层结构:数组+链表+红黑树。jdk7
:新的元素指向旧的元素。jdk8
:旧的元素指向新的元素)jdk8
中当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且当前数组的长度 > 64时,此时此索引位置上的所数据改为使用红黑树存储。DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16
DEFAULT_LOAD_FACTOR:HashMap的默认加载因子:0.75
threshold:扩容的临界值,=容量*填充因子:16 * 0.75 => 12
TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树:8
MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64
HashMap:作为Map的主要实现类;线程不安全的,效率高;存储null的key和value,扩容的话是原来的二倍
Hashtable:作为古老的实现类;线程安全的,效率低;不能存储null的key和value
扩容的话是原来的二倍+1
Propertie:常用来处理配置文件。key和value都是String类型
HashMap的底层:数组+链表 (jdk7及之前) , 数组+链表+红黑树 (jdk 8)
相同点:
(1) 都是java.util包下的类
(2) 都实现了Map接口,存储方式都是key-value形式
(3) 同时也都实现了Serializable和Cloneable接口
(4) 负载因子都是0.75
负载因子(loadFactor):
当我们第一次创建 HashMap 的时候,就会指定其容量(如果未明确指定,默认是 16),随着我们不断的向 HashMap 中 put 元素的时候,就有可能会超过其容量,那么就需要有一个扩容机制。 所谓扩容,就是扩大 HashMap 的容量,在向 HashMap中添加元素过程中,如果 元素个数(size)超过临界值(threshold)的时候,就会进行自动扩容(resize),并且,在扩容之后,还需要对 HashMap 中原有元素进行rehash,即将原来桶中的元素重新分配到新的桶中。
在 HashMap 中,临界值(threshold) = 负载因子(loadFactor) * 容量(capacity)。 loadFactor 是装载因子(负载因子),表示 HashMap 满的程度,默认值为 0.75f,也就是说默认情况下,当 HashMap 中元素个数达到了容量的 3/4 的时候就会进行自动扩容。
不同点:
(1) HashMap
是非线程安全,效率高;HashTable
是线程安全的,效率低
(2) HashMap
允许null
作为键或值,HashTable
不允许,运行时会报NullPointerException
(3) HashMap
添加元素使用的是自定义hash算法,HashTable
使用的是key
的hashCode
(4) HashMap
在数组+链表的结构中引入了红黑树,HashTable
没有
(5) HashMap
初始容量为16,HashTable
初始容量为11
(6) HashMap
扩容是当前容量翻倍,HashTable
是当前容量翻倍+1
(7) HashMap
只支持Iterator
遍历,HashTable
支持Iterator
和Enumeration
(8) HashMap
与HashTable
的部分方法不同,比如HashTable
有contains
方法。
相同点:两者都可以在java.util包的类
不同点:
Collection接口:单列集合,用来存储一个一个的对象
List接口:存储有序的、可重复的数据。 -->“动态”数组,替换原的数组
Object[ ] elementData
存储,适用于查找频繁。ArrayList
高;底层使用双向链表存储Object[ ] elementData
存储Set接口:存储无序的、不可重复的数据 -->高中讲的“集合”(无序互斥)
Set
接口的主要实现类;线程不安全的;可以存储null值HashSet
的子类;遍历其内部数据时,可以按照添加的顺序遍历LinkedHashSet
效率高于HashSet
。Map:双列数据,存储key-value
对的数据 —类似于高中的函数:y = f(x)
null
的key
和value
扩容的话是原来的二倍map
元素时,可以照添加的顺序实现遍历。HashMap
底层结构基础上,添加了一对指针,指向前一个和后一个元素。HashMap
。key-value
对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序null
的key
和value
扩容的话是原来的二倍+1key
和value
都是String
类型ArrayList和LinkedList的异同
相同点:
不同点
(1)什么是hash冲突?
哈希算法被计算的数据是无限的,而计算后的结果范围有限,所以总会存在不同的数据经过计算后得到的值相同,这就是哈希冲突
(2)HashMap如何解决hash冲突?
String
:不可变的字符序列;底层使用char[ ]
存储StringBuffer
:可变的字符序列;线程安全的,效率低;底层使用char[]
存储StringBuilder
:可变的字符序列;jdk5.0
新增的,线程不安全的,效率高;底层使用char[]
存储(1)不可变性:当你给一个字符串重新赋值之后,老值并没有在内存中销毁,而是重新开辟一块空间存储新值。
(2)String 类中使用 final 关键字修饰字符数组来保存字符串,private final char value[ ],所以String 对象是不可变的。
(3)线程安全
在Lambda表达式中,将其划分了几块。这一行就是
lambda
表达式。
() -> System.out.println(“使用Lambda表达式”);
下面我们对lambda
的格式进行一个介绍:(1)左边括号:
lambda
的形参列表,就好比是我们定义一个接口,里面有一个抽象方法,这个抽象方法的形参列表。(2)箭头:
lambda
的操作符,所以你看见这个箭头心中知道这是一个lambda
表达式就可以了。(3)右边
lambda
体:就好比是我们实现了接口中的抽象方法。
2、接口的默认方法和静态方法
默认方法使得开发者可以在不破坏二进制兼容性的前提下,往现存接口中添加新的方法,即不强制那些实现了该接口的实现类也同时实现这个新添加的方法。
简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。
3、方法引用
方法引用使得开发者可以直接引用现存的方法、Java类的构造方法或者实例对象。方法引用和Lambda表达式配合使用,使得java类的构造方法看起来更加紧凑简洁,减少冗余代码。
方法引用通过方法的名字来指向一个方法
方法引用使用一对冒号 ::
public class Test {
public static void main(String[] args) {
//传统的方式来实现MyFunction/得到一个实现接口的对象 可以使用
//匿名内部类
//MyFunction hf = new MyFunction() {
// @Override
// public String apply(Desk desk) {
// return "hello desk";
// }
//};
//String val = hf.apply(new Desk());
//System.out.println("val-" + val);
MyFunction<Desk,String> hf2 = Desk::getBrand;
String val2 = hf2.apply(new Desk());
System.out.println("val2-" + val2);//这里输出结果就是val2-北京牌
}
}
//定义一个函数式接口: 有且只有一个抽象方法的接口
//我们可以使用@FunctionalInterface 来标识一个函数式接口
//MyFunction是一个函数式接口 (是自定义泛型接口)
@FunctionalInterface
interface MyFunction<T, R> {
R apply(T t); //抽象方法: 表示根据类型T的参数,获取类型R的结果
//public void hi();
//函数式接口,依然可以有多个默认实现方法
default public void ok() {
System.out.println("ok");
}
}
@FunctionalInterface
interface MyInterface {
public void hi();
}
class Desk { //Bean
private String name = "my desk";
private String brand = "北京牌";
private Integer id = 10;
//getter setter tostring 方法
}
4、重复注解
在Java 5中使用注解有一个限制,即相同的注解在同一位置只能声明一次,Java 8引入重复注解,这样相同的注解在同一地方也可以声明多次;Java 8在编译器层做了优化,相同注解会以集合的方式保存,因此底层的原理并没有变化。
5、扩展注解的支持
Java 8扩展了注解的上下文,几乎可以为任何东西添加注解,包括局部变量、泛型类、父类与接口的实现,连方法的异常也能添加注解。
6、Optional类
Optional 类是一个可以为null的容器对象。如果值存在则isPresent()
方法会返回true,调用get()方法会返回该对象。
Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
Java应用中最常见的bug就是空指针异常,Optional 类的引入很好的解决空指针异常,从而避免源码被各种null检查污染,以便开发者写出更加整洁的代码。
7、Stream(流)
什么是 Stream?
Stream API(java.util.stream)是把真正的函数式编程风格引入到Java库中,这是目前为止最大的一次对Java库的完善,以便开发者能够写出高效率、干净、简洁的代码。其实简单来说可以把Stream理解为MapReduce,当然Google的MapReduce的灵感也是来自函数式编程,它其实是一连串支持连续、并行聚集操作的元素,从语法上看,也很像linux的管道、或者链式编程,代码写起来简洁明了!
Stream(流)是一个来自数据源的元素队列并支持聚合操作,Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对
Java 集合运算和表达的高阶抽象。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选,
排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal
operation)得到前面处理的结果
8、日期时间 API
Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理。在旧版的 Java 中,日期时间 API 存在诸多问题,其中有:
非线程安全 java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
设计很差 Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
时区处理麻烦 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。
Java8 在 java.time 包下提供了很多新的 API,新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。以下仅介绍两个比较重要的 API:
9、JavaScript引擎Nashorn
从 JDK 1.8 开始,Nashorn取代Rhino(JDK 1.6, JDK1.7) 成为 Java 的嵌入式 JavaScript 引擎。Nashorn 完全支持 ECMAScript 5.1 规范以及一些扩展,它使用基于 JSR 292 的新语言特性,其中包含在 JDK 7 中引入的 invokedynamic,将 JavaScript 编译成 Java 字节码,与先前的 Rhino 实现相比,这带来了 2 到 10倍的性能提升。
Nashorn的主要用途:允许在JVM上开发运行JavaScript应用,允许Java与JavaScript相互调用。
10、Base64
在Java 8中,Base64编码成为了Java类库的标准。Base64类同时还提供了对URL、MIME友好的编码器与解码器。
除了这十大新特性之外,还有另外的一些新特性:
11、更好的类型推测机制:
Java 8在类型推测方面有了很大的提高,这就使代码更整洁,不需要太多的强制类型转换了。
12、编译器优化:
Java 8将方法的参数名加入了字节码中,这样在运行时通过反射就能获取到参数名,只需要在编译时使用-parameters参数。
13、并行(parallel)数组:
支持对数组进行并行处理,主要是parallelSort()方法,它可以在多核机器上极大提高数组排序的速度。
14、并发(Concurrency):
在新增Stream机制与Lambda的基础之上,加入了一些新方法来支持聚集操作。
15、Nashorn引擎jjs:
基于Nashorn引擎的命令行工具。它接受一些JavaScript源代码为参数,并且执行这些源代码。
16、类依赖分析器jdeps:
可以显示Java类的包级别或类级别的依赖。
17、JVM的PermGen空间被移除:
取代它的是Metaspace(JEP 122)。
两个流同时只能使用一个。 使用了字节流,就不能再使用字符流,反之亦然,否则就会报错
为什么需要序列化与反序列化?
当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。当两个
Java 进程进行通信时,需要 Java 序列化与反序列化实现进程间的对象传送。换句话说,一方面,发送方需要把这个 Java
对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出 Java 对象。
优点:
多线程有两种实现方法,
同步的实现方面有两种
在线程上添加锁。Lock 或者synchronized 可以将线程不安全变为线程安全,
Lock 能完成synchronized 所实现的所有功能;
Collections.synchronizedList();
也能实现线程安全
主要不同点:
使用new
关键字
Class
对象的newInstance
()方法
Class的newInstance()方法可以在运行时创建一个类的新实例。它等效于使用new操作符,但是语法更加动态。
构造函数对象的newInstance
()方法
Constructor的newInstance()方法可以在运行时创建一个类的新实例,并且可以传入构造函数的参数。这种方式比Class的newInstance()方法更加灵活,因为可以选择不同的构造函数。
对象反序列化
反序列化是将对象从字节流中恢复的过程。通过序列化后,可以把对象存储到文件或网络中,然后再通过反序列化的方式恢复成对象。
Object
对象的clone()
方法
clone( )方法可以创建对象的一个副本,并且可以重写clone()方法来实现深克隆。
使用工厂模式
可以将对象的创建和使用解耦。通过定义一个对象工厂,可以更加灵活地产生对象。
1)死锁定义:
死锁是指两个或多个进程在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。
2)产生死锁的必要条件
3)怎么避免死锁
答:Java 中的23 种设计模式:Builder( 建造模式),Factory( 工厂模式),Factory Method(工厂方法模式),Prototype(原始模型模式),Singleton(单例模式),Facade(门面模式),Adapter(适配器模式), Bridge(桥梁模式), Composite(合成模式),Decorator(装饰模式), Flyweight(享元模式), Proxy(代理模式),Command(命令模式), Interpreter(解释器模式), Visitor(访问者模式),Iterator(迭代子模式), Mediator(调停者模式), Memento(备忘录模式),Observer(观察者模式),State(状态模式),Strategy(策略模式),Template Method(模板方法模式), Chain Of Responsibleity(责任链模式)。
工厂模式:
根据工厂模式实现的类可以根据提供的数据生成一组类中某一个类的实例,通常这一组类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作。
首先需要定义一个基类,该类的子类通过不同的方法实现了基类中的方法。然后需要定义一个工厂类,工厂类可以根据条件生成不同的子类实例。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。
如果一段代码可以保证多个线程访问的时候正确操作共享数据,那么它是线程安全的。
当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安全的。
二者都是java多态的体现
(1) 重载:
两同一不同:同一个类里面、相同方法名
参数列表不同:参数个数不同,参数类型不同
(2)重写
子类重写父类的方法。
SSM学习笔记—AOP详解
AOP作用:
AOP(Aspect-Oriented Programming,面向切面编程)能在不改变原来代码的情况下对程序的某些功能进行增强。降低模块间的耦合度,提升代码的可读性和可维护性。在Spring中事务处理、日志管理、权限控制等场景用到了AOP原理。
Spring AOP是基于动态代理的,如果要代理的对象实现了某个接口,那么Spring AOP就会使用JDK动态代理去创建代理对象;而对于没有实现接口的对象,就无法使用JDK动态代理,转而使用CGlib动态代理生成一个被代理对象的子类来作为代理。当然也可以使用AspectJ,Spring AOP中已经集成了AspectJ,AspectJ应该算得上是Java生态系统中最完整的AOP框架了。使用AOP之后我们可以把一些通用功能抽象出来,在需要用到的地方直接使用即可,这样可以大大简化代码量。我们需要增加新功能也方便,提高了系统的扩展性。日志功能、事务管理和权限管理等场景都用到了AOP。
Spring的缺点
SpringBoot的优点
1)在类的上面两个注解:
@RestController 复合注解
@RestController注解= @ResponseBody+@Controller,效果是将方法返回的对象直接在浏览器上展示成json格式。
@RequestMapping
将 HTTP 请求映射到 MVC 和 REST 控制器的处理方法上,提供路由信息,负责URL到Controller中的具体函数的映射。
2)四中REST风格的请求方式
@PostMapping (增加)
将HTTP post请求映射到特定处理程序的方法注解
@DeleteMapping (删除)
将HTTP post请求映射到特定处理程序的方法注解
@PutMapping (修改)
将HTTP post请求映射到特定处理程序的方法注解
@GetMapping (查询)
将HTTP get请求映射到特定处理程序的方法注解
3)几个请求参数注解
1)启动注解 @SpringBootApplication
@SpringBootConfiguration 注解,继承@Configuration注解,主要用于加载配置文件
@EnableAutoConfiguration 注解,开启自动配置功能
@ComponentScan 注解,主要用于组件扫描和自动装配
2)Controller 相关注解
@Controller
@RestController 复合注解
@RequestBody
@RequestMapping
@PostMapping用于将HTTP post请求映射到特定处理程序的方法注解
@DeleteMapping用于将HTTP post请求映射到特定处理程序的方法注解
@PutMapping用于将HTTP post请求映射到特定处理程序的方法注解
@GetMapping用于将HTTP get请求映射到特定处理程序的方法注解
3)取请求参数值
@PathVariable:获取url中的数据
@RequestParam:获取请求参数的值
@RequestHeader 把Request请求header部分的值绑定到方法的参数上
@CookieValue 把Request header中关于cookie的值绑定到方法的参数上
4)注入bean相关
@Service
@Controller
@Component
@Repository
@Scope作用域注解
@Entity实体类注解
@Bean产生一个bean的方法
@Autowired 自动导入
5)导入配置文件
@PropertySource注解
@ImportResource导入xml配置文件
@Import 导入额外的配置信息
6)事务注解
@Transactional
7)全局异常处理
@ControllerAdvice 统一处理异常
@ExceptionHandler 注解声明异常处理方法
exception
SVN
SVN:集中式版本控制器(版本控制器),基于C/S架构并且严重依赖服务器端,它将数据存放在SVN的中央仓库,当服务器端无法使用的时候,版本控制也就无法再使用了。
GIT
Git是目前世界上最先进的分布式版本控制系统(没有之一)。当这个系统的任何一个客户端出现问题的时候,都可以从另外的客户端(即使服务器挂了)获取所有的代码。
SVN与GIT的区别:
Pom、jar、war包
pom:用在父级工程或聚合工程中,用来做jar包的版本控制,必须指明这个聚合工程的打包方式为pom。
聚合工程只是用来帮助其他模块构建的工具,本身并没有实质的内容。具体每个工程代码的编写还是在生成的工程中去写。
对于在父工程中导的依赖工程也可享有。
jar:工程的默认打包方式,打包成jar用作jar包使用。存放一些其他工程都会使用的类,工具类。我们可以在其他工程的pom文件中去引用它
war:打包成war,发布在服务器上,如网站或服务。用户可以通过浏览器直接访问,或者是通过发布服务被别的工程调用
1)级联属性
联合查询:级联属性封装结果集
eg:dept.id
eg:dept.departmentName
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp">
<id column="id" property="id"/>
<result column="gender" property="gender"/>
<result column="did" property="dept.id"/>
<result column="dept_name" property="dept.departmentName"/>
resultMap>
<select id="getEmpAndDept" resultMap="MyDifEmp">
SELECT e.id id,e.last_name last_name,e.gender gender,e.d_id d_id, d.id did,d.dept_name dept_name
FROM tbl_employee e,tbl_dept d
HERE e.d_id=d.id AND e.id=#{id}
select>
2)association
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp2">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="gender" property="gender"/>
<association property="dept" javaType="com.atguigu.mybatis.bean.Department">
<id column="did" property="id"/>
<result column="dept_name" property="departmentName"/>
association>
resultMap>
(1)先按照员工id查询员工信息
(2)根据查询员工信息中的d_id值去部门表查出部门信息
(3)部门设置到员工中;
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpByStep">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
<association property="dept"
select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
column="d_id">
association>
resultMap>
<select id="getEmpByIdStep" resultMap="MyEmpByStep">
select * from tbl_employee where id=#{id}
<if test="_parameter!=null">
and 1=1
if>
select>
反向代理、负载均衡、动静分离
可以共用一个80端口详细配置如下:
做负载均衡、反向代理时使用
#管理端转发
server {
listen 80;
server_name admin-xxxxx.xxx.xxx;
location / {
proxy_pass http://localhost:10003;
}
}
#商家端转发
server {
listen 80;
server_name store-xxxxx.xxx.xxx;
location / {
proxy_pass http://localhost:10002;
}
}
// nginx.conf
# nginx 80端口配置 (监听demo二级域名)
server {
listen 80;
server_name demo.test.com;
location / {
root /home/www/demo;
index index.html index.htm;
}
}
# nginx 80端口配置 (监听product二级域名)
server {
listen 80;
server_name product.test.com;
location / {
root /home/www/product;
index index.html index.htm;
}
}
配置完成后保存,重启nginx服务,访问测试
Redis,英文全称是Remote Dictionary Server(远程字典服务),是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
与MySQL数据库不同的是,Redis的数据是存在内存中的。它的读写速度非常快,每秒可以处理超过10万次读写操作。因此redis被广泛应用于缓存。
另外,Redis也经常用来做分布式锁。
除此之外,Redis支持事务、持久化、LUA 脚本、LRU 驱动事件、多种集群方案
Redis通过MULTI、EXEC、WATCH等一组命令集合,来实现事务机制。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。
简言之,Redis事务就是顺序性、一次性、排他性的执行一个队列中的一系列命令。
Redis执行事务的流程如下:
top
如下输出,找到这个%CPU表示cpu占用率,默认是降序,因此先定位到进程id 也就是PID
找到进程后,我们接着细致的找进程中的哪一个线程占用cpu过高
jps -l | grep 进程pid
这行命令的作用是通过jps -l
打印进程pid
对应的java
程序是哪一个,至于grep只是为了过滤
ps -mp 进程pid -o THREAD,tid,time
printf "%x\n" 上面得到的线程tid
也可以自己通过进制转换得到对应的16机制的tid
jstack
可以打印堆栈信息,因为堆栈信息内容比较多,所以我们需要知道对应的线程id才可以快速的找到问题所在。jstack 进程id | grep 16进制的tid -A60
这行命令就是打印指定进程的堆栈信息,然后通过 grep 对应的tid进行过滤(找到cpu占用最高的线程),-A60是打印前面60行堆栈信息。
这个时候就会发现报错的信息,就好比在写程序中控制台打印出来的异常一样,然后找到对应的类第几行代码就可以了。一般先根据项目包名找,不是自己项目中的包肯定不是你写的代码,暂时认为其它jar包的代码时没有问题的,如果有问题再回来看这些信息
delete | truncate | drop |
---|---|---|
删除表中数据(表结构保留 可回滚rollback) | 删除表,再以原表结构新建表。(如果之前的表有自增auto_increment 那么清空计数器) | 删表 |
DML语言(数据处理语言), 在开启事务时,delete删除的数据可以回滚 | DDL (数据定义语言)删除的数据无法回滚 | DDL (数据定义语言)删除的数据无法回滚 |
1)相同点:
2)不同点:
truncate 和 delete 只删除数据不删除表的结构(定义)
drop 语句将删除表的结构被依赖的约束(constrain)、触发器(trigger)、索引(index);依赖于该表的存储过程/函数将保留,但是变为 invalid 状态。
速度,一般来说: drop> truncate > delete
delete 语句是数据库操作语言(dml),如果开启事务,不会自动提交,能够回滚
truncate、drop 是数据库定义语言(ddl),操作立即生效,不能回滚。
delete 语句不影响表所占用的 extent,高水线(high watermark)保持原位置不动
drop 语句将表所占用的空间全部释放。
truncate 语句缺省情况下见空间释放到 minextents个 extent,除非使用reuse storage;truncate 会将高水线复位(回到最开始)。
安全性:小心使用 drop 和 truncate,尤其没有备份的时候.否则哭都来不及
使用上,想删除部分数据行用 delete,注意带上where子句. 回滚段要足够大.
想删除表,当然用 drop
想保留表而将所有数据删除,如果和事务无关,用truncate即可。如果和事务有关,用delete。
如果是整理表内部的碎片,可以用truncate跟上reuse stroage,再重新导入/插入数据。
对于由 FOREIGN KEY 约束引用的表,不能使用 truncate,而应使用不带 WHERE 子句的 delete语句。
由于 TRUNCATE TABLE 不记录在日志中,所以它不能激活触发器。
TRUNCATE TABLE 不能用于参与了索引视图的表
视图是已经编译好的sql语句。而表不是。
视图没有实际的物理记录。而表有。
表是内容,视图是窗口。
表只用物理空间而视图不占用物理空间,视图只是逻辑概念的存在,表可以及时对它进行修改,但视图只能有创建的语句来修改。
表是内模式,视图是外模式。
视图是查看数据表的一种方法,可以查询数据表中某些字段构成的数据,只是一些SQL语句的集合。从安全的角度说,视图可以不给用户接触数据表,从而不知道表结构。
表属于全局模式中的表,是实表;视图属于局部模式的表,是虚表。
视图的建立和删除只影响视图本身,不影响对应的基本表。
原子性(atomicity)
一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作,这就是事务的原子性
一致性(consistency)
事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态。指数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。例如对银行转帐事务,不管事务成功还是失败,应该保证事务结束后ACCOUNTS表中Tom和Jack的存款总额为2000元。
隔离性(isolation)
事务的隔离性是指在并发环境中,并发的事务时相互隔离的,一个事务的执行不能不被其他事务干扰。不同的事务并发操作相同的数据时,每个事务都有各自完成的数据空间,即一个事务内部的操作及使用的数据对其他并发事务时隔离的,并发执行的各个事务之间不能相互干扰。
持久性(durability)
一旦事务提交,那么它对数据库中的对应数据的状态的变更就会永久保存到数据库中。–即使发生系统崩溃或机器宕机等故障,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束的状态
//因为建立索引树的时候,a是第一个,就好像树干一样。
//没有最左边的字段,即使后面的字段建立了索引,也无法命中。
select * from table where c = "3"; //不会走索引
select * from table where b = 2 and c = "3"; //不会走索引
如果列类型是字符串,那在查询条件中需要将数据用引号引用起来,否则不走索引
索引列上参与计算会导致索引失效
如果mysql估计全表扫描要比使用索引要快,会不适用索引
没有查询条件,或者查询条件没有建立索引
在查询条件上没有使用引导列
查询的数量是大表的大部分,应该是30%以上。
不要定义冗余或重复的索引
不建议用无序的值作为索引;
删除不再使用或者很少使用的索引;
数据量小的表最好不要使用索引;
有大量重复数据的列上不要建立索引;
避免对经常更新的表创建过多的索引;
在 WHERE 中使用不到的字段,不要设置索引;