java中static关键字的作用
在Java中static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,当然也可以修饰代码块。
Java把内存分为栈内存和堆内存,其中栈内存用来存放一些基本类型的变量、数组和对象的引用,堆内存主要存放一些对象。在JVM加载一个类的时候,若该类存在static修饰的成员变量和成员方法,则会为这些成员变量和成员方法在固定的位置开辟一个固定大小的内存区域(只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们),有了这些“固定”的特性,那么JVM就可以非常方便地访问他们。
1、static变量
static修饰的变量我们称之为静态变量,没有用static修饰的变量称之为实例变量,他们两者的区别是:静态变量是随着类加载时被完成初始化的,它在内存中仅有一个,且JVM也只会为它分配一次内存,同时类所有的实例都共享静态变量,可以直接通过类名来访问它。但是实例变量则不同,它是伴随着实例的,每创建一个实例就会产生一个实例变量,它与该实例同生共死。所以我们一般在这两种情况下使用静态变量:对象之间共享数据、访问方便。
2、static方法
static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。但是要注意的是,虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法/变量的。因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。
Java中的内存分配:
Java程序在运行时,需要在内存中的分配空间。为了提高运算效率,就对数据进行了不同空间的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
具体划分为如下5个内存空间:(非常重要)
栈:存放局部变量
堆:存放所有new出来的东西
方法区:被虚拟机加载的类信息、常量、静态常量等。
程序计数器(和系统相关)
本地方法栈
Java反射机制的作用:
1)在运行时判断任意一个对象所属的类。
2)在运行时判断任意一个类所具有的成员变量和方法。
3)在运行时任意调用一个对象的方法
4)在运行时构造任意一个类的对象
什么是反射机制?
简单说,反射机制值得是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。
java反射机制提供了什么功能?
在运行时能够判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用任一对象的方法
在运行时创建新类对象
哪里用到反射机制?
jdbc中有一行代码:Class.forName('com.mysql.jdbc.Driver.class').newInstance();
spring的理解
是一个开源框架让java开发模块化,并且全面。贯穿逻辑层,表现层,持久层。让每一个功能模块都可以独立分开,降低耦合,提高代码复用率!spring通过控制反转降低耦合性,一个对象的依赖通过被动注入的方式而非主动new还包括面向切面, mvc的整合等等,以上仅仅是个人对Spring的浅显认识。
spring IOC 和AOP
IOC:控制反转也叫依赖注入,IOC利用java反射机制,AOP利用代理模式。所谓控制反转是指,本来被调用者的实例是有调用者来创建的,这样的缺点是耦合性太强,IOC则是统一交给spring来管理创建,将对象交给容器管理,你只需要在spring配置文件总配置相应的bean,以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象。在spring容器启动的时候,spring会把你在配置文件中配置的bean都初始化好,然后在你需要调用的时候,就把它已经初始化好的那些bean分配给你需要调用这些bean的类。
AOP:面向切面编程。(Aspect-Oriented Programming)
AOP可以说是对OOP的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码,属于静态代理
spring中的bean对象生命周期有多长
如果在配置文件中声明一个bean对象,这个web程序一直运行,那这个bean对象会不会一直存在
默认的bean是单例的,也就是说只有spring 容器关闭的时候才会销毁这些bean对象,如果声明的bean对象是prototype类型的话,就非单例了, 那么这些对象将不由spring容器维护,该对象没有引用的时候jvm会适时垃圾回收
spring aop的底层原理
spring两种代理方式
若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
优点:因为有接口,所以使系统更加松耦合
缺点:为每一个目标类创建接口
若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。
缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。
JDK动态代理
1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
2.创建被代理的类以及接口
3.通过Proxy的静态方法
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
4.通过代理调用方法
JDK的动态代理是靠多态和反射来实现的,它生成的代理类需要实现你传入的接口,并通过反射来得到接口的方法对象
CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
1、生成代理类Class的二进制字节码;
2、通过Class.forName加载二进制字节码,生成Class对象;
3、通过反射机制获取实例构造,并初始化代理类对象。
spring ioc相关
原理是反射+工厂模式
springmvc重要的类
https://blog.csdn.net/scholar_man/article/details/48052407
spring的bean的作用域
Spring 3中为Bean定义了5中作用域,分别为singleton(单例)、prototype(原型)、request、session和global session,5种作用域说明如下:
1.singleton:单例模式,Spring IoC容器中只会存在一个共享的Bean实例,无论有多少个Bean引用它,始终指向同一对象。Singleton作用域是Spring中的缺省作用域,也可以显示的将Bean定义为singleton模式,配置为:
<bean id="userDao" class="com.ioc.UserDaoImpl" scope="singleton"/>
2.prototype:原型模式,每次通过Spring容器获取prototype定义的bean时,容器都将创建一个新的Bean实例,每个Bean实例都有自己的属性和状态,而singleton全局只有一个对象。根据经验,对有状态的bean使用prototype作用域,而对无状态的bean使用singleton作用域。
3.request:在一次Http请求中,容器会返回该Bean的同一实例。而对不同的Http请求则会产生新的Bean,而且该bean仅在当前Http Request内有效。
<bean id="loginAction" class="com.cnblogs.Login" scope="request"/>,针对每一次Http请求,Spring容器根据该bean的定义创建一个全新的实例,且该实例仅在当前Http请求内有效,而其它请求无法看到当前请求中状态的变化,当当前Http请求结束,该bean实例也将会被销毁。
4.session:在一次Http Session中,容器会返回该Bean的同一实例。而对不同的Session请求则会创建新的实例,该bean实例仅在当前Session内有效。
<bean id="userPreference" class="com.ioc.UserPreference" scope="session"/>,同Http请求相同,每一次session请求创建新的实例,而不同的实例之间不共享属性,且实例仅在自己的session请求内有效,请求结束,则实例将被销毁。
5.global Session:在一个全局的Http Session中,容器会返回该Bean的同一个实例,仅在使用portlet context时有效。
autowired 和 resource注解的区别
https://www.cnblogs.com/think-in-java/p/5474740.html
spring mvc
https://www.cnblogs.com/wdpnodecodes/p/7401325.html
spring 相关问题
https://www.cnblogs.com/liangyihui/p/5917773.html
redis 的数据类型
五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)
mvn的指令的区别
mvn -version 查看maven的版本及配置信息
mvn archetype:create -DgroupId= DartifactId= 构建java项目
mvn archetype:create -DgroupId= DartifactId= -DarchetypeArtifactId=maven-archetype-webapp 创建web项目
mvn compile 编译项目代码
mvn package 打包项目
mvn package -Dmaven.test.skip=true 打包项目时跳过单元测试
mvn test 运行单元测试
mvn clean 清除编译产生的target文件夹内容,可以配合相应命令一起使用,如mvn clean package, mvn clean test
mvn install 打包后将其安装在本地仓库
mvn deploy 打包后将其安装到pom文件中配置的远程仓库
mvn eclipse:eclipse 将maven生成eclipse项目结构
mvn eclipse:clean 清除maven项目中eclipse的项目结构
mvn site 生成站点目录
mvn dependency:list 显示所有已经解析的所有依赖
mvn dependency:tree 以树的结构展示项目中的依赖
mvn dependency:analyze 对项目中的依赖进行分析,依赖未使用,使用单未引入
mvn tomcat:run 启动tomcat
java的内部匿名类
????
stringbuffer和stringbuilder的实现原理
StringBuilder继承自AbstractStringBuilder,与String类似,StringBuilder类也封装了一个字符数组,定义如下:
char[] value;
与String不同,它不是final的,可以修改。
它的默认构造方法是:
public StringBuilder() {
super(16);
}
new StringBuilder()这句代码,内部会创建一个长度为16的字符数组,count的默认值为0
append会直接拷贝字符到内部的字符数组中,如果字符数组长度不够,会进行扩展,实际使用的长度用count体现。
扩展的逻辑是,分配一个足够长度的新数组,然后将原内容拷贝到这个新数组中,最后让内部的字符数组指向这个新数组
StringBuilder的大部分方法中都会调用父类方法或属性, 足以见得该父类对其的影响还是很大的,所以我们将从头至尾简单介绍下它的父类AbstractStringBuilder。该类中只有两个属性
value属性表示的是一个字符数组,该数组的作用和String中的字符数组的作用是一样的,只是此value数组并没有被final修饰,也就是说该数组内部的值是可以动态修改的,这也是StringBuilder存在的意义。count属性表示的不是value数组的长度,它代表的是value数组中实际上存放的字符数目,例如:value长度为10,我存放8个字符,剩下位置为空,此时count的值就为8,而value.length()为10。
对于一个StringBuilder对象,我们可以不断的追加字符串到其中,这样就会遇到value数组长度不够的时候,该方法就是用于处理这种情况,在我们实际操作value数组之前,大多会调用该方法判断此次操作之后是否会导致数组溢出,如果是则会将原数组长度扩大两倍加上2并拷贝原数组中的内容到新数组中,然后才实际操作value数组。(此时的value数组已经被扩容了)。
分布式和集群
分布式:一个业务分拆多个子业务,部署在不同的服务器上,(我的补充:)具有处理高并发的能力,但一个子业务系统宕机,该子业务功能将无法实现。
集群:同一个业务,部署在多个服务器上,(我的补充:)具有高可用的能力,一个系统宕机,不影响业务实现。
分布式事物
RocketMQ第一阶段发送Prepared消息时,会拿到消息的地址,第二阶段执行本地事物,第三阶段通过第一阶段拿到的地址去访问消息,并修改状态。细心的读者可能又发现问题了,如果确认消息发送失败了怎么办?
RocketMQ会定期扫描消息集群中的事物消息,这时候发现了Prepared消息,它会向消息发送者确认,Bob的钱到底是减了还是没减呢?如果减了是回滚还是继续发送确认消息呢?RocketMQ会根据发送端设置的策略来决定是回滚还是继续发送确认消息。这样就保证了消息发送与本地事务同时成功或同时失败。如下图:
为了能解决该问题,同时又不和业务耦合,RocketMQ提出了“事务消息”的概念。
具体来说,就是把消息的发送分成了2个阶段:Prepare阶段和确认阶段。
具体来说,上面的2个步骤,被分解成3个步骤:
(1) 发送Prepared消息
(2) update DB
(3) 根据update DB结果成功或失败,Confirm或者取消Prepared消息。
可能有人会问了,前2步执行成功了,最后1步失败了怎么办?这里就涉及到了RocketMQ的关键点:RocketMQ会定期(默认是1分钟)扫描所有的Prepared消息,询问发送方,到底是要确认这条消息发出去?还是取消此条消息
分布式事务(Distributed Transaction DT )
分布式事务顾名思义就是在分布式环境下运行的事务,对于分布式事务来说,事务的每个操作步骤是运行在不同机器上的服务的。分布式事务处理的关键是必须有一种方法可以知道事务在任何地方所做的所有动作,提交或回滚事务的决定必须产生统一的结果(全部提交或全部回滚)
在现如今的大型互联网平台中,基本上都是采用分布式的SOA架构,所以分布式事务是非常常见的。比如一个电商平台的下单场景,一般对于用户下单会有两个步骤,一是订单业务采取下订单操作,二是库存业务采取减库存操作,但在大型电子商务平台上这两个业务一般会运行在不同的机器上,这就是一个典型的分布式事务场景。还有一个常见的场景就是支付宝向余额宝转账,而支付宝和余额宝不是一个系统,怎么保证这两个系统之间的一致性就是分布式事务所关注的问题。
在分布式系统里面有一个CAP定律,这个定理的内容是指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼
一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
分区容错性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
解决分布式事务问题还有一种方案,也是现在大型互联网平台普遍采用的方案,就是利用消息中间件
分布式session -- 基于redis的session共享
将Session数据集中存储,然后不同Web服务器从同样的地方获取Session,如下图:
Synchronized(对象锁)和Static Synchronized(类锁)的区别
https://blog.csdn.net/cs408/article/details/48930803
synchronized修饰
1.Synchronized修饰非静态方法,实际上是对调用该方法的对象加锁,俗称“对象锁”
情况1:同一个对象在两个线程中分别访问该对象的两个同步方法
结果:会产生互斥。
解释:因为锁针对的是对象,当对象调用一个synchronized方法时,其他同步方法需要等待其执行结束并释放锁后才能执行。
情况2:不同对象在两个线程中调用同一个同步方法
结果:不会产生互斥。
解释:因为是两个对象,锁针对的是对象,并不是方法,所以可以并发执行,不会互斥。形象的来说就是因为我们每个线程在调用方法的时候都是new 一个对象,那么就会出现两个空间,两把钥匙
2.Synchronized修饰静态方法,实际上是对该类对象加锁,俗称“类锁”。
情况1:用类直接在两个线程中调用两个不同的同步方法
结果:会产生互斥。
解释:因为对静态对象加锁实际上对类(.class)加锁,类对象只有一个,可以理解为任何时候都只有一个空间,里面有N个房间,一把锁,因此房间(同步方法)之间一定是互斥的。
注:上述情况和用单例模式声明一个对象来调用非静态方法的情况是一样的,因为永远就只有这一个对象。所以访问同步方法之间一定是互斥的。
情况2:用一个类的静态对象在两个线程中调用静态方法或非静态方法
结果:会产生互斥。
解释:因为是一个对象调用,同上。
情况3:一个对象在两个线程中分别调用一个静态同步方法和一个非静态同步方法
结果:不会产生互斥。
解释:因为虽然是一个对象调用,但是两个方法的锁类型不同,调用的静态方法实际上是类对象在调用,即这两个方法产生的并不是同一个对象锁,因此不会互斥,会并发执行。
volatile关键字、可见性具体的理解
volatile不具备原子性,使用条件:
对变量的写操作不依赖于当前值
该变量没有包含在具有其他变量的不变式子中
适合作为状态标记量
当多个线程进行操作共享数据时,可以保证内存中的数据可见。底层原理:内存栅栏。使用volatile关键字修饰时,可理解为对数据的操作都在主存中进行。
设计模式的理解和应用
volatile关键字为什么不是线程安全的
这一些操作并不是原子性,也就是 在read load之后,如果主内存count变量发生修改之后,线程工作内存中的值由于已经加载,不会产生对应的变化,所以计算出来的结果会和预期不一样
对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的
例如假如线程1,线程2 在进行read,load 操作中,发现主内存中count的值都是5,那么都会加载这个最新的值
在线程1堆count进行修改之后,会write到主内存中,主内存中的count变量就会变为6
线程2由于已经进行read,load操作,在进行运算之后,也会更新主内存count的变量值为6
AQS相关
它维护了一个volatile int state(代表共享资源)和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)。这里volatile是核心关键词
AQS定义两种资源共享方式:Exclusive(独占,只有一个线程能执行,如ReentrantLock)和Share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)
https://www.cnblogs.com/daydaynobug/p/6752837.html
jdk1.8的新特性
https://www.cnblogs.com/snowInPluto/p/5981400.html
lambda表达式的实现原理
jvm 内存模型 JMM
描述多线程环境中线程与内存的关系
https://blog.csdn.net/suifeng3051/article/details/52611310
https://blog.csdn.net/zjf280441589/article/details/53437703
GC用的引用可达性分析算法中,哪些对象可作为GC Roots对象(https://blog.csdn.net/ma345787383/article/details/77099522)
先说一下可达性分析算法的思想:从一个被称为GC Roots的对象开始向下搜索,如果一个对象到GC Roots没有任何引用链相连时,则说明此对象不可用。
在java中可以作为GC Roots的对象有以下几种:
虚拟机栈中引用的对象、方法区类静态属性引用的对象、方法区常量池引用的对象、本地方法栈JNI引用的对象
虽然这些算法可以判定一个对象是否能被回收,但是当满足上述条件时,一个对象 不一定会被回收。当一个对象不可达GC Roots时,这个对象并不会马上被回收,而是处于一个死缓的阶段,若要被真正的回收需要经历两次标记。如果对象在可达性分析中没有与GC Roots的引用链,那么此时就会被第一次标记并且进行一次筛选,筛选的条件是是否有必要执行finalize()方法。当对象没有覆盖finalize()方法或者已经被虚拟机调用过,那么就认为是没必要的。
如果该对象有必要执行finalize()方法,那么这个对象将会放在一个称为F-Queue的队列中,虚拟机会触发一个finalize()线程去执行,此线程是低优先级的,并且虚拟机不会承诺一直等待它运行完,这还是因为如果finalize()执行缓慢或者发生了死锁,那么就会造成F-Queue队列一直等待,造成了内存回收系统的崩溃。GC对处于F-Queue中的对象进行第二次被标记,这时,该对象将被移除“即将回收”集合,等待回收。
TCP与UDP区别总结:
https://blog.csdn.net/u013777351/article/details/49226101
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。
3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
4.每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP对系统资源要求较多,UDP对系统资源要求较少。
网络方面、简要表述http协议、抓包什么的
https://blog.csdn.net/done58/article/details/50996680
https://www.cnblogs.com/ranyonsue/p/5984001.html
https://www.cnblogs.com/qdhxhz/p/8468913.html
死锁发生的原因:
1、系统资源有限
2、进程或线程推进顺序不恰当
3、资源分配不当
死锁发生的四个条件:
1、互斥条件:一份资源每次只能被一个进程或线程使用(在Java中一般体现为,一个对象锁只能被一个线程持有)
2、请求与保持条件:一个进程或线程在等待请求资源被释放时,不释放已占有资源
3、不可剥夺条件:一个进程或线程已经获得的资源不能被其他进程或线程强行剥夺
4、循环等待条件:形成一种循环等待的场景
死锁代码示例:
void transfer(Account from,Account to,int amount){
synchronized(from){
synchronized(to){
from.setAmount(from.getAmount()-amount);
to.setAmount(to.getAmount()+amount)
}
}
}
//transfer(a,b,100)和transfer(b,a,100)同时进行
解决思路:
1.一次性获取全部锁
2.按一定顺序获得锁
3.加入超时判定
ReentrantLock提供了tryLock()、tryLock(long timeout, TimeUnit unit)、lock.lockInterruptibly()
tryLock() 方法试图申请一个锁,在成功获得锁后返回true,否则,立即返回false,而且线程可以立即离开去做其他的事情。
tryLock(long timeout, TimeUnit unit) 是一个具有超时参数的尝试申请锁的方法,阻塞时间不会超过给定的值;如果成功则返回true
lockInterruptibly() 获得锁,但是会不确定地发生阻塞。如果线程被中断,抛出一个InterruptedException异常。
死锁的解决方案:
尽可能不死锁
碰撞检测
等锁超时
数据库索引方面的问题
索引分单列索引和组合索引。单列索引,即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引。组合索引,即一个索引包含多个列。索引可以大大提高MySQL的检索速度。索引也会有它的缺点:虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。
索引种类
普通索引:仅加速查询
唯一索引:加速查询 + 列值唯一(可以有null)
主键索引:加速查询 + 列值唯一(不可以有null)+ 表中只有一个
组合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并
全文索引:对文本的内容进行分词,进行搜索
innodb存储引擎索引概述:
innodb存储引擎支持两种常见的索引:B+树索引和哈希索引。
数据库中B+树索引分为聚集索引(clustered index)和非聚集索引(secondary index).这两种索引的共同点是内部都是B+树,高度都是平衡的,叶节点存放着所有数据。不同点是叶节点是否存放着一整行数据。
(1) 聚集索引
Innodb存储引擎表是索引组织表,即表中数据按主键顺序存放。而聚集索引就是按每张表的主键构造一颗B+树。并且叶节点存放整张表的行记录数据。每张表只能有一个聚集索引(一个主键)。
聚集索引的另一个好处是它对于主键的排序查找和范围的速度非常快。叶节点的数据就是我们要找的数据。
(2) 非聚集索引
非聚集索引。叶级别不包含行的全部数据,叶级别除了包含行的键值以外,每个索引行还包含了一个书签(bookmark),该书签告诉innodb存储引擎,哪里可以找到与索引对应的数据。
非聚集索引的存在并不影响数据再聚集索引中的组织,因此一个表可以有多个辅助索引。当通过辅助索引查找数据时,innodb会遍历非聚集索引并通过叶级别的指针获得指向主键索引的主键。然后再通过主键索引找到一行完整的数据。
数据库数据库中的五大约束包括:
1.主键约束(Primay Key Coustraint) 唯一性,非空性;
2.唯一约束 (Unique Counstraint)唯一性,可以空,但只能有一个;
3.默认约束 (Default Counstraint) 该数据的默认值;
4.外键约束 (Foreign Key Counstraint) 需要建立两表间的关系;
5.非空约束(Not Null Counstraint):设置非空约束,该字段不能为空。
数据库中的范式:
第一范式(1NF):
数据表中的每一列(字段),必须是不可拆分的最小单元,也就是确保每一列的原子性。
例如: userInfo: '山东省烟台市 1318162008' 依照第一范式必须拆分成
userInfo: '山东省烟台市' userTel: '1318162008'两个字段
第二范式(2NF):
满足1NF后要求表中的所有列,都必需依赖于主键,而不能有 任何一列与主键没有关系(一个表只描述一件事情)。
例如:订单表只能描述订单相关的信息,所以所有的字段都必须与订单ID相关。产品表只能描述产品相关的信息,所以所有的字段都必须与产品ID相关。因此在同一张表中不能同时出现订单信息与产品信息。
第三范式(3NF):
第三范式(3NF):满足2NF后,要求:表中的每一列都要与主键直接相关,而不是间接相关(表中的每一列只能依赖于主键)
例如:订单表中需要有客户相关信息,在分离出客户表之后,订单表中只需要有一个用户ID即可,而不能有其他的客户信息,因为其他的用户信息是直接关联于用户ID,而不是关联于订单ID。
SQL相关
https://blog.csdn.net/u011464124/article/details/54618616
https://blog.csdn.net/m13666368773/article/details/7612113
mysql 2种引擎的区别
区别:1. InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务; 2. InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败; 3. InnoDB是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。而MyISAM是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。 4. InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快; 5. Innodb不支持全文索引,而MyISAM支持全文索引,查询效率上MyISAM要高; 如何选择:1. 是否要支持事务,如果要请选择innodb,如果不需要可以考虑MyISAM;2. 如果表中绝大多数都只是读查询,可以考虑MyISAM,如果既有读写也挺频繁,请使用InnoDB。3. 系统奔溃后,MyISAM恢复起来更困难,能否接受; 4. MySQL5.5版本开始Innodb已经成为Mysql的默认引擎(之前是MyISAM),说明其优势是有目共睹的,如果你不知道用什么,那就用InnoDB,至少不会差。
如何定位慢sql
服务端加慢sql日志
数据库调优我个人觉得必须要明白两件事
1.定位问题(你得知道问题出在哪里,要不然从哪里调优呢)
2.解决问题(这个没有基本的方法来处理,因为不同的问题处理的方式方法不一样
得从实践中不断的探索,如sql调优,配置优化,硬件升级等等)
如何分析慢sql
explain
如何解决慢sql
加索引,in优化、分页优化、分库分表等等。。。