java面试准备(个人)

目录

java思想

java

排序

插入排序

冒泡排序

快速排序

堆排序

桶排序

面向对象的特征

修饰符

string不是基本类型

float f=3.4;是否正确?

short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?

goto 是Java中的保留字

int 和Integer 有什么区别?

&和&&的区别?

内存中的栈(stack)、堆(heap)和静态存储区的用法。

Math.round(11.5) 等于多少? Math.round(-11.5)等于多少?

用最有效率的方法计算2乘以8?

构造器(constructor)是否可被重写(override)?

String s=new String(“xyz”);创建了几个字符串对象?

接口是否可继承(extends)接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)?

如何实现字符串的反转及替换?

日期和时间:

Java 语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用?

网络协议

TCP,UDP,HTTP

Socket 通信

设计模式

设计模式六大原则

工厂模式

单例模式

SpringMVC

工作原理

springmvc常用注解

开启注解处理器和适配器

get和post乱码

spring容器

spring,IOC,AOP

spring注解

spring作用

springjdbc,springDAO,springORM

spring配置文件

Spring 的依赖注入

基于 Java 的 Spring 注解配置

Spring 的通知是什么?

mybatis

#和$的区别

̕Mybatis 的编程步骤

mybatis解决jdbc

使用 MyBatis 的 mapper 接口调用

分布式

负载均衡实现

redis

redis存储方式

redis常见问题

redis适用场景

Memcache 与 Redis 的区别

redis数据结构

redis优缺点

redis持久化

死锁

死锁产生的必要条件

产生原因

预防死锁

避免死锁

银行家算法

多线程

Mysql

SQL优化

避免使用子查询

用in代替or

读取适当的记录limit m,n。不要读多余的数据

禁止不必要的order by排序

少用select *

将多次插入换成批量insert插入

尽量使用数字型字段

mysql有哪些索引

操作

insert

update

delete

select

高级操作

表复制

接口

spring boot jpa

1.yml文件

2.实体类

3.具体操作类接口

4.Controller控制展示类

idea项目目录结构

@Data注解代替get和set方法

@RestController注解

@RequestBody注解

POST/PUT/DELETE请求

根据id查询数据库信息

分页查询

spring boot基本结构

1.配置application.yml文件

2.建立实体类,与数据库表字段一致(在entity包中)

3.创建mapper接口

4.建立service层对mapper接口查询的数据进行处理

5.在controller中实例化service层的方法

Ajax

$.ajax

$.get和$.post

$.getJSON


java思想

java

排序

插入排序

把未排序的元素一个一个地插入到有序的集合中,插入时把有序集合从后向前扫一遍,找到合适的插入位置

时间复杂度是O(n²) 空间复杂度是O(1)

冒泡排序

它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,

时间复杂度O(n^2) 空间复杂度O(1)

快速排序

快速排序也属于交换排序算法,通过元素之间的比较和交换位置来达到排序的目的。

快速排序每次排序的时候设置一个基准点,将小于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。

快速排序算法的实现思路就是分治思想的应用。

时间复杂度O(nlogn) 空间复杂度O(nlogn)

堆排序

堆排序按照从小到大的顺序进行排序的步骤如下:

\1. 将长度为 n 的序列构造成为一个大顶堆

\2. 将根结点与序列最后一个结点进行交换,此时最后一个结点就是该序列的最大值

\3. 将剩余的 n - 1 个结点再次构造成为一个大顶堆;

\4. 重复步骤 2、3,直到构造成一个完全有序的序列。

堆需要满足两个条件:

  1. 是一颗完全二叉树(Complete Binary Tree)

  2. 堆上面的每一个节点都必须满足父结点的值大于等于子结点的值或者父结点的值小于等于子结点的值

int tree[] = {6, 10, 3, 8, 5, 12, 7, 2, 9}

第一步:通过原始序列构造一个大顶堆(升序采用大顶堆,降序采用小顶堆)。

  1. 先通过序列通过从上到下从左往右的顺序构造一个完全二叉树

  2. 对第三层的父节点和第四层的子结点进行调整,其中粉红色代表发生交换的结点。使得其父节点大于两个子结点。

    即也是从最后 1 个非叶子结点开始 (8 - 1) / 2 = 3, 也就是从 8 开始进行从左到右从下到上进行调整。

    [8,2,9] 中,9 最大,交换 8 和 9。

  3. 对第二层父节点和第三层子结点进行调整。

    [10,9,5] 中,10 最大,不交换。

    [3,12,7] 中,12 最大,交换 3 和 12。

  4. 对第一层父节点和第二层子结点进行调整。

    [6,10,12] 中,12 最大,交换 6 和 12。

  5. 这时,上面操作导致 [6,3,7] 不是一个大顶堆,继续调整。

    [6,3,7] 中,7 最大,交换 6 和 7。

时间复杂度O(nlogn) 空间复杂度O(1)

桶排序

桶排序的思想就是把待排序的数尽量均匀地放到各个桶中,再对各个桶进行局部的排序,最后再按序将各个桶中的数输出,即可得到排好序的数。

用于处理数组长度不过的问题

首先确定桶的个数。因为桶排序最好是将数据均匀地分散在各个桶中,那么桶的个数最好是应该根据数据的分散情况来确定。首先找出所有数据中的最大值mx和最小值mn;

根据mx和mn确定每个桶所装的数据的范围 size,有size = (mx - mn) / n + 1,n为数据的个数,需要保证至少有一个桶,故而需要加个1;

求得了size即知道了每个桶所装数据的范围,还需要计算出所需的桶的个数cnt,有cnt = (mx - mn) / size + 1,需要保证每个桶至少要能装1个数,故而需要加个1;

求得了size和cnt后,即可知第一个桶装的数据范围为 [mn, mn + size),第二个桶为 [mn + size, mn + 2 * size),…,以此类推因此步骤2中需要再扫描一遍数组,将待排序的各个数放进对应的桶中。

对各个桶中的数据进行排序,可以使用其他的排序算法排序,例如快速排序;也可以递归使用桶排序进行排序;

将各个桶中排好序的数据依次输出,最后得到的数据即为最终有序。

面向对象的特征

封装, 继承,多态 “抽象”

修饰符

作用域 当前类 同包 子类 其他

public √ √ √ √

protected √ √ √ ×

default √ √ × ×

private √ × × ×

类的成员不写访问修饰时默认为default

string不是基本类型

Java中的基本数据类型只有8个:byte、short、int、long、float、double、char、boolean

float f=3.4;是否正确?

答:不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F;

short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?

答:对于short s1 = 1; s1 = s1 + 1;由于1是int类型,因此s1+1运算结果也是int 型,需要强制转换类型才能赋值给short型。而short s1 = 1; s1 += 1;可以正确编译,因为s1+= 1;相当于s1 = (short)(s1 + 1);其中有隐含的强制类型转换。

goto 是Java中的保留字

int 和Integer 有什么区别?

答:Java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入不是对象的基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java为每一个基本数据类型都引入了对应的包装类型(wrapper class),int的包装类就是Integer,从JDK 1.5开始引入了自动装箱/拆箱机制,使得二者可以相互转换。

public class AutoUnboxingTest {  
  
    public static void main(String[] args) {  
        Integer a = new Integer(3);  
        Integer b = 3;              // 将3自动装箱成Integer类型  
        int c = 3;  
        System.out.println(a == b); // false 两个引用没有引用同一对象  
        System.out.println(a == c); // true a自动拆箱成int类型再和c比较  
    }  
}

public class Test03 {  
  
    public static void main(String[] args) {  
        Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;  
          
        System.out.println(f1 == f2);  //true
        System.out.println(f3 == f4);  //false
    }  
}  
如果字面量的值在-128到127之间,那么不会new新的Integer对象,而是直接引用常量池中的Integer对象,所以上面的面试题中f1==f2的结果是true,而f3==f4的结果是false。

&和&&的区别?

答:&运算符有两种用法:(1)按位与;(2)逻辑与。&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true整个表达式的值才是true。&&之所以称为短路运算是因为,如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算。很多时候我们可能都需要用&&而不是&,例如在验证用户登录时判定用户名不是null而且不是空字符串,应当写为:username != null &&!username.equals(“”),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的equals比较,否则会产生NullPointerException异常。注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此

内存中的栈(stack)、堆(heap)和静态存储区的用法。

答:通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用内存中的栈空间;而通过new关键字和构造器创建的对象放在堆空间;程序中的字面量(literal)如直接书写的100、“hello”和常量都是放在静态存储区中。栈空间操作最快但是也很小,通常大量的对象都是放在堆空间,整个内存包括硬盘上的虚拟内存都可以被当成堆空间来使用。

String str = new String(“hello”);

上面的语句中str放在栈上,用new创建出来的字符串对象放在堆上,而“hello”这个字面量放在静态存储区。

Math.round(11.5) 等于多少? Math.round(-11.5)等于多少?

答:Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加0.5然后进行下取整 (+0.5)

用最有效率的方法计算2乘以8?

答: 2 << 3(左移3位相当于乘以2的3次方,右移3位相当于除以2的3次方)。

31 * num <==> (num << 5) - num,左移5位相当于乘以2的5次方(32)再减去自身就相当于乘以31

构造器(constructor)是否可被重写(override)?

答:构造器不能被继承,因此不能被重写,但可以被重载。

String s=new String(“xyz”);创建了几个字符串对象?

答:两个对象,一个是静态存储区的"xyz",一个是用new创建在堆上的对象。

接口是否可继承(extends)接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)?

答:接口可以继承接口。抽象类可以实现(implements)接口,抽象类可继承具体类,但前提是具体类必须有明确的构造函数。

如何实现字符串的反转及替换?

答:方法很多,可以自己写实现也可以使用String或StringBuffer / StringBuilder中的方法。有一道很常见的面试题是用递归实现字符串反转,代码如下所示:

public static String reverse(String originStr) { if(originStr == null || originStr.length() <= 1) return originStr; return reverse(originStr.substring(1)) + originStr.charAt(0); }

日期和时间:

1)如何取得年月日、小时分钟秒?

2)如何取得从1970年1月1日0时0分0秒到现在的毫秒数?

3)如何取得某月的最后一天?

4)如何格式化日期?

答:操作方法如下所示:

1)创建java.util.Calendar 实例,调用其get()方法传入不同的参数即可获得参数所对应的值

2)以下方法均可获得该毫秒数:

Calendar.getInstance().getTimeInMillis(); System.currentTimeMillis(); //何问起 hovertree.com3)示例代码如下:

Calendar time = Calendar.getInstance(); time.getActualMaximum(Calendar.DAY_OF_MONTH); //何问起 hovertree.com4)利用java.text.DataFormat 的子类(如SimpleDateFormat类)中的format(Date)方法可将日期格式化。

42、打印昨天的当前时刻。

答:

public class YesterdayCurrent { public static void main(String[] args){ Calendar cal = Calendar.getInstance(); cal.add(Calendar.DATE, -1); System.out.println(cal.getTime()); }

Java 语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用?

答:Java 通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java 中,每个异常都是一个对象,它是Throwable 类或其子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。Java 的异常处理是通过5 个关键词来实现的:try、catch、throw、throws和finally。一般情况下是用try来执行一段程序,如果出现异常,系统会抛出(throw)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺省处理器来处理;try用来指定一块预防所有“异常”的程序;catch 子句紧跟在try块后面,用来指定你想要捕捉的“异常”的类型;throw 语句用来明确地抛出一个“异常”;throws用来标明一个成员函数可能抛出的各种“异常”;finally 为确保一段代码不管发生什么“异常”都被执行一段代码;可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部写另一个try语句保护其他代码。每当遇到一个try 语句,“异常”的框架就放到栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种“异常”进行处理,栈就会展开,直到遇到有处理这种“异常”的try 语句。

网络协议

TCP,UDP,HTTP

在网络层,有 IP 协议、ICMP 协议、ARP 协议、RARP 协议等。在传输层,有 TCP 协议与 UDP 协议。在应用层,有 WebSocket、FTP、HTTP、TELNET、SMTP、DNS 等协议。而 HTTPS 可以理解为更安全的 HTTP 协议。

因此,TCP、UDP、HTTP、HTTPS 都是通信协议,只不过它们所在的层级不同,负责的工作也不同,并且 HTTP 是基于 TCP 实现的。

Socket 通信

Socket 是为了实现以上的通信过程而建立成来的通信管道,其真实的代表是客户端和服务器端的一个通信进程,双方进程通过 Socket 进行通信,而通信的规则采用指定的协议。Socket 只是一种连接模式,不是协议。

设计模式

设计模式六大原则

单一原则: 一个类只负责一项职责,尽量做到类只有一个行为原因引起变化

里氏替换原则::子类可以扩展父类的功能,但不能改变原有父类的功能;

依赖倒置原则 : 面向接口编程;

接口隔离 :建立单一接口

迪米特原则: 最少知道原则,尽量降低类与类之间的耦合;

开闭原则:用抽象构建架构,用实现扩展原则;

工厂模式

工厂模式提供了一种将对象的实例化过程封装在工厂类中的方式。通过使用工厂模式,可以将对象的创建与使用代码分离,提供一种统一的接口来创建不同类型的对象。

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

主要解决:主要解决接口选择的问题。

何时使用:我们明确地计划不同条件下创建不同实例时。

如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。

关键代码:创建过程在其子类执行。

应用实例: 1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。 2、Hibernate 换数据库只需换方言和驱动就可以。

优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

工厂模式包含以下几个核心角色:

  • 抽象产品(Abstract Product):定义了产品的共同接口或抽象类。它可以是具体产品类的父类或接口,规定了产品对象的共同方法。

  • 具体产品(Concrete Product):实现了抽象产品接口,定义了具体产品的特定行为和属性。

  • 抽象工厂(Abstract Factory):声明了创建产品的抽象方法,可以是接口或抽象类。它可以有多个方法用于创建不同类型的产品。

  • 具体工厂(Concrete Factory):实现了抽象工厂接口,负责实际创建具体产品的对象。

单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

  • 1、单例类只能有一个实例。

  • 2、单例类必须自己创建自己的唯一实例。

  • 3、单例类必须给所有其他对象提供这一实例。

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

主要解决:一个全局使用的类频繁地创建与销毁。

何时使用:当您想控制实例数目,节省系统资源的时候。

如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

关键代码:构造函数是私有的

  • 、一个班级只有一个班主任。

  • 2、Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。

  • 3、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。

SpringMVC

工作原理

用户向服务器发送请求,被springMVC前端控制器捕获,前端控制器对请求URL进行解析后将请求映射到处理器。

springmvc常用注解

@requestMapping 用于请求url映射
@RequestBody 注解实现接收http请求的json数据,转java对象
@ResponseBady 注解实现将controller方法返回对象转化为json响应给用户

开启注解处理器和适配器

在springmvc.xml中通过<mvc:annotation-driven>开启

get和post乱码

post请求web.xml中配置CharacterEncodingFilter过滤器,设置为utf-8
get请求:1.修改tomcat配置文件,添加编码和工程编码一致
2.对参数进行重新编码 String userName = New String()

spring容器

spring,IOC,AOP

IOC 控制反转:Spring IOC 负责创建对象,管理对象。通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期

优点:IOC 或 依赖注入把应用的代码量降到最低。它使应用容易测试,单元测试不再需要单例和 JNDI 查找机制

spring是一个IOC和AOP容器框架
spring容器的主要核心是:
控制反转(IOC):在 spring 开发模式中,spring 容器使用了工厂模式为我们创建了所需要的对象,不需要我们自己创建,可以直接调用
依赖注入(DI):spring 使用 javaBean 对象的 set 方法或者带参数的构造方法为我们在创建所需对象时将其属性自动设置所需要的值的过程
面向切面编程(AOP):将许多对象相似的方面横向抽成一个切面,对这个切面进行一些如权限控制,事务管理,记录日志等公用操作的处理过程

spring注解

Spring 在 2.5 版本以后开始支持注解的方式来配置依赖注入。可以用注解的方式来代替 xml 中 bean 的描述。注解注入将会被容器在 XML 注入之前被处理,所以后者会覆盖掉前者对于同一个属性的处理结果。

注解装配在 spring 中默认是关闭。<context:annotation-config /》

spring作用

a.Spring 根据配置文件来进行创建及组装对象间依赖关系,只需要改配置文件即可
b.Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制
c.采用 Spring,我们只需获取连接,执行 SQL,其他事物相关的都交给 Spring 来管理
d.Spring 还能与第三方数据库访问框架(如 Hibernate、JPA)无缝集成,第三方 Web(如 Struts、JSF)框架无缝集成

springjdbc,springDAO,springORM

Spring-JDBC 提供了 Jdbc 模板类,它移除了连接代码以帮你专注于 SQL 查询和相关参数
Spring-DAO 并非 Spring 的一个模块,它实际上是指示你写 DAO 操作、写好 DAO 操作的一些规范
Spring-ORM 是一个囊括了很多持久层技术(JPA,JDO,Hibernate,iBatis)的总括模块

spring配置文件

Spring 配置文件是个 XML 文件,这个文件包含了类信息,描述了如何配置它们,以及如何相互调用

Spring 的依赖注入

依赖注入的另一种说法是“控制反转”,通俗的理解是:平常我们 new 一个实例,这个实例的控制权是我们程序员,而控制反转是指 new 实例工作不 由我们程序员来做而是交给 spring 容器来做

IOC(依赖注入)方式

  1. set注入

  2. 构造器注入

  3. 静态工厂注入

  4. 实例工厂注入

基于 Java 的 Spring 注解配置

允许你在少量的 Java 注解的帮助下,进行你的大部分 Spring 配置而非通过 XML 文件
以@Configuration 注解为例,它用来标记类可以当做一个 bean 的定义,被 Spring IOC 容器使用。另一个例子是 @Bean 注解,它表示此方法将要返回一个对象,作为一个 bean 注册进 Spring 应用上下文。

基于注解的容器配置

在 Spring 配 置 文 件 中 配 置 context:annotation-config/元素 开启

Spring 的通知是什么?

通知是个在方法执行前或执行后要做的动作,实际上是程序执行时要通过 SpringAOP 框架触发的代码段。
before:前置通知,在一个方法执行前被调用。
after: 在方法执行之后调用的通知,无论方法执行是否成功。
after-returning: 仅当方法成功完成后执行的通知
after-throwing: 在方法抛出异常退出时执行的通知
around: 在方法执行之前和之后调用的通知。

mybatis

#和$的区别

#相当于对数据 加上 双引号,$相当于直接显示数据

#。如:order by #user_id#,如果传入的值是 111,那么解析成 sql 时的值为 order by "111",
$。如:order by $user_id$,如果传入的值是 id,则解析成的 sql 为 order by id.

#方式能够很大程度防止 sql 注入

一般能用#的就别用$

̕Mybatis 的编程步骤

1、创建 SqlSessionFactory

2、通过 SqlSessionFactory 创建 SqlSession

3、通过 sqlsession 执行数据库操作

4、调用 session.commit()提交事务

5、调用 session.close()关闭会话

public class Demo {
  public static void main(string[] args) throws Exception {
        // 读取mybatis-config.xml 文件
        Inputstream input = Resoutces.getResources.getResourceAstream("mybatis-config.xm");
        // 初始化mybatis,创建SqlsessionFactory类的实例
        SqlsessionFactory sql = new SqlSessionFactoryBuilder.build(input);
        // 创建session实列
        SqlSession session = SqlSessionFactory.openSession();    
        ManyToManyTest t = new ManyToManyTest();    
        // 根据用户id查询用户,测试一对多关系
        t.testSelectUserById(session);
        // 根据订单id查询订单,测试多对多关系
        t.testSelectOrderById(session) ;
        // 提交事务
        session.commit();
        // 关闭session
        session.close();
    }
}

mybatis解决jdbc

  1. 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。

解决:在 SqlMapConfig.xml 中配置数据链接池,使用连接池管理数据库链接。

  1. Sql 语句写在代码中造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java 代码。

解决:将 Sql 语句配置在 XXXXmapper.xml 文件中与 java 代码分离。

Mybatis 自动将 java 对象映射至 sql 语句。

Mybatis 自动将 sql 执行结果映射至 java 对象。、

使用 MyBatis 的 mapper 接口调用

  1. 接口方法名和xml中定义的sql的id相同

  2. 接口方法的输入和输出参数和xml定义的类型相同

  3. Mapper.xml 文件中的 namespace 即是 mapper 接口的类路径

分布式

负载均衡实现

选择合适的负载均衡算法:包括轮询、随机、加权轮询、加权随机、最小连接数等
搜集服务器信息:搜集服务器的IP地址、端口号、健康状态、负载等信息,并记录在负载均衡器中。
分发请求:根据负载均衡算法,将客户端请求分发到多个服务器上。
处理响应:当服务器处理完请求后,将响应返回到负载均衡器。

redis

redis是内存高速缓存数据库,用 C 语言编写,典型的 NoSQL 数据库服务器

Redis 是一 个 key-value 存储系统,它支持丰富的数据类型,如:string、list、set、zset(sorted set)、hash

redis把数据库统统加载在内存当中进 行操作,是纯内存操作,Redis 的性能非常出色,是已知性能最快的 Key-Value DB

单 个 value 的最大限制是 1GB,不像 memcached 只能保存 1MB 的数据

Redis 的主要缺点是数据库容量受到物理内存的限制

redis存储方式

redis把数据都读到内存中,并通过异步的方式将数据写入磁盘。。所以 redis 具有快速和 数据持久化的特征

如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。

redis常见问题

master写内存快照

当快照比较大时对性能影响是 非常大的,会间断性暂停服务

Redis 主从复制的性能问题

为了主从复制的速度和连接的稳定性,Slave 和 Master 最好在同一个局域 网内

主从复制,主机数据更新后根据配置和策略,自动同步到备份机的master/alave 机制,Master以写为主,Slave以读为主

Master AOF 持久化

Master 最好不要做任何持久化工作,包括内存快照和 AOF 日 志文件

如果数据比较关键,某个 Slave 开启 AOF 备份数据,策略为每秒同步一次

AOF是记录每一条写操作命令,之后恢复数据库的时候再把命令都执行一遍。

RDB是记录一瞬间redis数据库的所有数据,以二进制格式记录。这样会恢复的很快。

rdeis的rdb是是全量快照,也就是说对所有数据进行快照,但是很费时间
​
redis提供了两个命令:save,在主线程中执行,会导致阻塞;
bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是Redis RDB 文件生成的默认配置
​
在做快照时也可以对数据进行增删改

Master 调用 BGREWRITEAOF 重写 AOF 文件

AOF 在重写的时候会占大量的 CPU 和内存资源,导致服 务 load 过高,出现短暂服务暂停现象。

redis适用场景

会话缓存(Session Cache)

全页缓存(FPC)

队列

排行榜/计数器

发布/订阅

Memcache 与 Redis 的区别

memcache是一套分布式的高速缓存系统

1.存储方式不同
Memcache 是把数据全部存在内存中,断电后数据库会挂掉
Redis 有部分存在硬盘上,这样能保证数据的持久性
2.数据支持的类型不同 
memcahe 对数据类型支持相对简单,redis 有复杂的数据类型
3.支持的 value 大小不一样 
redis 最大可以达到 1GB,而 memcache 只有 1MB。
redis数据结构

string字符串 --简单的 key-value 类型

Hash字典

将结构化的信息打包成 hashmap,在客户端序列化后存储为一个字符串的值 (一般是 JSON 格式),比如用户的昵称、年龄

List列表 --redis 使用双端链表实现的 List

Set集合 --是一堆不重复值的组合

Sorted Set有序集合 将 Set 中的元素增加了一个权重参数 score

redis优缺点

优点

性能极高 100k+每秒

丰富的数据类型

原子性操作

把这种要么一起成功(A 帐户成功减少 1000,同时 B 帐户成 功增加 1000),要么一起失败(A 帐户回到原来状态,B 帐户也回到原来状态)的操作叫原子性操作
如果把一个事 务可看作是一个程序,它要么完整的被执行,要么完全不执行,这种特性就叫原子性。

丰富的特性 – Redis 还支持 publish/subscribe, 通知, key 过期等等特性

缺点

内存数据库 可能需要定期删除数据,预估和节约内存

修改配置文件,需要重启,将硬盘的数据加载进内存,时间较久,在这个过程中,redis 不能 提供服务

redis持久化

AOF持久化是记录每一条写操作命令,之后恢复数据库的时候再把命令都执行一遍。

优点

AOF会让redis非常耐久,默认是每秒fsync一次。fsync 会在后台 线程执行,不占有太多资源。AOF 文件是一个只进行追加操作的日志文件。redis-check-aof 工具能解决磁盘已满,写入中途停机等问题

当AOF文件过大自动重写,恢复当前数据集所需的最小命令集合,重写操作绝对安全:即使重写过程中发生停机,现有的 AOF 文件也不会丢失

缺点

对于相同数据集,AOF文件要大于RDB,速度慢于RDB。在处理巨大写入载入时,RDB 可以提供更有保证的最大延迟时间

AOF在小概率出现: 因为个别命令的原因,导致 AOF 文件在重新载入时,无法将数据集恢复 成保存时的原样。的BUG

RDB持久化是记录一瞬间redis数据库的所有数据,以二进制格式记录。这样会恢复的很快。

优点

它保存了 Redis 在某个时间点上的数据集 ,非 常适合用于进行备份,也可以随时将数据集还原到不同的版本

RDB 非常适 用于灾难恢复,可以在加密后传送到数据中心

RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。

RDB恢复大数据集时的速度比 AOF 的恢复速度要快

缺点

不能用于尽量避免丢失数据的服务器。因为保存是需要时间间隔的,如果发生故障,会丢失未保存的数据

fork可能会非常耗时,造成服务器停止处理客户端几毫秒。每次保存 RDB 的时候,Redis 都要 fork() 出一个子进程,并由子 进程来进行实际的持久化工作

同时应用 AOF 和 RDB:当 Redis 重启时, 它会优先使用 AOF 文件来还原数据集, 因为 AOF 文件保存的 数据集通常比 RDB 文件所保存的数据集更完整。

死锁

指多个线程同时被阻塞,其中一个或者全部线程都在等待某个资源,由于资源争夺而造成的一中僵局。若无外力推进,他们都将无法推进。由于无限期的阻塞,程序没有办法进行正常终止。

死锁产生的必要条件

  • 互斥使用

  • 不可剥夺

  • 请求和保持

  • 循环等待

产生原因

  • 资源竞争:当多个进程共享资源,如果资源数目小于进程数,形成资源竞争,造成死锁

  • 竞争不可剥夺资源:如果系统分配的不可剥夺资源数目小于进程所需,就会造成资源竞争,形成僵局。

  • 进程推进顺序不合法

预防死锁

通过设置限制条件,破坏死锁的必要条件

  • 一次性分配所有资源,这样就不会再请求资源了

  • 只要有一个资源得不到分配,也不给该进程分配其他资源

  • 当某进程获得了部分资源,但得不到其它资源,则释放已占有的资源

  • 系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反

避免死锁

在资源分配时,使用某种方法避免系统进入不安全的状态。

银行家算法

它最初是为银行设计的(因此得名),通过判断借贷是否安全,然后决定借不借。

在银行中,客户申请贷款的数量是有限的,每个客户在第一次申请贷款时要声明完成该项目所需的最大资金量,在满足所有贷款要求时,客户应及时归还。银行家在客户申请的贷款数量不超过自己拥有的最大值时,都应尽量满足客户的需要。用在操作系统中,银行家、出借资金、客户,就分别对应操作系统、资源、申请资源的进程。

每一个新进程进入系统时,必须声明需要每种资源的最大数目,其数目不能超过系统所拥有的的资源总量。当进程请求一组资源时,系统必须首先确定是否有足够的资源分配给该进程,若有,再进一步计算在将这些资源分配给进程后,是否会使系统处于不安全状态如果不会才将资源分配给它,否则让进程等待。

数据结构

  • 可利用资源向量Available

是一个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目。如果Available[j]=K,则表示系统中现有Rj类资源K个。

  • 最大需求矩阵Max

这是一个n×m的矩阵,定义了系统中n个进程中的每一个进程对m类资源的最大需求。如果Max[i,j]=K,则表示进程i需要Rj类资源的最大数目为K。

  • 分配矩阵Allocation

这是一个n×m的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。如果Allocation[i,j]=K,则表示进程i当前已分得Rj类资源的 数目为K。

  • 需求矩阵Need

这是一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j]=K,则表示进程i还需要Rj类资源K个。

多线程

Mysql

SQL优化

避免使用子查询

例:

SELECT * FROM t1 WHERE id (SELECT id FROM t2 WHERE name = 'chackca');

采用join关联方式对其进行了优化

SELECT t1.* FROM t1 JOIN t2 on t1.id = t2.id

用in代替or
  • 低效查询:SELECT * FROM t WHERE id = 10 OR id = 20 OR id = 30;

  • 高效查询:SELECT * FROM t WHERE id IN (10,20,30);

读取适当的记录limit m,n。不要读多余的数据

对于 limit m, n 的分页查询,越往后面翻页(即m越大的情况下)SQL的耗时会越来越长

select id,name from t limit 866613, 20

sql可以采用如下的写法:

select id,name from table_name where id> 866612 limit 20
禁止不必要的order by排序

如果我们对结果没有排序的要求,就尽量少用排序;

如果排序字段没有用到索引,也尽量少用排序;

另外,分组统计查询时可以禁止其默认排序

SELECT goods_id,count(*) FROM t GROUP BY goods_id;

默认情况下,Mysql会对所有的GROUP BT col1,col2…的字段进行排序,也就是说上述会对 goods_id进行排序,如果想要避免排序结果的消耗,可以指定ORDER BY NULL禁止排序:

SELECT goods_id,count(*) FROM t GROUP BY goods_id ORDER BY NULL

少用select *

SELECT语句务必指明字段名称,select * 增加很多不必要的消耗(CPU、IO、内存、网络带宽);

将多次插入换成批量insert插入
INSERT INTO t(id, name) VALUES(1, 'aaa');
INSERT INTO t(id, name) VALUES(2, 'bbb');
INSERT INTO t(id, name) VALUES(3, 'ccc');
—>
INSERT INTO t(id, name) VALUES(1, 'aaa'),(2, 'bbb'),(3, 'ccc');
尽量使用数字型字段

若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能。引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

mysql有哪些索引

优点:提高数据检索的效率,降低数据排序的成本。缺点:会降低更新表的速度。

  1. B-树索引,使表中的每一行都会在索引上有一个对应值;

  2. 哈希索引,可根据索引列对应的哈希值的方法获取表的记录行;

  3. 普通索引,允许在定义索引的列中插入重复值和空值;

  4. 唯一索引,可以避免数据出现重复;

  5. 主键索引,是为主键字段创建的索引;

  6. 空间索引,是对空间数据类型的字段建立的索引;

  7. 全文索引,用来查找文本中的关键字;

  8. 单列索引,即索引只包含原表的一个列。

操作

insert
insert into 表名(字段1,字段2[,...]) values (字段1的值,字段2的值,...);
insert into lx1 (id,name) values (1,2)
​
    例子:
insert into 表名 (id,name,score,passwd) values (1,'自定义',70.5,passwd('123456')) ;
 
passwd('123456') :查询数据记录时,密码字串以加密形式显示:若不使用passwd(), 查询时以明文显示

update
​
update 表名 set 字段名1=字段值1[,字段名2=字段值2] [where 条件表达式];
​
update lx1 set name='12',id='12' where id=1
​
例子:
update 表名 set passwd=PASSWORD('') where name='自定义';

delete
​
delete from 表名 [where 条件表达式];
​
delete from lx1 where id=12
​
例子
delete from 表名 where id=4;

select
格式:
 
select 字段名1,字段名2[,...] from 表名[where 条件表达式];
 
例子:
select * from 表名;
select id, name from 表名;
select id, name, score from 表名 where id=2;
 
select name from 表名\G          以列表方式竖向显示
select * from info limit 2;      只显示前3行
select * from info limit 2,3;    显示第3行后的前3行

高级操作
use 数据库名;
create table if not exists info (
id int(4) zerofill primary key auto_increment,
name varchar(10) not null,
cardid int(18) not null unique key, 
hobby varchar (50));
 
if not exists:表示检测要创建的表是否已存在,如果不存在就继续创建
 
int(4) zerofill: 表示若数值不满4位数,则前面用"0"填充,例0001
 
auto_ increment: 表示此字段为自增长字段,即每条记录自动递增1,默认从1开始递增; 自增长字段数据不可以重复;自增长字段必须是主键;如添加的记录数据没有指定此字段的值且添加失败也会自动递增一次
 
funique key: 表示此字段唯一键约束, 此字段数据不可以重复:一张表中只能有一个主键,但是一张表中可以有多个唯一键
 
​
if not exists:表示检测要创建的表是否已存在,如果不存在就继续创建
not null: 表示此字段不允许为NULL

表复制
create table test1 like test;
复制格式,通过like方法,复制数据库里的表结构生成另一个表
 
insert into test1 select * from test;
备份内容
克隆表,将数据表的数据记录生成到新的表中
 
create table test02 (select * from test);  复制test表数据到test02中
 
show create table test02\G
获取数据表的表结构、索引等信息
 
select * from test02

接口

spring boot jpa

1.yml文件

2.实体类

3.具体操作类接口

@Query注解使用方法

常用属性

value : 取值,要么使用原生SQL,要么使用JPQL

nativeQuery :表示是否采用原生SQL,诸如select * from tableName

@Modifying
@Transactional
@Query("update User set email = ?1 where id = ?2")
void updateUser(String email,Integer id);  //改
​
@Query(value = "delete from User where id = ?1")
void deleteByUserId(Integer id);           //删
​
@Query(value = "select * from tb_user  where  email like concat('%',?2,'%') and username like concat('%',?1,'%') ",nativeQuery = true)
User findByUsernameAndEmail( String username, String email);
                                           //查
​
@Query(value = "insert into tb_user(email,id_card,username,wage) values (:email,:idCard,:username,:wage)",nativeQuery = true)
void insertUser(String email,String idCard,String username,Double wage);                     //增
​
4.Controller控制展示类

@Resource注解就是在实现类中注入接口(表明这个就是接口的实现类)

@Resource:java的注解,属性较多,默认的注入方式为byName(根据名称进行匹配),type无法分辨时,可以根据name分辨,通过name属性来显式指定Bean名称。@Autowired:spring的注解,一个属性,默认的注入方式为byType(根据类型进行匹配),type无法分辨时,可以根据name分辨,变量名称要与Bean名称一致,也可以通过@Qualifier 注解来显式指定Bean名称,

例子,有两个苹果,一个叫哈哈,一个叫呵呵,你指着两个苹果,意思是去拿个苹果,让@Resource去拿,如果不说明,他懵了,但是你说明拿叫哈哈的那个,他就知道了,给你拿来了,让@Autowired去拿,如果不说明,他也懵了,但是他又是个聋子,听不到你说的,结果就拿不到,但是如果写了个字条(@Qualifier)写明拿呵呵,他也就知道了。
另外的情况就是,不管是@Resource或者@Autowired,如果你指苹果的时候就指的很明确,直接指到叫哈哈的苹果,他们也都能拿到(变量名称跟bean一样)。

idea项目目录结构

后台查询数据并提供接口的流程如下:

数据库查询数据,将数据返回成json方式,通过json方式返回前台,然后前台进行渲染具体流程(用于理解):1.在properties文件中配置数据链接,驱动,2.然后定义entity包,包中对象与数据库表一一对应,对象中成员与表中字段一一对应3.然后是mapper包,注意该包需要在demoApplication中配置包路径。 mapper包中对象就是接口,提供各种功能的接口,供controller调用4.在controller包中对象里声明@RestController,并定义路径, 然后通过@Resourse方式引进来,也就是从spring容器中引进来, 引进来后就可以直接调用其方法,返回一个对象,这个对象存储了从后台读到的数据

mapper包中对象--接口

在demoApplication中配置包路径

@Data注解代替get和set方法

@RestController注解

表示这个借口查询出来的数据都会被渲染成json返回前台

@RequestBody注解

把传过来的json数据解析包装成user实体

POST/PUT/DELETE请求

mapper中接口

根据id查询数据库信息

controller

接口

分页查询

controller

mapper接口

spring boot基本结构

1.配置application.yml文件

2.建立实体类,与数据库表字段一致(在entity包中)

只做数据库映射

3.创建mapper接口

在接口中定义方法,并将sql语句写在resource里mapper中的xml文件里

和数据库匹,比如要做的insert操作...

mapper接口

xml文件

要在application.yml中说明mybatis配置的xml文件在哪

4.建立service层对mapper接口查询的数据进行处理

做业务逻辑的,比如做些操作,计算

5.在controller中实例化service层的方法

只给前端交互,做展示

Ajax

是一种异步无刷新的技术

AJAX即“Asynchronous Javascript And XML”(异步的JavaScript和XML),是指一种创建交互式网页应用的网页开发技术,用于浏览器和服务器之间进行数据交互。
AJAX在浏览器与Web服务器之间使用异步数据传输(HTTP请求),这样就可使网页从服务器请求少量的信息,而不是整个页面。AJAX描述了一种主要使用脚本操作HTTP的Web应用架构,AJAX应用的主要特点是使用脚本操纵HTTP和Web服务器进行数据交换,不会导致页面重载。
对AJAX的印象:
AJAX是异步的JavaScript和XML;
AJAX是一种用于创建更好更快以及交互性更强的Web应用程序的技术;
AJAX是一种独立于Web服务器软件的浏览器技术;
AJAX不是一种新的编程语言,而是一种技术;
AJAX 使用 JavaScript 在 web 浏览器与 web 服务器之间来发送和接收数据(前端后端交互);
AJAX在浏览器与Web服务器之间使用异步数据传输(HTTP请求)。

$.ajax

html实际操作

点击按钮,发送ajax请求,将数据显示到页面中

html页面

需要显示的数据

$.get和$.post

html实例

$.getJSON

实例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值