什么是数据库事务:访问并可能改变数据库中个数据项的一个程序执行单元。
实现方式共有两种:编码方式即采用注解的方式(类头的@Transactional为默认事务配置);声明式事务管理方式(bean)。
基于AOP技术实现的声明式事务管理,实质就是:在方法执行前后进行拦截,然后在目标方法开始之前创建并加入事务,执行完目标方法后根据执行情况提交或回滚事务。
声明式事务管理又有两种方式:基于XML配置文件的方式;另一个是在业务方法上进行@Transactional注解,将事务规则应用到业务逻辑中。
1、自旋锁:自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时 才能进入临界区。
2、自旋锁的其他种类
3、阻塞锁:常用的有五个状态的锁都是阻塞所。
4、可重入锁:ReentrantLock
5、读写锁:写锁是排他锁,读锁是共享锁。
6、互斥锁
7、悲观锁:在整个数据处理过程中,将数据处于锁定状态。 悲观锁的实现,往往依靠数据库提供的锁机制。
8、乐观锁:乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。
公平锁(Fair):加锁前检查是否有排队等待的线程,优先排队等待的线程,先来先得
非公平锁(Nonfair):加锁时不考虑排队等待问题,直接尝试获取锁,获取不到自动到队尾等待
18、信号量
mysql不支持Full join。
select * from A inner join B on A.name = B.name;
在ON匹配阶段 WHERE 子句的条件都不会被使用。仅在匹配阶段完成以后,WHERE 子句条件才会被使用。它将从匹配阶段产生的数据中检索过滤。
cross join:交叉连接,得到的结果是两个表的乘积,即笛卡尔积。
还有inner join,left join,right join。
在JSP中无需创建就可以使用的9个对象,它们是:request、response、session、application、out、pagecontext、config、page、exception
l out(JspWriter):等同与response.getWriter(),用来向客户端发送文本数据;
1. void clear() ;
清除输出缓冲区的内容,但是不输出到客户端。
2. void clearBuffer() ;
清除输出缓冲区的内容,并输出到客户端。
3. void close() ;
关闭输出流,清除所有内容。
4. void flush() ;
输出缓冲区里面的数据。
5. int getBufferSize() ;
获取以kb为单位的目前缓冲区大小。
6. int getRemaining() ;
获取以kb为单位的缓冲区中未被占用的空间大小。
7. boolean isAutoFlush() ;
是否自动刷新缓冲区。
8. void newLine() ;
输出一个换行字符。
l config(ServletConfig):对应“真身”中的ServletConfig,config对象用来存放Servlet初始的数据结构;config 对象的主要作用是取得服务器的配置信息。通过 pageConext对象的 getServletConfig() 方法可以获取一个config对象。当一个Servlet 初始化时,容器把某些信息通过 config对象传递给这个 Servlet。
l page(当前JSP的真身类型):当前JSP页面的“this”,即当前对象,page对象代表JSP对象本身,或者说代表编译后的servlet对象,可以用( (javax.servlet.jsp.HttpJspPage)page )来取用它的方法和属性;
l pageContext(PageContext):页面上下文对象,它是最后一个没讲的域对象,pageContext对象存储本JSP页面相关信息,如属性、内建对象等;pageContext 对象的作用是取得任何范围的参数,通过它可以获取 JSP页面的out、request、reponse、session、application 等对象。
l exception(Throwable):只有在错误页面中可以使用这个对象,错误对象,只有在JSP页面的page指令中指定isErrorPage="true"后,才可以在本页面使用exception对象;
l request(HttpServletRequest):即HttpServletRequest类的对象,request对象包含所有请求的信息,如请求的来源、标头、cookies和请求相关的参数值等,request对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。request对 象的作用域为一次请求。;
getParameterNames() 获取客户端提交的所有参数的名字。
l response(HttpServletResponse):即HttpServletResponse类的对象,response对象主要将JSP容器处理后的结果传回到客户端,response 代表的是对客户端的响应,主要是将JSP容器处理过的对象传回到客户端。response对象也具有作用域,它只在JSP页面内有效;
response.sendRedirect(index.jsp)
l application(ServletContext):即ServletContext类的对象,主要功用在于取得或更改Servlet的设定;
setAttribute(String key,Object obj):将参数Object指定的对象obj添加到Application对象中,并为添加的对象指定一个索引关键字。
getAttribute(String key):获取Application对象中含有关键字的对象。
l session(HttpSession):即HttpSession类的对象,不是每个JSP页面中都可以使用,如果在某个JSP页面中设置<%@page session=”false”%>,说明这个页面不能使用session,session对象表示目前个别用户的会话状态,用来识别每个用户。
public String getId():获取Session对象编号。
public void setAttribute(String key,Object obj):将参数Object指定的对象obj添加到Session对象中,并为添加的对象指定一个索引关键字。
public Object getAttribute(String key):获取Session对象中含有关键字的对象。
public Boolean isNew():判断是否是一个新的客户。
1.ArrayList是实现了基于动态数组的数据结构,ArrayList不具有线程安全性,LinkedList基于链表的数据结构,LinkedList可以看做为一个双向链表,LinkedList也是线程不安全的。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
Vector是线程安全的
下面列出了Array和ArrayList的不同点:
Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。
Array大小是固定的,ArrayList的大小是动态变化的。
ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。
对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。
ArrayList和LinkedList都实现了List接口,他们有以下的不同点:
ArrayList是基于索引的数据接口,它的底层是数组。它可以以O(1)时间复杂度对元素进行随机访问。与此对应,LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。
相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。
LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。
Java提供了只包含一个compareTo()方法的Comparable接口。这个方法是可以比较单个字段的
Java 提供了包含compare()和equals()两个方法的Comparator接口。compare()方法用来给两个输入参数排序,第一个参数大于第二个参数 返回正整数. 相等返回0
类的构造函数定义为private的,保证其他类不能实例化此类,static保证每个类访问到的都是同一个。
饿汉模式:
public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton newInstance(){
return instance;
}
} //缺点,在类加载之后就被创建,即使没有用到
懒汉模式:
public class Singleton{
private static Singleton instance = null;
private Singleton(){}
public static synchronized Singleton newInstance(){
if(null == instance){
instance = new Singleton();
}
return instance;
}
}//在特定时间加载,延迟加载
双重校验锁:
public class Singleton {
private static volatile Singleton instance = null;
private Singleton(){}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {//2
instance = new Singleton();
}
}
}
return instance;
}
}//线程安全
静态内部类:
public class Singleton{
private static class SingletonHolder{
public static Singleton instance = new Singleton();
}
private Singleton(){}
public static Singleton newInstance(){
return SingletonHolder.instance;
}
}
枚举:
public enum Singleton{
instance;
public void whateverMethod(){}
} //很少使用
4.给了一个表三个字段,写SQL语句。主要考察基本SQL语句语法、聚集函数和Group By的用法
姓名 | 分数 | 课程 |
name | score | course |
统计出每个学生有多少门课分数大于80分 select * from
select name,count(*) as num from student where score > 80 group by name;
http://www.cnblogs.com/hnrainll/archive/2013/11/06/3410042.html(讲到了minor GC)
当两个存活区切换了几次(HotSpot虚拟机默认15次,用-XX:MaxTenuringThreshold控制,大于该值进入老年代)之后,仍然存活的对象(其实只有一小部分,比如,我们自己定义的对象),将被复制到老年代。Eden区与Survivor的比例较大,HotSpot默认是 8:1。在发生Minor GC时,虚拟机会检查每次晋升进入老年代的大小是否大于老年代的剩余空间大小,如果大于,则直接触发一次Full GC。
1) 从JVM内存模型开始说起,在纸上画出大概的组成部分,然后说出每个组成部分的特点
线程隔离的有:虚拟机栈,本地方法栈和程序计数器;
线程共享的有:方法区(被虚拟机加载的类的元数据信息:如常量、静态变量、即时编译器编译后的代码。也成为永久代)和堆区(存放所有对象实例和数组);
程序计数器(Program Counter Register):
每一个Java线程都有一个程序计数器来用于保存程序执行到当前方法的哪一个指令,对于非Native方法,这个区域记录的是正在执行的VM原语的地址,如果正在执行的是Natvie方法,这个区域则为空(undefined)。此内存区域是唯一一个在VM Spec中没有规定任何OutOfMemoryError情况的区域。
Java虚拟机栈:
本地变量表存放了编译期可知的各种标量类型(boolean、byte、char、short、int、float、long、double)、对象引用(不是对象本身,仅仅是一个引用指针)、方法返回地址等。其中long和double会占用2个本地变量空间(32bit),其余占用1个。
本地方法栈:
本地方法栈是为虚拟机使用到的Native方法服务。
堆:
绝大部分的对象实例和数组都在这里分配。
2) 开始说说分代GC,这时就把GC算法引入进来,再结合每个区域的特点 把Minor GC 和Full GC 引入进来
标记-清除算法:从根节点开始标记所有可达对象,其余没标记的即为垃圾对象,执行清除。但回收后的空间是不连续的。
复制算法:将内存分成两块,每次只使用其中一块,垃圾回收时,将标记的对象拷贝到另外一块中,然后完全清除原来使用的那块内存。复制后的空间是连续的。(适用于新生代)
标记-压缩算法:适合用于老年代的算法(存活对象多于垃圾对象)。标记后不复制,而是将存活对象压缩到内存的一端,然后清理边界外的所有对象。
2) 可以跟他说说垃圾回收器,Serial 、 ParNew 、CMS 等等
Serial 是单线程的,新生代使用的是复制算法,老年代使用的是标记整理算法;
ParNew是Serial的多线程版本,Parallel Scavenge是ParNew的增强版,提供可控制的吞吐量设置;
Serial Old和ParNew Old对应的是老年代的GC;
CMS是一种以获取最短回收停顿时间为目标的收集器;使用的标记清楚算法;
初始标记,并发标记,重新标记,并发清除;
21.垃圾回收器G1,我只说了CMS
CMS包含初始标记、并发标记、重新标记、并发清除4步。其中初始标记和重新标记是需要停止其他操作的,并发标记和并发清除是与应用线程并发执行。
但是CMS是CPU资源敏感的;无法处理浮动垃圾;CMS是基于“标记-清除”算法的,所以有碎片。
G1是面向服务端的,特点:并行与并发、分代收集、空间整合(使用标记-整理算法)、可预测停顿。它不再区分新老生代,而是划分region,并通过Remembered Set来避免全堆扫描。
G1收集过程是:初始标记、并发标记、最终标记和筛选回收。除了并发标记是并发的,其他都是阻塞的。
死锁:是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。
四个条件同时具备:互斥条件、不可抢占条件、占有且申请条件、循环等待条件。
避免方法:
(1)严格按照一定顺序访问资源;
(2)在取得进程能够执行的所有资源后才给进程分配资源,否则不分配;
(3)
银行家算法:
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
安全:使用元子类,实现并发锁,使用线程安全的类,使用volatile关键字,
建立聚族索引: CREATE CLUSTER INDEX index_name ON table_name(column_name1,column_name2,...);
存储特点:
聚集索引:表数据按照索引的顺序来存储的,也就是说索引项的顺序与表中记录的物理顺序一致。对于聚集索引,叶子结点即存储了真实的数据行,不再有另外单独的数据页。 在一张表上最多只能创建一个聚集索引,因为真实数据的物理顺序只能有一种。
非聚集索引 : 表数据存储顺序与索引顺序无关。对于非聚集索引,叶结点包含索引字段值及指向数据页数据行的逻辑指针,其行数量与数据表行数据量一致。
几乎都用的IOC(通过Spring容器进行对象的管理,以及对象之间组合关系的映射)
日志管理是AOP
。四个特性和隔离级别必须要牢记,了解
事务并发控制带来的问题:脏读、不可重复读、更新丢失、幻读等等
原子性,一致性,隔离性,持久性;
① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
③ Read committed (读已提交):可避免脏读的发生。
④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。
MySql在哪一个级别? 可重复读
oracle是 读已提交
4种都有啊?
indentity 实现数据库自增的生成策略每次加1
sequence 通过序列生成 主键
native 让数据库自己生成 适合的主键
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在 的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。InnoDB除了通过范围条件加锁时使用间隙锁外,如果使用相等条件请求给一个不存在的记录加锁,InnoDB也会使用间隙锁!
Select * from emp where empid > 100 for update;
间隙锁的主要作用是为了防止出现幻读,但是它会把锁定范围扩大,有时候也会给我们带来麻烦。
间隙锁,然后数据库会向左扫描扫到第一个比给定参数小的值, 向右扫描扫描到第一个比给定参数大的值, 然后以此为界,构建一个区间, 锁住整个区间内的数据。
InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。MyISAM存储引擎只支持表锁。
MyISAM表锁是deadlock free的,这是因为MyISAM总是一次获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
MySQL的表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动 给涉及的表加写锁,这个过程并不需要用户干预,因此,用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。
例子:
Lock tables orders read local, order_detail read local;
Select sum(total) from orders;
Select sum(subtotal) from order_detail;
Unlock tables;
上面的例子在LOCK TABLES时加了“local”选项,其作用就是在满足MyISAM表并发插入条件的情况下,允许其他用户在表尾并发插入记录。MyISAM是写优先的。
通过定期在系统空闲时段执行 OPTIMIZE TABLE语句来整理空间碎片,收回因删除记录而产生的中间空洞。
InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION);二是采用了行级锁。
l 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
l 排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。
另外,为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。
l 意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
l 意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。
排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE。
InnoDB行锁是通过给索引上的索引项加锁来实现的.由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。如果不是相同的索引就不会等待。
create table tab_no_index(id int,name varchar(10)) engine=innodb;
一是MySQL的恢复是SQL语句级的,也就是重新执行BINLOG中的SQL语句。
二是MySQL的Binlog是按照事务提交的先后顺序记录的,恢复也是按这个顺序进行的。
简单(GC)、面向对象、平台无关(JVM)、分布式、多线程、可靠和安全等特性
Collection 接口的接口 对象的集合
├ List 子接口 按进入先后有序保存 可重复
│├ LinkedList 接口实现类 链表 插入删除 没有同步 线程不安全
│├ ArrayList 接口实现类 数组 随机访问 没有同步 线程不安全
│
├ Queue 子接口 队列集合
└ Set 子接口 仅接收一次,并做内部排序
├ HashSet
│ └ LinkedHashSet 插入的次序
└ TreeSet
Map 接口 键值对的集合
├ Hashtable 接口实现类 同步 线程安全 键值非空
├ HashMap 接口实现类 没有同步 线程不安全
│├ LinkedHashMap 插入次序
│└ WeakHashMap
├ TreeMap 基于红黑树,可以返回子树 排序的
└ IdentifyHashMap
Collections 是针对集合类的一个帮助类。提供了一系列静态方法实现对各种集合的搜索、打乱Collections .shuffer()\\排序Collections .sort()、线程完全化等操作。相当于对 Array 进行类似操作的类——
Arrays 。
通过compartor 的conpare(两个参数)
使用Collections.sort()传入ArrayList,会采用默认的方式进行排序(字典序)
使用Collections.sort()传入ArrayList和自己实现Commparator接口的类的对象,实现自定义排序
使用List.sort()传入自己实现Commparator接口的类的对象,实现自定义排序
Annotation是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。通过使用Annotation,开发人员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充的信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证、处理或者进行部署。
4个元注解:1.@Target,用于描述注解的使用范围,@Target(ElementType.FIELD)
2.@Retention,用于描述注解的生命周期,@Retention(RetentionPolicy.RUNTIME)
3.@Documented,可以被例如javadoc此类的工具文档化
4.@Inherited,@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。
三种标准annontation类型:
(1)Override,被标注的方法重载了父类的方法;
(2)Deprecated
(3)SuppressWarnings,此注解能告诉Java编译器关闭对类、方法及成员变量的警告。
@Autowired顾名思义,就是自动装配,其作用是为了消除代码Java代码里面的getter/setter与bean属性中的property。
如果容器中有一个以上匹配的Bean,则可以通过@Qualifier注解限定Bean的名称;
@Service对应的是业务层Bean;
@Repository对应数据访问层Bean;
@Configuration把一个类作为一个IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。
@Scope注解 作用域
@Lazy(true) 表示延迟初始化
@Service用于标注业务层组件、
@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注数据访问组件,即DAO组件。
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Scope用于指定scope作用域的(用在类上)
@PostConstruct用于指定初始化方法(用在方法上)
@PreDestory用于指定销毁方法(用在方法上)
@DependsOn:定义Bean初始化及销毁时的顺序
@Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
@Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。如下:
@Autowired @Qualifier("personDaoBean") 存在多个实例配合使用
@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
@PostConstruct 初始化注解
@PreDestroy 摧毁注解 默认 单例 启动就加载
@Async异步方法调用
透明性,暴露资源存在。
充分利用 HTTP 协议本身语义。
无状态,这点非常重要。在调用一个接口(访问、操作资源)的时候,可以不用考虑上下文,不用考虑当前状态,极大的降低了复杂度
HTTP 本身提供了丰富的内容协商手段,无论是缓存,还是资源修改的乐观并发控制,都可以以业务无关的中间件来实现
低耦合;
hashcode方法计算key决定在数组中的位置,hashcode值相同发生hash冲突,通过形成链表解决冲突 euqals方法决定在链表中的位置
HashMap不是线程安全的
wait()和notify()必须在synchronized代码块中调用。
在并发量比较小的情况下,使用synchronized是个不错的选择,但是在并发量比较高的情况下,其性能下降很严重,此时ReentrantLock是个不错的方案。
区别:
(1)Synchronized是java关键字,是内置特性;而Lock是一个类;
(2)Lock可以让等待锁的线程响应中断,而synchronized却不行;
(3)Lock可以提高多个线程进行读操作的效率;
(4)Synchronized的锁是自动释放的,Lock需要手动释放;
(5)Lock可以知道线程有没有成功获得锁。
java.util.concurrent.locks有Lock是一个接口:
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
ReentrantLock(可重入锁)是唯一实现了Lock接口的类。
单独调用interrupt()方法不能中断正在运行过程中的线程,只能中断阻塞过程中的线程。
ReentrantReadWriteLock是唯一实现ReadWriteLock接口的类,有ReadLock和WriteLock方法。
synchronized和ReentrantLock都是可重入锁。
公平锁即尽量以请求锁的顺序来获取锁。比如同是有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该所,这种就是公平锁。
ReentrantLock lock = new ReentrantLock(true);
,synchronized就是非公平锁,它无法保证等待的线程获取锁的顺序。
而对于ReentrantLock和ReentrantReadWriteLock,它默认情况下是非公平锁,但是可以设置为公平锁。
public void test() {
...
synchronized(this) {
// todo your code
}
...
}
//此时,其效果等同于
public synchronized void test() {
// todo your code
}
Daemon的作用是为其他线程的运行提供服务,比如说GC线程。thread.setDaemon(true)必须在thread.start()之前设置。 在Daemon线程中产生的新线程也是Daemon的。
当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程
命令模式:将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化,用于“行为请求者”与“行为实现者”解耦,可实现二者之间的松耦合,以便适应变化。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。
java.lang.Runnable 和 javax.swing.Action是使用命令模式的经典场景。
java.util.concurrent.ThreadPoolExecutor;
corePoolSize:核心池的大小
maximumPoolSize:线程池最大线程数
keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
线程池状态:
static final int RUNNING = 0;
static final int SHUTDOWN = 1;
static final int STOP = 2;
static final int TERMINATED = 3;
execute()
submit()
shutdown()
shutdownNow()立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务.
线程池的种类:
Executors.newCachedThreadPool(); //创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE
Executors.newSingleThreadExecutor(); //创建容量为1的缓冲池
Executors.newFixedThreadPool(int); //创建固定容量大小的缓冲池
Executors.newScheduleThreadPool创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer。
一般需要根据任务的类型来配置线程池大小:
如果是CPU密集型任务,就需要尽量压榨CPU,参考值可以设为 NCPU+1
如果是IO密集型任务,参考值可以设置为2*NCPU
单个任务处理的时间很短而请求的数目却是巨大的。join和close都可以用来关闭线程池。不同的是,join会把队列中的任务执行完,而close则立刻清空队列,并且中断所有的工作线程。
线程池大小,死锁,系统资源不足,并发错误,线程泄漏(比如都在等待用户输入),任务过载(太多等待任务)。
Java中的HashMap是以键值对(key-value)的形式存储元素的。HashMap需要一个hash函数,它使用hashCode()和 equals()方法来向集合/从集合添加和检索元素。当调用put()方法的时候,HashMap会计算key的hash值,然后把键值对存储在集合中 合适的索引上。如果key已经存在了,value会被更新成新值。HashMap的一些重要的特性是它的容量(capacity),负载因子(load factor)和扩容极限(threshold resizing)。
equals一般是用来实现两个对象内容的比较,如果不重写就会和==一样。一般重写equals方法的时候都会相应的重写hashCode方法。(重写hashCode方法是个难点)
Java中的HashMap使用hashCode()和equals()方法来确定键值对的索引,当根据键获取值的时候也会用到这两个方法。如果没有正确 的实现这两个方法,两个不同的键可能会有相同的hash值,因此,可能会被集合认为是相等的。而且,这两个方法也用来发现重复元素。所以这两个方法的实现 对HashMap的精确性和正确性是至关重要的。
如何保证key的唯一性?即hashCode和equals的实现原理
相等的对象必须具有相同的散列码,但散列码相同则不一定是相等的对象,而且不相等的对象也不一定需要有不同的散列码。
HashMap和Hashtable都实现了Map接口,因此很多特性非常相似。但是,他们有以下不同点:
HashMap允许键和值是null,而Hashtable不允许键或者值是null。
Hashtable是同步的,而HashMap不是。因此,HashMap更适合于单线程环境,而Hashtable适合于多线程环境。
HashMap提供了可供应用迭代的键的集合,因此,HashMap是快速失败的。另一方面Hashtable提供了对键的列举(Enumeration)。一般认为Hashtable是一个遗留的类。
26.一致性Hash原理
Trace跟踪参数:
-XX:+PrintGCDetails 打印GC详细信息;
-XX:+PrintGCTimeStamps 打印GC时间戳;
-Xloggc:log/gc.log 指定GC log的位置;
-XX:+PrintHeapAtGC 每一次GC前和GC后,都打印堆信息;
-XX:+TraceClassLoading 监控类的加载;
-XX:+PrintClassHistogram 按下Ctrl+Break后,打印类的信息;
堆的分配参数:
-Xmx20m -Xms5m 指定最大堆和最小堆;
问题1: -Xmx(最大堆空间)和 –Xms(最小堆空间)应该保持一个什么关系,可以让系统的性能尽可能的好呢?
问题2:如果你要做一个Java的桌面产品,需要绑定JRE,但是JRE又很大,你如何做一下JRE的瘦身呢?
-Xmn 官方推荐新生代占堆的3/8,幸存代占新生代的1/10
设置新生代大小
新生代(eden+2*s)和老年代(不包含永久区)的比值
例如:4,表示新生代:老年代=1:4,即新生代占整个堆的1/5
设置两个Survivor区和eden的比值
例如:8,表示两个Survivor:eden=2:8,即一个Survivor占年轻代的1/10
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump
如果发生了OOM异常,那就把dump信息导出到d:/a.dump文件中。
-XX:OnOutOfMemoryError=D:/tools/jdk1.7_40/bin/printstack.bat %p //p代表的是当前进程的pid
上方参数的意思是说,执行printstack.bat脚本,而这个脚本做的事情是:D:/tools/jdk1.7_40/bin/jstack -F %1 > D:/a.txt,即当程序OOM时,在D:/a.txt中将会生成线程的dump。
-XX:PermSize=16m -XX:MaxPermSize:设置永久区的初始空间和最大空间;
栈的分配参数:
Xss 设置栈空间的大小。通常只有几百K;-Xss128K
-XX:+UseParallelGC -XX:ParallelGCThreads=20此配置仅对年轻代有效。
-XX:MaxGCPauseMillis=100 : 设置每次年轻代垃圾回收的最长时间
-XX:+UseCMSCompactAtFullCollection :打开对年老代的压缩。
常见配置汇总
只要term加1之后,之前的leader就作废,这轮选举一定能选出来。我觉得还得看下这个term什么时候会加1,意思就是题目中follower在什么情况下term比之前leader高。因为follower在一个时间段内因为网络波动收不到leader的心跳,他就自动转化为candidate状态且term+1。
time_wait 状态本来就是等待2个msl就直接进入closed状态
TIME_WAIT状态维持时间是两个MSL时间长度,也就是在1-4分钟。Windows操作系统就是4分钟。
MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时间.
time_wait存在的原因:
1.可靠的终止TCP连接。
2.保证让迟来的TCP报文段有足够的时间被识别并丢弃。
为什么要三次握手:
为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。
为什么需要四次挥手:
原因是因为tcp是全双工模式,接收到FIN时意味将没有数据再发来,但是还是可以继续发送数据。
1. 容器寻找Bean的定义信息并且将其实例化。
2.受用依赖注入,Spring按照Bean定义信息配置Bean的所有属性。
3.如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。
4.如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身。
5.如果BeanPostProcessor和Bean关联,那么它们的postProcessBeforeInitialzation()方法将被调用。
6.如果Bean指定了init-method方法,它将被调用。
7.最后,如果有BeanPsotProcessor和Bean关联,那么它们的postProcessAfterInitialization()方法将被调用。
生命周期:执行完上面的步骤就可以使用了,使用完毕后关闭容器:
调用DisposableBean的destory方法;
Bean在实例化的过程中:Constructor > @PostConstruct >InitializingBean > init-method
Bean在销毁的过程中:@PreDestroy > DisposableBean > destroy-method
在整个Java.io包中最重要的就是5个类和一个接口。5个类指的是File、OutputStream、InputStream、Writer、Reader;一个接口指的是Serializable.
适配器模式,改变接口来重复使用
把一个类的接口变成客户端能接受的另一种接口。
使两个接口不一样的类能一起工作。
InputStreamReader适配器实现了Reader接口,持有InputStream引用。这样Reader字节最终调用InputStream
InputStreamReader:对象+接口
装饰器模式,接口不变,增强原来对象的功能
赋予类更多的功能,
FileInputStream,
BufferedInputStream是具体实现者,把InputStream读取内容保存在内存中,增强了功能。
它的基础就是AbstractQueuedSynchronizer抽象类,Lock,CountDownLatch等的基础就是该类,而该类又用到了 CAS操作。CAS之前已经介绍过。JUC在同步器的设计上有获取操作和释放操作。AbstractQueuedSynchronizer(AQS)就是 一种同步器的实现。
原子对象;
locks;
Semaphore一个计数信号量,主要用于控制多线程对共同资源库访问的限制。
CountDownLatch一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。CyclicBarrier用于一组线程执行时,每个线程执行有多个节点,每个节点的处理需要相互等待。
CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。但是有ABA的问题,可以通过版本号来解决。
public synchronized int compareAndSwap(int expectedValue, int newValue) {
int oldValue = value;
if (oldValue == expectedValue) {
value = newValue;
}
return oldValue;
}
unsafe.compareAndSwapInt(this, valueOffset, expect, update);
Morris遍历,实际上是用叶子节点的空指针来记录当前节点的位置,然后一旦遍历到了叶子节点,发现叶子节点的右指针指向的是当前节点,那么就认为以当前节点的左子树已经遍历完成。
它的遍历规则如下:
1. 如果当前节点的左子节点为空时,输出当前节点,并将当前节点置为该节点的右子节点;
2. 如果当前节点的左子节点不为空,找到当前节点左子树的最右节点(该节点为当前节点中序遍历的前驱节点);
2.1. 如果最右节点的右指针为空(right=null),将最右节点的右指针指向当前节点,当前节点置为其左子节点;
2.2. 如果最右节点的右指针不为空,将最右节点右指针重新置为空(恢复树的原状),输出当前节点,并将当前节点置为其右节点;
3. 重复1~2,直到当前节点为空。
ps -ef | grep java
kill -9 [PID] -9 表示强迫进程立即停止
cat /proc/meminfo
sudo atop atop命令是一个终端环境的监控命令。它显示的是各种系统资源的综合,并且在高负载的情况下进行了彩色标注。
top top命令提供了实时的运行中的程序的资源使用统计。
free -h free命令是一个快速查看内存使用情况的方法,它是对 /proc/meminfo 收集到的信息的一个概述。
ps命令可以实时的显示各个进程的内存使用情况。
vmstat命令显示实时的和平均的统计,覆盖CPU、内存、I/O等内容。
因为有final关键字,所以不能被继承。
“+”是通过StringBuffer或者是StringBuilder的append()和toString()方法来实现的。
String类对象为不可变对象,StringBuffer类对象为可修改对象,可以通过append()方法来修改值;都是线程安全的。
StringBuilder线程不安全,但是效率比StringBuffer高。
开放地址法是对那些发生冲突的记录,用hi=(h(key)+di)mod n方法再次确定Hash地址。
n:为哈希表长;
di:为增量序列,其取法有以下三种:
1)线性探测再散列 di= c * i
2)二次探测再散列 di = 12, -12, 22, -22, …,
3) 随机探测再散列 di是一组伪随机数列 或者 di=i×H2(key) (又称双散列函数探测)
链地址法:将所有哈希地址相同的记录都链接在同一链表中
Java异常分为Exception和Error两大类型,Exception又分为运行时异常(RuntimeException)和非运行时异常(如IOException),运行时异常代表运行时由Java虚拟机生成的异常,Java编译器要求Java程序必须捕获或生命所有的非运行时异常,但对运行时异常可以不做处理。
Java中有两种异常:受检查的(checked)异常和不受检查的(unchecked)异常。不受检查的异常不需要在方法或者是构造函数上声明,就算方法或者是构造函数的执行可能会抛出这样的异常,并且不受检查的异常可以传播到方法或者是构造函数的外面。相反,受检查的异常必须要用throws语句在方法或者是构造函数上声明。这里有Java异常处理的一些小建议。
Java中Exception和Error有什么区别?
方法运行过程中如果发生了意外,方法将生成一个相应类型的异常,并把它交给运行时系统,这一过程称为抛出。运行时系统受到异常后,会寻找相应的代码来处理,这一过程称为捕获。
Exception和Error都是Throwable的子类。Exception用于用户程序可以捕获的异常情况。Error是指Java虚拟机内部发生错误,由虚拟机生产并抛出,定义了不期望被用户程序捕获的异常。
为什么使用自定义异常?
因为项目中有时会有符合Java语法,但是不符合业务逻辑的情况,这时就需要自定义异常了。
什么是cookie?session和cookie有什么区别?
cookie是Web服务器发送给浏览器的一块信息。浏览器会在本地文件中给每一个Web服务器存储cookie。以后浏览器在给特定的Web服务器发请求的时候,同时会发送所有为该服务器存储的cookie。下面列出了session和cookie的区别:
无论客户端浏览器做怎么样的设置,session都应该能正常工作。客户端可以选择禁用cookie,但是,session仍然是能够工作的,因为客户端无法禁用服务端的session。
在存储的数据量方面session和cookies也是不一样的。session能够存储任意的Java对象,cookie只能存储String类型的对象。
设置session有效期的方法有:
(1)在Tomcat的server.xml中定义;
(2)在工程的web.xml中定义;
(3)通过session.setMaxInactiveInterval(1000);
判断session是否失效:
request.getSession(false) == null ?
清楚session中的信息:session.invalidate();
Cookie可以设置有效期:cookie.setMaxAge(120);
在禁用Cookie的情况下使用Session:response.encodeurl(url);
队为空的判断:front==rear;队为满的判断:(rear+1)%MAXSIZE==front。
public class CircleQueue {
private int[] q = null;
//首索引
private int head = 0;
//尾索引
private int tail = 0;
private int len = 0;
public CircleQueue(int len){
this.len = len;
q = new int[len];
}
//insert into circle queue
private int insert(int x){
//判断循环队列是否已满
if (isFull()){
System.out.println("circle queue is Full");
return -1;
}else {
q[tail] = x;
//逻辑上实现首尾相连,循环队列
tail = (tail + 1) % len;
//返回最近插入的元素
return x;
}
}
private int pop(){
if (isNull()){
System.out.println("circle queue is Null");
return -1;
}else {
int n = q[head];
//头结点不断追赶尾结点
head = (head + 1)%len;
//返回最近弹出的元素
return n;
}
}
private int head(){
return q[head];
}
private int tail(){
return q[(tail + len - 1)%len];
}
private boolean isFull(){
if ((tail + 1) % len == head){
return true;
}else {
return false;
}
}
//check is null
private boolean isNull(){
//首尾相等的话则为空
if (head == tail){
return true;
}else {
return false;
}
}
}
GET http://download.microtool.de:80/somedata.exe
Host: download.microtool.de
Accept:*/* 告诉WEB服务器自己接受什么介质类型,*/* 表示任何类型
Pragma: no-cache
Cache-Control: no-cache 指定请求和响应遵循的缓存机制。
Connection:Keep-Alive 表示连接状态
Referer: http://download.microtool.de/
User-Agent:Mozilla/4.04[en](Win95;I;Nav)
Range:bytes=554554-
响应:
HTTP/1.0 200 OK
Date:Mon,31Dec200104:25:57GMT
Server:Apache/1.3.14(Unix)
Content-type:text/html
Last-modified:Tue,17Apr200106:46:28GMT
Etag:"a030f020ac7c01:1e9f"
Content-length:39725426
Content-range:bytes554554-40279979/40279980
TCP/IP的4层模型:
(1)应用层:FTP、DNS、Telnet、SMTP、HTTP
(2)传输层:TCP(传输控制协议)、UDP(用户数据报协议)
(3)网络层:IP
(4)网络接口层:接受和发送IP数据包。
(1)应用层:与其他计算机进行通讯的一个应用,它是对应应用程序的通信服务的。示例:telnet,HTTP,FTP,WWW,NFS,SMTP等。
(2)表示层:这一层的主要功能是定义数据格式及加密。示例:加密,ASII等。
(3)会话层:他定义了如何开始、控制和结束一个会话,包括对多个双向小时的控制和管理,以便在只完成连续消息的一部分时可以通知应用,从而使表示层看到的数据是连续的。示例:RPC,SQL等。
(4)传输层:这层的功能包括是否选择差错恢复协议还是无差错恢复协议,及在同一主机上对不同应用的数据流的输入进行复用,还包括对收到的顺序不对的数据包的重新排序功能。示例:TCP,UDP,SPX。
(5)网络层:这层对端到端的包传输进行定义,他定义了能够标识所有结点的逻辑地址,还定义了路由实现的方9式和学习的方式。。示例:IP,IPX等。
(6)数据链路层:他定义了在单个链路上如何传输数据。
(7)物理层:OSI的物理层规范是有关传输介质的特性标准,这些规范通常也参考了其他组织制定的标准。
1、在浏览器中输入www.qq.com域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析。
2、如果hosts里没有这个域名的映射,则查找本地DNS解析器缓存,是否有这个网址映射关系,如果有,直接返回,完成域名解析。
3、如果hosts与本地DNS解析 器缓存都没有相应的网址映射关系,首先会找TCP/ip参数中设置的首选DNS服务器,在此我们叫它本地DNS服务器,此服务器收到查询时,如果要查询的 域名,包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析,此解析具有权威性。
4、如果要查询的域名,不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析,此解析不具有权威性。
5、如果本地DNS服务器本地区域文 件与缓存解析都失效,则根据本地DNS服务器的设置(是否设置转发器)进行查询,如果未用转发模式,本地DNS就把请求发至13台根DNS,根DNS服务 器收到请求后会判断这个域名(.com)是谁来授权管理,并会返回一个负责该顶级域名服务器的一个IP。本地DNS服务器收到IP信息后,将会联系负 责.com域的这台服务器。这台负责.com域的服务器收到请求后,如果自己无法解析,它就会找一个管理.com域的下一级DNS服务器地址 (qq.com)给本地DNS服务器。当本地DNS服务器收到这个地址后,就会找qq.com域服务器,重复上面的动作,进行查询,直至找到 www.qq.com主机。
6、如果用的是转发模式,此DNS服 务器就会把请求转发至上一级DNS服务器,由上一级服务器进行解析,上一级服务器如果不能解析,或找根DNS或把转请求转至上上级,以此循环。不管是本地 DNS服务器用是是转发,还是根提示,最后都是把结果返回给本地DNS服务器,由此DNS服务器再返回给客户机。
当应用过程需要将一个主机域名映射为IP地址时,就调用域名解析函数,解析函数将待转换的域
名放在DNS请求中,以UDP报文方式发给本地域名服务器。 本地的域名服务器查到域名后,将对应的IP地址放在应答报文中返回。同时域名服务器还必须具有连向其他服务器的信息以支持不能解析时的转发。若域名服务器 不能回答该请求,则此域名服务器就暂成为DNS中的另一个客户,向根域名服务器发出请求解析,根域名服务器一定能找到下面的所有二级域名的域名服务器,这样以此类推,一直向下解析,直到查询到所请求的域名。
protected Object | clone() 创建并返回此对象的一个副本。 |
boolean | equals(Object obj) 指示其他某个对象是否与此对象“相等”。 |
protected void | finalize() 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。 |
Class> | getClass() 返回此 Object 的运行时类。 |
int | hashCode() 返回该对象的哈希码值。 |
void | notify() 唤醒在此对象监视器上等待的单个线程。 |
void | notifyAll() 唤醒在此对象监视器上等待的所有线程。 |
String | toString() 返回该对象的字符串表示。 |
void | wait() 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。 |
void | wait(long timeout) 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。 |
void | wait(long timeout, int nanos) 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。 |
进程是执行着的应用程序,而线程是进程内部的一个执行序列。一个进程可以有多个线程。线程又叫做轻量级进程。
进程是CPU分配资源的最小单位,线程是CPU调度和程序执行的最小单位;
一个进程有几个(至少一个)线程组成,他们共享进程资源,同一个人进程可以有多个线程并发,一个线程可以创建和撤销另一个线程;
进程有自己的独立地址空间,线程只有自己的堆栈和局部变量;
进程切换需要很大的开销,线程开销相对较小。
协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。
反射的作用于原理。
反射是指程序可以访问、检测和修改其自身状态或行为的一种能力。
数据库的DDL、DML(数据操纵语言)
DDL(数据库定义语句)是SQL语言的四大功能之一。
用于定义数据库的三级结构,包括外模式、概念模式、内模式及其相互之间的映像,定义数据的完整性、安全控制等约束
DDL不需要commit.
CREATE
ALTER
DROP
TRUNCATE
COMMENT
RENAME
DML分成交互型DML和嵌入型DML两类。
依据语言的级别,DML又可分成过程性DML和非过程性DML两种。
需要commit.
SELECT
INSERT
UPDATE
DELETE
MERGE
CALL
EXPLAIN PLAN
LOCK TABLE
DCL(数据库控制语言)
GRANT 授权
REVOKE 取消授权
TCL(Transaction Control Language)事务控制语言
SAVEPOINT 设置保存点
ROLLBACK 回滚
SET TRANSACTION
底层也是char[]}通过append拼接字符
内核态: CPU可以访问内存所有数据, 包括外围设备, 例如硬盘, 网卡. CPU也可以将自己从一个程序切换到另一个程序
用户态: 只能受限的访问内存, 且不允许访问外围设备. 占用CPU的能力被剥夺, CPU资源可以被其他程序获取
用户态切换到内核态的3种方式:a. 系统调用;b. 异常;c. 外围设备的中断。
代理设计模式。
Runnable target = new MyTarget();// 目标角色
Thread proxy = new Thread(target);// 代理角色
proxy.start();
在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。
private void handleSocket() throws Exception {
Reader reader = new InputStreamReader(socket.getInputStream());
char chars[] = new char[64];
int len;
StringBuilder sb = new StringBuilder();
String temp;
int index;
while ((len=reader.read(chars)) != -1) {
temp = new String(chars, 0, len);
if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就结束接收
sb.append(temp.substring(0, index));
break;
}
sb.append(temp);
}
System.out.println("from client: " + sb);
//读完后写一句
Writer writer = new OutputStreamWriter(socket.getOutputStream());
writer.write("Hello Client.");
writer.flush();
writer.close();
reader.close();
socket.close();
}
}
----------------------------------------------------------------更新---------------------------------------------
数据库索引;(高频)
CREATE CLUSTER INDEX id
索引的实现通常使用B树及其变种B+树。
优点:加快查询速度;
缺点:占用空间,维护起来比较耗时;
建议使用索引的地方:主键,外键;需要排序或者根据范围来检索的列;经常需要搜索的列;WHERE子句中的列。
不创建索引的列:查询很少用到的列;只有很少数据值的列;修改性远远大于检索性的列。
索引类型有:主键索引,唯一索引,聚集索引。
将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。B-Tree中一次检索最多需要h-1次I/O(根节点常驻内存),渐进复杂度为O(h)=O(logdN)。一般实际应用中,出度d是非常大的数字,通常超过100,因此h非常小(通常不超过3)。
而红黑树这种结构,h明显要深的多。由于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性,所以红黑树的I/O渐进复杂度也为O(h),效率明显比B-Tree差很多。
预读的长度一般为页(page)的整倍数。页是计算机管理存储器的逻辑块,硬件及操作系统往 往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页(在许多操作系统中,页得大小通常为4k),主存和磁盘以页为单位交换数据。当程序要 读取的数据不在主存中时,会触发一个缺页异常,此时系统会向磁盘发出读盘信号,磁盘会找到数据的起始位置并向后连续读取一页或几页载入内存中,然后异常返 回,程序继续运行。
索引类型(全文索引),底层实现(B+树),什么情况下索引会失效
索引是对数据库表中一列或多列的值进行排序的一种结构。
唯一索引、主键索引和聚集索引。
MySQL目前主要有以下几种索引类型:FULLTEXT,HASH,BTREE,RTREE。
FULLTEXT,即为全文索引,目前只有MyISAM引擎支持。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不过目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引。
HASH,hash很适合做索引,为某一列或几列建立hash索引,就会利用这一列或几列的值通过一定的算法计算出一个hash值,对应一行或几行数据。
以下几种情况,将导致索引失效:
3.like查询是以%开头
4.如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
5.如果mysql估计使用全表扫描要比使用索引快,则不使用索引
数据库优化(索引、存储引擎、sql优化、视图)
1.适当建立索引:对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引,但索引并不是越多越好:
(1)应尽量避免在 where 子句中对字段进行 null 值判断,应尽量避免在 where 子句中使用 != 或 <> 操作符,以及like "%aa",使用参数, or (如果一个字段有索引,一个字段没有索引),in 和 not in 也要慎用,应尽量避免在where子句中对字段进行函数操作,不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
2.Update 语句,如果只更改1、2个字段,不要Update全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志。
3.对于多张大数据量(这里几百条就算大了)的表JOIN,要先分页再JOIN,否则逻辑读会很高,性能很差。
4.select count(*) from table;这样不带任何条件的count会引起全表扫描,并且没有任何业务意义,是一定要杜绝的。
5.应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。
6.选择适当的字段类型,特别是主键:尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型。
索引的实现通常使用B树及其变种B+树。
本文转自:https://www.cnblogs.com/shan1393/p/9292374.html