Created
June 25, 2021 02:59
-
-
Save 1726242034/a7899c6bd41f04fd9bb5a182ee738c66 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| cloud computing | |
| 云计算是基于互联网的相关服务的增加、使用和交付模式,通常涉及通过互联网来提供动态易扩展且经常是虚拟化的资源。 | |
| 云是网络、互联网的一种比喻说法。过去在图中往往用云来表示电信网,后来也用来表示互联网和底层基础设施的抽象。 | |
| 因此,云计算甚至可以让你体验每秒10万亿次的运算能力,拥有这么强大的计算能力可以模拟核爆炸、预测气候变化和市场发展趋势。 | |
| 用户通过电脑、笔记本、手机等方式接入数据中心,按自己的需求进行运算。 | |
| 美国国家标准与技术研究院(NIST)定义:云计算是一种按使用量付费的模式,这种模式提供可用的、便捷的、按需的网络访问, | |
| 进入可配置的计算资源共享池(资源包括网络,服务器,存储,应用软件,服务),这些资源能够被快速提供,只需投入很少的管理工作, | |
| 或与服务供应商进行很少的交互。XenSystem,以及在国外已经非常成熟的Intel 和IBM,各种“云计算”的应用服务范围正日渐扩大,影响力也无可估量 | |
| 不同的“云”对应着不同的基础设施。下面是三种广义的“云”: | |
| 基础设施即服务(IaaS) | |
| 平台即服务(PaaS) | |
| 软件即服务(SaaS) | |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | |
| openstack介绍、架构 | |
| OpenStack是(infrastructure as a service,基础设置即服务)IAAS架构的实现。 | |
| OpenStack是一个开源的云计算管理平台项目,由几个主要的组件组合起来完成具体工作。 | |
| OpenStack支持几乎所有类型的云环境,项目目标是提供实施简单、可大规模扩展、丰富、标准统一的云计算管理平台 | |
| OpenStack通过各种互补的服务提供了基础设施即服务(IaaS)的解决方案,每个服务提供API以进行集成。 | |
| OpenStack包含两个主要模块:Nova 和 Swift | |
| 整个OpenStack是由控制节点,计算节点,网络节点,存储节点四大部分组成。 | |
| 控制节点架构: | |
| 控制节点负责对其余节点的控制,包含虚拟机建立,迁移,网络分配,存储分配等等 | |
| 控制节点包括以下服务 | |
| 管理支持服务 | |
| 管理支持服务包含MySQL与Qpid两个服务 | |
| MySQL:数据库作为基础/扩展服务产生的数据存放的地方 | |
| Qpid:消息代理(也称消息中间件)为其他各种服务之间提供了统一的消息通信服务 | |
| 基础管理服务 | |
| 基础管理服务包含Keystone,Glance,Nova,Neutron,Horizon五个服务 | |
| Keystone:认证管理服务,提供了其余所有组件的认证信息/令牌的管理,创建,修改等等,使用MySQL作为统一的数据库 | |
| Glance:镜像管理服务,提供了对虚拟机部署的时候所能提供的镜像的管理,包含镜像的导入,格式,以及制作相应的模板 | |
| Nova:计算管理服务,提供了对计算节点Nova的管理,使用Nova-API进行通信 | |
| Neutron:网络管理服务,提供了对网络节点的网络拓扑管理,同时提供Neutron在Horizon的管理面板 | |
| Horizon:控制台服务,提供了以Web的形式对所有节点的所有服务的管理,通常把该服务称为DashBoard | |
| 扩展管理服务 | |
| 扩展管理服务包含Cinder,Swift,Trove,Heat,Centimeter五个服务 | |
| Cinder:提供管理存储节点的Cinder相关,同时提供Cinder在Horizon中的管理面板 | |
| Swift:提供管理存储节点的Swift相关,同时提供Swift在Horizon中的管理面板 | |
| Trove:提供管理数据库节点的Trove相关,同时提供Trove在Horizon中的管理面板 | |
| Heat:提供了基于模板来实现云环境中资源的初始化,依赖关系处理,部署等基本操作,也可以解决自动收缩,负载均衡等高级特性。 | |
| Centimeter:提供对物理资源以及虚拟资源的监控,并记录这些数据,对该数据进行分析,在一定条件下触发相应动作 | |
| 控制节点一般来说只需要一个网络端口用于通信/管理各个节点 | |
| 计算节点架构 | |
| 计算节点负责虚拟机运行 | |
| 计算节点包含Nova,Neutron,Telemeter三个服务 | |
| 基础服务 | |
| Nova:提供虚拟机的创建,运行,迁移,快照等各种围绕虚拟机的服务,并提供API与控制节点对接,由控制节点下发任务 | |
| Neutron:提供计算节点与网络节点之间的通信服务 | |
| 扩展服务 | |
| Telemeter:提供计算节点的监控代理,将虚拟机的情况反馈给控制节点,是Centimeter的代理服务 | |
| 计算节点包含最少两个网络端口 | |
| eth0:与控制节点进行通信,受控制节点统一调配 | |
| eth1:与网络节点,存储节点进行通信 | |
| 网络节点架构 | |
| 网络节点负责对外网络与内网络之间的通信 | |
| 网络节点仅包含Neutron服务 | |
| Neutron:负责管理私有网段与公有网段的通信,以及管理虚拟机网络之间的通信/拓扑,管理虚拟机之上的防火等等 | |
| 网络节点包含三个网络端口 | |
| eth0:用于与控制节点进行通信 | |
| eth1:用于与除了控制节点之外的计算/存储节点之间的通信 | |
| eth2:用于外部的虚拟机与相应网络之间的通信 | |
| 存储节点架构 | |
| 存储节点负责对虚拟机的额外存储管理等等 | |
| 存储节点包含Cinder,Swift等服务 | |
| Cinder:块存储服务,提供相应的块存储,简单来说,就是虚拟出一块磁盘,可以挂载到相应的虚拟机之上, | |
| 不受文件系统等因素影响,对虚拟机来说,这个操作就像是新加了一块硬盘,可以完成对磁盘的任何操作, | |
| 包括挂载,卸载,格式化,转换文件系统等等操作,大多应用于虚拟机空间不足的情况下的空间扩容等等 | |
| Swift:对象存储服务,提供相应的对象存储,简单来说,就是虚拟出一块磁盘空间,可以在这个空间当中存放文件, | |
| 也仅仅只能存放文件,不能进行格式化,转换文件系统,大多应用于云磁盘/文件 | |
| 存储节点包含最少两个网络接口 | |
| eth0:与控制节点进行通信,接受控制节点任务,受控制节点统一调配 | |
| eth1:与计算/网络节点进行通信,完成控制节点下发的各类任务 | |
| openstack通过Nova调用KVM/XEN/VMWARE等虚拟机化技术创建虚拟机,即openstack是一个管理平台框架,支持众多的虚拟化管理, | |
| cinder存储支持GlusterFS、ISCSI、MFS等存储技术给虚拟机使用,即openstack不会绑定某一个应用,而是兼容众多的相关技术,因此火的一塌糊涂! | |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | |
| OpenStack认证服务(Keystone) | |
| OpenStack认证服务(Keystone) | |
| Keystone为所有的OpenStack组件提供认证和访问策略服务,它依赖自身REST(基于Identity API)系统进行工作, | |
| 主要对(但不限于)Swift、Glance、Nova等进行认证与授权。事实上,授权通过对动作消息来源者请求的合法性进行鉴定。 | |
| 重要组成: | |
| 服务器: 一个中心化的服务器使用RESTFul接口来提供认证和授权服务。 | |
| Drivers: 驱动或服务后端被整合进集中式服务器中。它们被用来访问OpenStack外部仓库的身份信息, | |
| 并且它们可能已经存在于OpenStack被部署在的基础设施(例如,SQL数据库或LDAP服务器)中。 | |
| Modules: 中间件模块运行于使用身份认证服务的OpenStack组件的地址空间中。这些模块拦截服务请求, | |
| 取出用户凭据,并将它们送入中央是服务器寻求授权。中间件模块和OpenStack组件间的整合使用Python Web服务器网关接口。 | |
| Keystone采用两种授权方式,一种基于用户名/密码,另一种基于令牌(Token)。除此之外,Keystone提供以下三种服务: | |
| 令牌服务:含有授权用户的授权信息 | |
| 目录服务:含有用户合法操作的可用服务列表 | |
| 策略服务:利用Keystone具体指定用户或群组某些访问权限 | |
| keystone认证服务注意点: | |
| 服务入口:如Nova、Swift和Glance一样每个OpenStack服务都拥有一个指定的端口和专属的URL,我们称其为入口(endpoints)。 | |
| 区位:在某个数据中心,一个区位具体指定了一处物理位置。在典型的云架构中,如果不是所有的服务都访问分布式数据中心或服务器的话,则也称其为区位。 | |
| 用户:Keystone授权使用者 | |
| PS:代表一个个体,OpenStack以用户的形式来授权服务给它们。用户拥有证书(credentials),且可能分配给一个或多个租户。经过验证后,会为每个单独的租户提供一个特定的令牌。 | |
| 服务:总体而言,任何通过Keystone进行连接或管理的组件都被称为服务。举个例子,我们可以称Glance为Keystone的服务。 | |
| 角色:为了维护安全限定,就云内特定用户可执行的操作而言,该用户关联的角色是非常重要的。 | |
| PS:一个角色是应用于某个租户的使用权限集合,以允许某个指定用户访问或使用特定操作。角色是使用权限的逻辑分组,它使得通用的权限可以简单地分组并绑定到与某个指定租户相关的用户。 | |
| 租间:租间指的是具有全部服务入口并配有特定成员角色的一个项目。 | |
| PS:一个租间映射到一个Nova的“project-id”,在对象存储中,一个租间可以有多个容器。根据不同的安装方式,一个租间可以代表一个客户、帐号、组织或项目。 | |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | |
| OpenStack计算设施(Nova) | |
| OpenStack计算设施(Nova) | |
| Nova是OpenStack计算的弹性控制器。OpenStack云实例生命期所需的各种动作都将由Nova进行处理和支撑,这就意味着Nova以管理平台的身份登场, | |
| 负责管理整个云的计算资源、网络、授权及测度。虽然Nova本身并不提供任何虚拟能力,但是它将使用 libvirt API 与虚拟机的宿主机进行交互。 | |
| Nova通过Web服务API来对外提供处理接口,而且这些接口与Amazon的Web服务接口是兼容的。 | |
| 功能及特点: 实例生命周期管理、计算资源管理、网络与授权管理、基于REST的API、异步连续通信、支持各种宿主:Xen、XenServer/XCP、KVM、UML、VMware vSphere及Hyper-V | |
| Nova弹性云(OpenStack计算部件)包含以下主要部分: | |
| API Server(nova-api) | |
| API服务器提供了云设施与外界交互的接口,它是外界用户对云实施管理的唯一通道。通过使用web服务来调用各种EC2的API, | |
| 接着API服务器便通过消息队列把请求送达至云内目标设施进行处理。作为对EC2-api的替代,用户也可以使用OpenStack的原生API,我们把它叫做“OpenStack API”。 | |
| 接收和响应来自最终用户的计算API请求。此服务支持OpenStack计算服务API,Amazon EC2 API, | |
| 以及特殊的管理API用于赋予用户做一些管理的操作。它会强制实施一些规则,发起多数的编排活动,例如运行一个实例。 | |
| 消息队列(rabbit-mq server) | |
| OpenStack内部在遵循AMQP(高级消息队列协议)的基础上采用消息队列进行通信。Nova对请求应答进行异步调用, | |
| 当请求接收后便则立即触发一个回调。由于使用了异步通信,不会有用户的动作被长置于等待状态。例如, | |
| 启动一个实例或上传一份镜像的过程较为耗时,API调用就将等待返回结果而不影响其它操作,在此异步通信起到了很大作用,使整个系统变得更加高效。 | |
| 运算工作站(nova-compute) | |
| 运算工作站的主要任务是管理实例的整个生命周期。他们通过消息队列接收请求并执行,从而对实例进行各种操作。 | |
| 在典型实际生产环境下,会架设许多运算工作站,根据调度算法,一个实例可以在可用的任意一台运算工作站上部署。 | |
| 一个持续工作的守护进程,通过Hypervior的API来创建和销毁虚拟机实例。例如:XenServer/XCP 的 XenAPI、KVM 或 QEMU 的 libvirt、VMware 的 VMwareAPI | |
| 过程是蛮复杂的。最为基本的,守护进程同意了来自队列的动作请求,转换为一系列的系统命令如启动一个KVM实例,然后,到数据库中更新它的状态。 | |
| 网络控制器(nova-network) | |
| 网络控制器处理主机的网络配置,例如IP地址分配,配置项目VLAN,设定安全群组以及为计算节点配置网络。 | |
| 卷管理(nova-volume) | |
| 卷工作站管理基于LVM的 实例卷,它能够为一个实例创建、删除、附加卷,也可以从一个实例中分离卷。卷管理为何如此重要? | |
| 因为它提供了一种保持实例持续存储的手段,比如当结束一个 实例后,根分区如果是非持续化的,那么对其的任何改变都将丢失。 | |
| 可是,如果从一个实例中将卷分离出来,或者为这个实例附加上卷的话,即使实例被关闭,数据仍然保存其中。 | |
| 这些数据可以通过将卷附加到原实例或其他实例的方式而重新访问。 | |
| 因此,为了日后访问,重要数据务必要写入卷中。这种应用对于数据服务器实例的存储而言,尤为重要。 | |
| 调度器(nova-scheduler) | |
| 拿到一个来自队列请求虚拟机实例,然后决定那台计算服务器主机来运行它。 | |
| 调度器负责把nova-API调用送达给目标。调度器以名为“nova-schedule”的守护进程方式运行,并根据调度算法从可用资源池中恰当地选择运算服务器。 | |
| 有很多因素都可以影响调度结果,比如负载、内存、子节点的远近、CPU架构等等。强大的是nova调度器采用的是可插入式架构。 | |
| 目前nova调度器使用了几种基本的调度算法: | |
| 随机化:主机随机选择可用节点; | |
| 可用化:与随机相似,只是随机选择的范围被指定; | |
| 简单化:应用这种方式,主机选择负载最小者来运行实例。负载数据可以从别处获得,如负载均衡服务器。 | |
| nova-cert: 服务器守护进程向Nova Cert服务提供X509证书。用来为euca-bundle-image生成证书。仅仅是在EC2 API的请求中使用 | |
| nova-novncproxy: 提供一个代理,用于访问正在运行的实例,通过VNC协议,支持基于浏览器的novnc客户端。 | |
| nova-spicehtml5proxy: 提供一个代理,用于访问正在运行的实例,通过 SPICE 协议,支持基于浏览器的 HTML5 客户端。 | |
| nova-xvpvncproxy: 提供一个代理,用于访问正在运行的实例,通过VNC协议,支持OpenStack特定的Java客户端。 | |
| SQL数据库: 存储构建时和运行时的状态,为云基础设施,包括有:可用实例类型、使用中的实例、可用网络、项目 | |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | |
| OpenStack镜像服务(Glance) | |
| OpenStack镜像服务(Glance) | |
| OpenStack镜像服务是IaaS的核心服务。 | |
| 它接受磁盘镜像或服务器镜像API请求,和来自终端用户或OpenStack计算组件的元数据定义。它也支持包括OpenStack对象存储在内的多种类型仓库上的磁盘镜像或服务器镜像存储。 | |
| 大量周期性进程运行于OpenStack镜像服务上以支持缓存。同步复制(Replication)服务保证集群中的一致性和可用性。其它周期性进程包括auditors, updaters, 和 reapers。 | |
| OpenStack镜像服务包括以下组件: | |
| glance-api: 接收镜像API的调用,诸如镜像发现、恢复、存储。 | |
| glance-registry: 存储、处理和恢复镜像的元数据,元数据包括项诸如大小和类型。 | |
| 数据库: 存放镜像元数据,用户是可以依据个人喜好选择数据库的,多数的部署使用MySQL或SQLite。 | |
| 镜像文件的存储仓库: 支持各种存储库类型,包括普通文件系统(或安装在 Glance-api 控制器节点上的任何文件系统)、 | |
| 对象存储、RADOS块设备、VMware数据存储和HTTP。请注意,某些存储库仅支持只读使用. | |
| 元数据定义服务: 通用的API,是用于为厂商,管理员,服务,以及用户自定义元数据。这种元数据可用于不同的资源, | |
| 例如镜像,工件,卷,配额以及集合。一个定义包括了新属性的键,描述,约束以及可以与之关联的资源的类型。 | |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | |
| OpenStack网络服务(neutron) | |
| OpenStack网络服务(neutron) | |
| OpenStack Networking(neutron),允许创建、插入接口设备,这些设备由其他的OpenStack服务管理。插件式的实现可以容纳不同的网络设备和软件,为OpenStack架构与部署提供了灵活性。 | |
| 它包含下列组件: | |
| neutron-server: 接收和路由API请求到合适的OpenStack网络插件,以达到预想的目的。 | |
| OpenStack网络插件和代理: 插入和拔出端口,创建网络或子网,并提供IP寻址。这些插件和代理因特定云中使用的供应商和技术而异。 | |
| OpenStack Networking随附适用于Cisco虚拟和物理交换机、NEC OpenFlow产品、Open vSwitch、Linux桥接和VMware NSX产品的插件和代理。 | |
| 常见的代理L3(3层),DHCP(动态主机IP地址),以及插件代理。 | |
| 消息队列: 大多数的OpenStack Networking安装都会用到,用于在neutron-server和各种各样的代理进程间路由信息。 | |
| 也为某些特定的插件扮演数据库的角色,以存储网络状态。OpenStack网络主要和OpenStack计算交互,以提供网络连接到它的实例。 | |
| 网络(neutron)概念 | |
| 网络服务提供网络,子网以及路由这些对象的抽象概念。每个抽象概念都有自己的功能,可以模拟对应的物理设备:网络包括子网,路由在不同的子网和网络间进行路由转发。 | |
| 对于任意一个给定的网络都必须包含至少一个外部网络。不想其他的网络那样,外部网络不仅仅是一个定义的虚拟网络。相反,它代表了一种OpenStack安装之外的能从物理的, | |
| 外部的网络访问的视图。外部网络上的IP地址可供外部网络上的任意的物理设备所访问外部网络之外,任何 Networking 设置拥有一个或多个内部网络。 | |
| 这些软件定义的网络直接连接到虚拟机。仅仅在给定网络上的虚拟机,或那些在通过接口连接到相近路由的子网上的虚拟机,能直接访问连接到那个网络上的虚拟机。 | |
| 如果外部网络想要访问实例或者相反实例想要访问外部网络,那么网络之间的路由就是必要的了。每一个路由都配有一个网关用于连接到外部网络,以及一个或多个连接到内部网络的接口。 | |
| 就像一个物理路由一样,子网可以访问同一个路由上其他子网中的机器,并且机器也可以访问路由的网关访问外部网络。另外,你可以将外部网络的IP地址分配给内部网络的端口。 | |
| 不管什么时候一旦有连接连接到子网,那个连接被称作端口。你可以给实例的端口分配外部网络的IP地址。通过这种方式,外部网络上的实体可以访问实例。网络服务同样支持安全组。 | |
| 安全组允许管理员在安全组中定义防火墙规则。一个实例可以属于一个或多个安全组,网络为这个实例配置这些安全组中的规则,阻止或者开启端口,端口范围或者通信类型。 | |
| 每一个Networking使用的插件都有其自有的概念。虽然对操作VNI和OpenStack环境不是至关重要的,但理解这些概念能帮助你设置Networking。 | |
| 所有的Networking安装使用了一个核心插件和一个安全组插件(或仅是空操作安全组插件)。另外,防火墙即服务(FWaaS)和负载均衡即服务(LBaaS)插件是可用的。 | |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | |
| OpenStack管理的Web接口(Horizon) | |
| OpenStack管理的Web接口(Horizon) | |
| Dashboard(horizon)是一个web接口,使得云平台管理员以及用户可以管理不同的Openstack资源以及服务。 | |
| Horizon具有如下一些特点: | |
| 实例管理:创建、终止实例,查看终端日志,VNC连接,添加卷等 | |
| 访问与安全管理:创建安全群组,管理密匙对,设置浮动IP等 | |
| 偏好设定:对虚拟硬件模板可以进行不同偏好设定 | |
| 镜像管理:编辑或删除镜像 | |
| 查看服务目录 | |
| 管理用户、配额及项目用途 | |
| 用户管理:创建用户等 | |
| 卷管理:创建卷和快照 | |
| 对象存储处理:创建、删除容器和对象 | |
| 为项目下载环境变量 | |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | |
| OpenStack块存储服务(Cinder) | |
| OpenStack块存储服务(Cinder) | |
| 块存储服务(cinder)为实例提供块存储。存储的分配和消耗是由块存储驱动器,或者多后端配置的驱动器决定的。还有很多驱动程序可用:NAS/SAN,NFS,ISCSI,Ceph等。 | |
| 典型情况下,块服务API和调度器服务运行在控制节点上。取决于使用的驱动,卷服务器可以运行在控制节点、计算节点或单独的存储节点。 | |
| OpenStack块存储服务(cinder)为虚拟机添加持久的存储,块存储提供一个基础设施为了管理卷,以及和OpenStack计算服务交互,为实例提供卷。此服务也会激活管理卷的快照和卷类型的功能。 | |
| 块存储服务通常包含下列组件: | |
| cinder-api: 接受API请求,并将其路由到cinder-volume执行。 | |
| cinder-volume: 与块存储服务和例如cinder-scheduler的进程进行直接交互。它也可以与这些进程通过一个消息队列进行交互。 | |
| cinder-volume服务响应送到块存储服务的读写请求来维持状态。它也可以和多种存储提供者在驱动架构下进行交互。 | |
| cinder-scheduler守护进程: 选择最优存储提供节点来创建卷。其与nova-scheduler组件类似。 | |
| cinder-backup daemon: cinder-backup服务提供任何种类备份卷到一个备份存储提供者。就像cinder-volume服务,它与多种存储提供者在驱动架构下进行交互。 | |
| 消息队列: 在块存储的进程之间路由信息 | |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | |
| OpenStack存储服务(Swift) | |
| OpenStack存储服务(Swift) | |
| Swift为OpenStack提供一种分布式、持续虚拟对象存储,它类似于Amazon Web Service的S3简单存储服务。Swift具有跨节点百级对象的存储能力。 | |
| Swift内建冗余和失效备援管理,也能够处理归档和媒体流,特别是对大数据(千兆字节)和大容量(多对象数量)的测度非常高效。 | |
| Swift功能及特点:海量对象存储、大文件(对象)存储、数据冗余管理、归档能力-----处理大数据集、为虚拟机和云应用提供数据容器、 | |
| 处理流媒体、对象安全存储、备份与归档、良好的可伸缩性、Swift代理服务器 | |
| 用户都是通过Swift-API与代理服务器进行交互,代理服务器正是接收外界请求的门卫,它检测合法的实体位置并路由它们的请求。 | |
| 此外,代理服务器也同时处理实体失效而转移时,故障切换的实体重复路由请求。 | |
| Swift对象服务器 | |
| 对象服务器是一种二进制存储,它负责处理本地存储中的对象数据的存储、检索和删除。对象都是文件系统中存放的典型的二进制文件,具有扩展文件属性的元数据(xattr)。 | |
| 注意:xattr格式被Linux中的ext3/4,XFS,Btrfs,JFS和ReiserFS所支持, | |
| 但是并没有有效测试证明在XFS,JFS,ReiserFS,Reiser4和ZFS下也同样能运行良好。不过,XFS被认为是当前最好的选择。 | |
| Swift容器服务器 | |
| 容器服务器将列出一个容器中的所有对象,默认对象列表将存储为SQLite文件(译者注:也可以修改为MySQL,安装中就是以MySQL为例)。 | |
| 容器服务器也会统计容器中包含的对象数量及容器的存储空间耗费。 | |
| Swift账户服务器 | |
| 账户服务器与容器服务器类似,将列出容器中的对象。 | |
| Ring(索引环) | |
| Ring容器记录着Swift中物理存储对象的位置信息,它是真实物理存储位置的实体名的虚拟映射,类似于查找及定位不同集群的实体真实物理位置的索引服务。 | |
| 这里所谓的实体指账户、容器、对象,它们都拥有属于自己的不同的Rings。 | |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | |
| 其他服务 | |
| 其他服务 | |
| 裸金属服务(ironic): 裸金属服务是提供管理和准备物理硬件支持的组件的集合。 | |
| 容器的基础设施管理服务(magnum): 容器的基础设施管理服务(magnum)是OpenStack API服务,它使容器编排引擎(COE),成为了OpenStack头等资源。 | |
| 数据库服务(trove): 数据库服务(trove)提供了数据库引擎的云部署功能。 | |
| DNS service (designate): DNS 服务(指定)为 DNS 区域和记录集提供云配置功能。 | |
| 秘钥管理器服务: 密钥管理服务为存储提供了RESTful API,以及密钥数据,比如口令、加密密钥和X.509证书。 | |
| 云消息服务(zaqar): 云消息服务允许开发人员共享分布式应用组件间的数据来完成不同任务,而不会丢失消息或要求每个组件总是可用。 | |
| 对象存储服务(swift): 对象存储服务(swift)通过REST API提供对象存储和检索的访问入口。 | |
| 编排服务(heat): 编排服务 (heat) 使用 Heat 编排模板 (HOT) 来创建和管理云资源。 | |
| 共享文件系统服务(manila): 共享文件系统服务(manila)提供了共享或分布式文件系统的协同访问。 | |
| 监测告警服务(aodh): 当收集到的测量或事件数据符合预定义的规则时,监测告警服务就会触发告警。 | |
| Telemetry 数据收集服务(ceilometer) | |
| Telemetry 数据收集服务提供如下功能: | |
| 高效地轮询与 OpenStack 服务相关的计量数据。 | |
| 通过监测通知收集来自各个服务发送的事件和计量数据。 | |
| 将收集到的数据发布到各个目标区,包括数据存储区和消息队列。 | |
| 虚拟机创建过程: | |
| 1.界面或命令行通过RESTful API向keystone获取认证信息。 | |
| 2.keystone通过用户请求认证信息,并生成auth-token返回给对应的认证请求。 | |
| 3.界面或命令行通过RESTful API向nova-api发送一个boot instance的请求(携带auth-token)。 | |
| 4.nova-api接受请求后向keystone发送认证请求,查看token是否为有效用户和token。 | |
| 5.keystone验证token是否有效,如有效则返回有效的认证和对应的角色(注:有些操作需要有角色权限才能操作)。 | |
| 6.通过认证后nova-api和数据库通讯。 | |
| 7.初始化新建虚拟机的数据库记录。 | |
| 8.nova-api通过rpc.call向nova-scheduler请求是否有创建虚拟机的资源(Host ID)。 | |
| 9.nova-scheduler进程侦听消息队列,获取nova-api的请求。 | |
| 10.nova-scheduler通过查询nova数据库中计算资源的情况,并通过调度算法计算符合虚拟机创建需要的主机。 | |
| 11.对于有符合虚拟机创建的主机,nova-scheduler更新数据库中虚拟机对应的物理主机信息。 | |
| 12.nova-scheduler通过rpc.cast向nova-compute发送对应的创建虚拟机请求的消息。 | |
| 13.nova-compute会从对应的消息队列中获取创建虚拟机请求的消息。 | |
| 14.nova-compute通过rpc.call向nova-conductor请求获取虚拟机消息。(Flavor) | |
| 15.nova-conductor从消息队队列中拿到nova-compute请求消息。 | |
| 16.nova-conductor根据消息查询虚拟机对应的信息。 | |
| 17.nova-conductor从数据库中获得虚拟机对应信息。 | |
| 18.nova-conductor把虚拟机信息通过消息的方式发送到消息队列中。 | |
| 19.nova-compute从对应的消息队列中获取虚拟机信息消息。 | |
| 20.nova-compute通过keystone的RESTfull API拿到认证的token,并通过HTTP请求glance-api获取创建虚拟机所需要镜像。 | |
| 21.glance-api向keystone认证token是否有效,并返回验证结果。 | |
| 22.token验证通过,nova-compute获得虚拟机镜像信息(URL)。 | |
| 23.nova-compute通过keystone的RESTfull API拿到认证k的token,并通过HTTP请求neutron-server获取创建虚拟机所需要的网络信息。 | |
| 24.neutron-server向keystone认证token是否有效,并返回验证结果。 | |
| 25.token验证通过,nova-compute获得虚拟机网络信息。 | |
| 26.nova-compute通过keystone的RESTfull API拿到认证的token,并通过HTTP请求cinder-api获取创建虚拟机所需要的持久化存储信息。 | |
| 27.cinder-api向keystone认证token是否有效,并返回验证结果。 | |
| 28.token验证通过,nova-compute获得虚拟机持久化存储信息。 | |
| 29.nova-compute根据instance的信息调用配置的虚拟化驱动来创建虚拟机。 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| GitHub | |
| 何为版本控制 | |
| 版本控制是一种记录文件内容变化,以便将来查阅特定版本修订情况的系统。 | |
| 版本控制其实最重要的是可以记录文件修改历史记录,从而让用户能够查看历史版本,方便版本切换。 | |
| 版本控制工具 | |
| 集中式版本控制工具 | |
| CVS、SVN(Subversion)、VSs...... | |
| 集中化的版本控制系统诸如CVS、SVN等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。多年以来,这已成为版本控制系统的标准做法。 | |
| 这种做法带来了许多好处,每个人都可以在一定程度上看到项目中的其他人正在做些什么。而管理员也可以轻松掌控每个开发者的权限,并且管理一个集中化的版本控制系统,要远比在各个客户端上维护本地数据库来得轻松容易。 | |
| 事分两面,有好有坏。这么做显而易见的缺点是中央服务器的单点故障。如果服务器宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。 | |
| 分布式版本控制工具 | |
| Git、Mercurial、Bazaar、Darcs...... | |
| 像Git这种分布式版本控制工具,客户端提取的不是最新版本的文件快照,而是把代码仓库完整地镜像下来(本地库)。 | |
| 这样任何一处协同工作用的文件发生故障,事后都可以用其他客户端的本地仓库进行恢复。因为每个客户端的每一次文件提取操作,实际上都是一次对整个文件仓库的完整备份。 | |
| 分布式的版本控制系统出现之后,解决了集中式版本控制系统的缺陷: | |
| 1.服务器断网的情况下也可以进行开发(因为版本控制是在本地进行的) | |
| 2.每个客户端保存的也都是整个完整的项目(包含历史记录,更加安全) | |
| 工作机制 | |
| 首先在工作区写代码 | |
| 写完之后' git add '把代码添加到暂存区 做一个临时存储 | |
| 最后使用' git commit '把上传到本地库 并生成对应历史版本 | |
| 本地库中的代码时无法删除无法回退的, | |
| 可以使用' push '命令把本地库的代码推送到远程库 | |
| git和代码托管中心 | |
| 代码托管中心是基于网络服务器的远程代码仓库,一般我们简单称为远程库。 | |
| 局域网: | |
| GitLab,搭建的GitLab只可以在局域网内使用 | |
| 互联网: | |
| GitHub(外网) | |
| Gitee码云(国内网站) | |
| 命令 | |
| git config --global user.email 1726242034@qq.com 设置用户邮箱 | |
| git config --global user.name xuJunNan 设置用户姓名 | |
| 初始化本地库 | |
| git想要管理当前目录 必须获取当前目录的使用权 使用' git init '命令获取 | |
| 比如想要管理' D:\BaiduNetdiskDownload '目录, 就需要进入到此目录 然后使用' git init '获取此目录的使用权(隐藏文件需要使用ll -a查看) | |
| 获取当前状态 | |
| git status | |
| 此命令会返回三行数据 | |
| On branch master | |
| 当前所在的分支 | |
| No commits yet | |
| 当前分支所提交的信息(在暂存区存储的文件 没有则不显示) | |
| 在暂存区中的文件可以提交到本地库 使用' git commit -m "日志信息" 文件名 '命令提交 | |
| 提交成功后可以使用' git reflog '命令查看引用日志的信息 | |
| d1722e5 (HEAD -> master) HEAD@{0}: commit: hel V2 commit | |
| 版本号 当前使用的master主版本 | |
| 使用' git reset --hard 版本号 '穿梭到指定的版本 | |
| Untracked files: (use "git add <file>..." to include in what will be committed) | |
| 当前文件夹中未提交的文件(在工作区存储的文件), | |
| 使用' git add 文件名 '追踪文件 即把文件上传到暂存区 做一个临时存储 | |
| 上传到暂存区完成之后 即可在' No commits yet '下面看到此文件 | |
| 使用' git rm --cached 文件名 '删除在暂存区的文件 | |
| 使用' git commit -m "日志信息" 文件名 '把暂存区的文件提交到本地库 | |
| 使用' git reflog '查看引用日志信息 | |
| 使用' git flog '查看引用日志的详细信息 | |
| 什么是分支 | |
| 在版本控制过程中,同时推进多个任务,为每个任务,我们就可以创建每个任务的单独分支。使用分支意味着程序员可以把自己的工作从开发主线上分离开来, | |
| 开发自己分支的时候,不会影响主线分支的运行。对于初学者而言,分支可以简单理解为副本,一个分支就是一个单独的副本。(分支底层其实也是指针的引用) | |
| ' git branch -v '查看所有分支 | |
| ' git branch 分支名称 '新建分支 | |
| ' git checkout 分支名称 '切换分支 | |
| ' git merge 分支名称 '把指定分支合并到当前分支上 | |
| 文件冲突 | |
| 当多个分支同时操作一个文件 并且都提交到了本地库之后进行合并,git就无法确定具体要保存哪一个分支的文件 | |
| 在合并分支的时候就需要手动进入到文件中以确定要怎么合并 | |
| 然后使用' git commit -m "版本信息"'来合并(不能加文件名 否则报错) | |
| ------------------------------------------------------------------------------------------------------------------------------------------------------ | |
| 远程库 | |
| 本地库中的代码可以上传到远程库 在远程库中的代码可以被所有用户拉取 | |
| ' git remote -v '查看所有远程库 | |
| ' git remote add 远程库别名 远程库url '添加远程库 | |
| ' git push 远程库别名 分支名称 '把本地库的代码推送到远程库 | |
| ' git pull 远程库别名 分支名称 '把远程库的代码拉取到本地库 | |
| ' git clone 远程库url '克隆远程库到本地(克隆操作会自动进行拉取代码、初始化本地仓库、创建别名操作) | |
| ssh免密登录 | |
| 进入到' C:\Users\xu172 '目录下 在git命令行界面输入' ssh-keyger -t rsa -C 邮箱 '创建ssh文件夹 | |
| ssh文件夹内的'id_rsa.pub'文件就是ssh的公钥 把这个公钥复制到github网站即可 | |
| 在github中点击头像下面的Settings, 然后点击SSH and GPG keys即可添加ssh公钥 | |
| ------------------------------------------------------------------------------------------------------------------------------------------------------ | |
| idea继承git | |
| idea需要先把idea的目录初始文件忽略掉 因为这些文件与项目无关 不参与服务器上部署运行 | |
| 在idea中打开: File | Settings | Version Control | Git, | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Mysql锁机制 | |
| 锁是为了保证数据的一致性。行锁必须建立在索引上, 如果没有索引那么就只会创建出表锁, 因为没有索引的话, | |
| mysql会全表扫描, 那样会锁定整张表所有的记录, 包括不存在的记录, 此时其他事务不能修改不能删除不能添加 | |
| innodb支持表锁和行锁, myisam只支持表锁 | |
| 表锁: 当修改表中数据时 通过锁住整张表来保证数据一致性。特点是开销小 加锁快 不会出现死锁, 锁粒度大 发生锁冲突的概率小 并发度相对低 | |
| 行锁: 当修改表中数据时 通过锁住当前行来保证数据一致性。特点是开销大 加锁慢 会出现死锁, 锁粒度小 发生锁冲突的概率大 并发度相对高 | |
| 但并不是说行锁就一定比表锁快, 例如一张表有300w条数据 要修改150w数据才可以让其他程序执行, 此时就需要创建一次表锁 因为创建行锁就需要150w次 | |
| 锁类型 | |
| 记录锁(Record Lock): | |
| 当前记录的锁 就是行锁(insert update操作自动加行锁), 行锁必须建立在索引上, 如果没有索引那么就只会创建出表锁 | |
| 因为没有索引的话, mysql会全表扫描, 那样会锁定整张表所有的记录, 包括不存在的记录, 此时其他事务不能修改不能删除不能添加 | |
| 不加索引 两个事务修改同一行记录 卡住了 创建的是表锁 | |
| 不加索引 两个事务修改同一表非同行记录 卡住了 创建的是表锁 | |
| 加索引 两个事务修改同一行记录 卡住了 创建的是行锁 | |
| 加索引 两个事务修改同表的不同行 可以修改 创建的是行锁 | |
| 间隙锁(GAP Lock): | |
| 在RR(repeatable read)的隔离级别下 为了避免'幻读'引入了GAP Lock, 它锁定的是记录范围 不包含记录本身, 也就是不允许在范围内插入数据 | |
| 根据检索条件向下寻找最靠近检索条件的记录值A作为左区间 向上寻找最靠近检索条件的记录值B作为右区间 即锁定的间隙为A,B | |
| 即: 如果where是xx = 10, 那么就会去找xx = 10的记录前一条A和后一条B, A和B之间的区间就会被锁住不允许添加数据 | |
| 即: 如果where是xx > 10, 那么10这个记录的'前一条记录往后'的所有记录都会被锁住不允许添加数据 | |
| id num | |
| 1 2 | |
| 3 4 | |
| 6 5 | |
| 8 5 | |
| 10 5 | |
| 13 11 | |
| 如果num=4, 那么间隙就是(1 2) - (6 5), (6 5)记录后面都不算。比如(5 5)就会被锁, 而(7 5)和(7 5)以后的就可以成功 | |
| 如果num=5 num的值有多个, 那么间隙就是(3 4) - (13 11) | |
| 如果num=5, num的间隙就是4 - 11, 插入4 - 11都会堵塞, 4以前和11以后可以成功 | |
| 更新数据 num=5 where id=1 堵塞 (num=5在间隙中) | |
| 插入数据 id=2 where num=4 成功 (num=4在区间中 但是id=2却在左区间3 4的前面 所以不受影响) | |
| 插入数据 id=4 where num=4 堵塞 (num=4在区间中 而且id=4也在左区间3 4的后面 所以会堵塞) | |
| 创建间隙锁(lock in share mode) | |
| select * from xx where xx = 9 lock in share mode | |
| 临键锁(next-key lock): | |
| 临键锁是' 记录锁和间隙锁的组合 ', 它的封锁范围既包含索引记录 也包含索引区间 | |
| 读取记录时 会先上一个Record Lock, 然后判断是否是唯一索引 不是的话就再上一个间隙锁 | |
| 注: 临键锁的主要目的也是为了避免幻读。如果把事务的隔离级别降级为RC(read committed) 临键锁也会失效 | |
| 表锁 | |
| 在InnoDB下 ,使用表锁要注意以下两点。 | |
| 1. 使用LOCK TALBES虽然可以给InnoDB加表级锁,但必须说明的是,表锁不是由InnoDB存储引擎层管理的,而是由其上一层MySQL Server负责的, | |
| 仅当autocommit=0、innodb_table_lock=1(默认设置)时,InnoDB层才能知道MySQL加的表锁,MySQL Server才能感知InnoDB加的行锁,这种情况下, | |
| InnoDB才能自动识别涉及表级锁的死锁;否则,InnoDB将无法自动检测并处理这种死锁。 | |
| 2. 在用LOCAK TABLES对InnoDB锁时要注意,要将AUTOCOMMIT设为0,否则MySQL不会给表加锁;事务结束前,不要用UNLOCAK TABLES释放表锁, | |
| 因为UNLOCK TABLES会隐含地提交事务;COMMIT或ROLLBACK不能释放用LOCAK TABLES加的表级锁,必须用UNLOCK TABLES释放表锁,正确的方式见如下语句。 | |
| 加锁 | |
| lock tables teacher write,student read; 给teacher表加一个写锁 给student表加一个读锁 | |
| select * from teacher; | |
| commit; 建议提交事务后再释放锁 | |
| unlock tables; 释放表锁 | |
| 读锁/共享锁: | |
| 多个session可以同时读取表 但不能进行更改操作(读锁、写锁建立在索引上就是行锁, 建立在非主键字段就是表锁) | |
| 加锁(使用lock in share mode): select * from test where sss = 10 lock in share mode; | |
| 写锁/排他锁/独占锁/互斥锁: | |
| 只有当前session可以往表中写数据 其他session不能进行读操作和写操作(mysql中使用了mvcc 使得其他session中可以读数据) | |
| 加锁(使用for update): select * from test where sss = 10 for update; | |
| MDL锁 | |
| MySQL 5.5引入了meta data lock,简称MDL锁,用于保证表中元数据的信息。在会话A中,表开启了查询事务后,会自动获得一个MDL锁, | |
| 会话B就不可以执行任何DDL语句,不能执行为表中添加字段的操作,会用MDL锁来保证数据之间的一致性。元数据就是描述数据的数据,也就是你的表结构 | |
| 意思是在你开启了事务之后获得了意向锁,其他事务就不能修改你的表结构 | |
| 意向锁 | |
| 在mysql的innodb引擎中,意向锁是表级锁,意向锁有两种 | |
| 意向共享锁(IS) 是指在给一个数据行加共享锁前必须获取该表的意向共享锁 | |
| 意向排它锁(IX) 是指在给一个数据行加排他锁前必须获取该表的意向排他锁 | |
| 意向锁和MDL锁都是为了防止在事务进行中,执行DDL语句导致数据不一致。 | |
| 乐观锁(不加锁) | |
| 乐观锁大多是基于数据版本记录机制实现,一般是给数据库表增加一个"version"字段。读取数据时,将此版本号一同读出,之后更新时,对此版本号加一。 | |
| 此时将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。 | |
| 比如下单操作: | |
| 查询出商品信息 | |
| select number, version from teacher where id = 1; | |
| 根据商品信息生成订单。 | |
| 将商品数量减1。 | |
| update teacher set number = number-1,version = version + 1 where id = 1 and version = 3(查出来的version) | |
| 悲观锁(都加锁) | |
| 悲观锁依靠数据库提供的锁机制实现。MySQL中的共享锁和排它锁都是悲观锁。数据库的增删改操作默认都会加排他锁,而查询不会加任何锁。 | |
| 锁等待 | |
| 锁等待是指一个事务过程中产生的锁,其他事务需要等待上一个事务释放它的锁,才能占用该资源。如果该事务一直不释放, | |
| 就需要持续等待下去,直到超过了锁等待时间,会报一个等待超时的错误 | |
| 查看锁等待时间: select @@innodb_lock_wait_timeout | |
| 修改锁等待时间: set innodb_lock_wait_timeout = 10 | |
| 死锁 | |
| 死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,就是所谓的锁资源请求产生了回路现象,即死循环。 | |
| InnoDB引擎可以自动检测死锁并回滚该事务 但是好不容易执行了一个业务给我回滚了,所以死锁尽量不要出现。 | |
| 死锁的条件 | |
| 1. 两行记录,至少两个事务 | |
| 2. 事务A 操作 第n行数据,并加锁 update teacher set name = 'a' where id = 1; | |
| 3. 事务B 操作 第m行数据,并加锁 update teacher set name = 'b' where id = 2; | |
| 4. 事务A 操作 第m行数据 update teacher set name = 'c' where id = 2; | |
| 5. 事务B 操作 第n行数据 update teacher set name = 'd' where id = 1; | |
| 6. 形成死锁 Deadlock found when trying to get lock; try restarting transaction | |
| 如何避免死锁 | |
| 如果不同的程序会并发处理同一个表,或者涉及多行记录,尽量约定使用相同顺序访问表,可以大大减少死锁的发生。 | |
| 业务中尽量采用小事务,避免使用大事务,要及时提交和回滚事务,可减少死锁产生的概率。 | |
| 同一个事务中尽量做到一次锁定所需要的所有资源,减少死锁发生的概率。 | |
| 对于非常容易发生死锁的业务,可以尝试使用升级锁的力度,该用表锁减少死锁的发生 | |
| MVCC(Multi-Version Concurrency Control)多版本并发控制 | |
| MVCC多版本并发控制指的是 “维持一个数据的多个版本,使得读写操作没有冲突” 这么一个概念。仅仅是一个理想概念(实现方式是快照读) | |
| MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。 | |
| MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非堵塞并发读 | |
| MVCC就是为了实现读--写冲突不加锁,而这个读指的就是快照读, 而非当前读,当前读实际上是一种加锁的操作,是悲观锁的实现 | |
| 当前读 | |
| 像select lock in share mode( 共享锁), select for update ; update, insert ,delete( 排他锁)这些操作都是一种当前读, | |
| 为什么叫当前读?因为它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁 | |
| 快照读 | |
| 像不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别, | |
| 串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制, | |
| 即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销; | |
| 既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本 | |
| MVCC带来的好处是? | |
| 多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本, | |
| 版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。所以MVCC可以为数据库解决以下问题 | |
| 在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能 | |
| 同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题 | |
| MVCC实现原理 | |
| MVCC模型在MySQL中的具体实现则是由 3个隐式字段, undo日志 , Read View 等去完成的,具体可以看下面的MVCC实现原理 | |
| 3个隐式字段 | |
| 每行记录除了我们自定义的字段外,还有数据库隐式定义的DB_TRX_ID(隐式主键), DB_ROLL_PTR(事务ID) , DB_ROW_ID(回滚指针) 等字段 | |
| DB_TRX_ID: 6byte,最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID | |
| DB_ROLL_PTR: 7byte,回滚指针,指向这条记录的上一个版本(存储于rollback segment里) | |
| DB_ROW_ID: 6byte,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引 | |
| 实际还有一个删除flag隐藏字段, 既记录被更新或删除并不代表真的删除,而是删除flag变了 | |
| 比如一个表 | |
| name age DB_TRX_ID DB_ROLL_PTR DB_ROW_ID | |
| jerry 24 1 1 0x11111111 | |
| DB_ROW_ID 是数据库默认为该行记录生成的唯一隐式主键, | |
| DB_TRX_ID 是当前操作该记录的事务ID, | |
| DB_ROLL_PTR 是一个回滚指针,用于配合undo日志,指向上一个旧版本 | |
| undo log | |
| 事务中的修改操作 其实都是在表中真实的修改了,只是原来的旧数据被保存在了undo日志中,如果发生回滚操作 就会恢复undo日志中的旧数据 | |
| 写锁为什么可以让其他事务进行读操作? 因为其他事务读取的是undo日志中的旧数据 | |
| undo log主要分为两种: | |
| insert undo log | |
| 代表事务在insert 新记录时产生的undo log , 只在事务回滚时需要,并且在事务提交后可以被立即丢弃 | |
| update undo log | |
| 事务在进行update 或delete 时产生的undo log ; 不仅在事务回滚时需要,在快照读时也需要; | |
| 所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被purge 线程统一清除 | |
| purge线程,想成是一个环卫工人 | |
| 从前面的分析可以看出,为了实现InnoDB的MVCC机制,更新或者删除操作都只是设置一下老记录的deleted_bit,并不真正将过时的记录删除。 | |
| 为了节省磁盘空间,InnoDB有专门的purge线程来清理deleted_bit为true的记录。为了不影响MVCC的正常工作, | |
| purge线程自己也维护了一个read view(这个read view相当于系统中最老活跃事务的read view); | |
| 如果某个记录的deleted_bit为true,并且DB_TRX_ID相对于purge线程的read view可见,那么这条记录一定是可以被安全清除的 | |
| MVCC的执行流程 | |
| 在事务1修改数据时 数据库会先对该行加排他锁(写锁),然后会把该行数据拷贝到undo log日志文件中作为旧数据, | |
| 拷贝完成后修改该行数据,并且把隐式字段的事务ID修改为当前事务的ID 回滚指针指向undo log文件中的旧数据。 | |
| 不同事务或者相同事务的对同一记录的修改,会导致该记录的undo log成为一条链表,undo log的链首就是最新的旧记录,链尾就是最早的旧记 | |
| 事务提交后释放锁 | |
| 事务2 | |
| name age DB_TRX_ID DB_ROLL_PTR DB_ROW_ID | |
| tom 30 1 2 0x21111112指向旧数据 | |
| undo log日志 | |
| name age DB_TRX_ID DB_ROLL_PTR DB_ROW_ID | |
| tom 30 1 1 0x11111111指向上一个旧数据 | |
| name age DB_TRX_ID DB_ROLL_PTR DB_ROW_ID | |
| jerry 24 1 null null | |
| Redo Log重做日志 | |
| InnoDB的修改数据的基本流程: 当我们想要修改DB上某一行数据的时候,InnoDB是把数据从磁盘读取到内存的缓冲池上进行修改。 | |
| 数据在内存中被修改,与磁盘中相比就存在了差异,我们称这种有差异的数据为脏页。 | |
| InnoDB对脏页的处理不是每次生成脏页就将脏页刷新回磁盘,这样会产生海量的IO操作,严重影响InnoDB的处理性能。 | |
| 对于此,InnoDB有一套完善的处理策略,与我们这次主题关系不大,表过不提。 | |
| 既然脏页与磁盘中的数据存在差异,那么如果在这期间DB出现故障就会造成数据的丢失。为了解决这个问题,redo log就应运而生了。 | |
| mysql的日志有两种: | |
| Redo log在数据库重启的时候被使用 因为其属于物理日志的特性 恢复速度远快于逻辑日志。 | |
| 物理日志(存储了数据被修改的值)、 | |
| 逻辑日志(存储了逻辑sql修改语句) | |
| checkpoint(检查站) | |
| 坦白来讲checkpoint本身是比较复杂的,checkpoint所做的事就是把脏页给刷新回磁盘。 | |
| 所以,当DB重启恢复时,只需要恢复checkpoint之后的数据。这样就能大大缩短恢复时间。当然checkpoint还有其他的作用。 | |
| LSN(Log Sequence Number) | |
| LSN实际上就是InnoDB使用的一个版本标记的计数,它是一个单调递增的值。数据页和redo log都有各自的LSN。 | |
| 我们可以根据数据页中的LSN值和redo log中LSN的值判断需要恢复的redo log的位置和大小 | |
| 工作原理 | |
| redo log就是存储了数据被修改后的值。当我们提交一个事务时,InnoDB会先去把要修改的数据写入日志,然后再去修改缓冲池里面的真正数据页。 | |
| redo log本身也由两部分所构成即' 重做日志缓冲(redo log buffer) '和' 重做日志文件(redo log file) '。这样的设计同样也是为了调和内存与磁盘的速度差异。 | |
| innodb_flush_log_at_trx_commit: InnoDB写入磁盘的策略是通过这个参数来控制 | |
| 为0时 表示事务提交不写入磁盘,写入过程在master thread中进行(会丢失掉master thread还没刷新进磁盘的部分数据) | |
| 为1时 表示事务提交必须调用一次fsync函数(fsync函数的作用是把'重做日志缓冲'中的数据写入到'重做日志文件') | |
| 为2时 表示事务提交时不写入重做日志文件,而是写入文件系统缓冲中 | |
| master thread: | |
| 这是InnoDB一个在后台运行的主线程,从名字就能看出这个线程相当的重要。它做的主要工作包括但不限于:刷新日志缓冲,合并插入缓冲,刷新脏页等。 | |
| master thread大致分为每秒运行一次的操作和每10秒运行一次的操作。master thread中刷新数据,属于checkpoint的一种。 | |
| 所以如果在master thread在刷新日志的间隙,DB出现故障那么将丢失掉这部分数据。 | |
| 当该值为2时,当DB发生故障能恢复数据。但如果操作系统也出现宕机,那么就会丢失掉,文件系统没有及时写入磁盘的数据。 | |
| 当该值为0时,并不是说不会在master thread中刷新日志了。master thread刷新日志是在不断进行的,所以redo log写入磁盘是在持续的写入 | |
| 宕机恢复 | |
| DB宕机后重启,InnoDB会首先去查看数据页中的LSN的数值。这个值代表数据页被刷新回磁盘的LSN的大小。然后再去查看redo log的LSN的大小。 | |
| 如果数据页中的LSN值大说明数据页领先于redo log刷新回磁盘,不需要进行恢复。反之需要从redo log中恢复数据。 | |
| 存储引擎 | |
| 1、InnoDB存储引擎 | |
| 从MySQL5.5版本之后,MySQL的默认内置存储引擎已经是InnoDB了,他的主要特点有: | |
| 支持事务。默认的事务隔离级别为可重复读,通过MVCC(并发版本控制)来实现的。 | |
| 使用的锁粒度为行级锁,可以支持更高的并发; | |
| 支持外键; | |
| 在InnoDB中存在着缓冲管理,通过缓冲池,将索引和数据全部缓存起来,加快查询的速度; | |
| 对于InnoDB类型的表,其数据的物理组织形式是聚簇表。所有的数据按照主键来组织。数据和索引放在一块,都位于B+数的叶子节点上; | |
| 2、MyISAM存储引擎 | |
| 在5.5版本之前,MyISAM是MySQL的默认存储引擎,该存储引擎并发性差,不支持事务,所以使用场景比较少,主要特点为: | |
| 不支持事务; | |
| 不支持外键,如果强行增加外键,不会提示错误,只是外键不其作用; | |
| 对数据的查询缓存只会缓存索引,不会像InnoDB一样缓存数据,而且是利用操作系统本身的缓存; | |
| 默认的锁粒度为表级锁,所以并发度很差,加锁快,锁冲突较少,所以不太容易发生死锁; | |
| 支持全文索引(MySQL5.6之后,InnoDB存储引擎也对全文索引做了支持), | |
| 但是MySQL的全文索引基本不会使用,对于全文索引,现在有其他成熟的解决方案,比如:ElasticSearch,Solr,Sphinx等。 | |
| 数据库所在主机如果宕机,MyISAM的数据文件容易损坏,而且难恢复; | |
| 两种引擎的对比 | |
| 1、由于锁粒度的不同,InnoDB比MyISAM支持更高的并发; | |
| 2、InnoDB为行级锁,MyISAM为表级锁,所以InnoDB相对于MyISAM来说,更容易发生死锁,锁冲突的概率更大,而且上锁的开销也更大,因为需要为每一行加锁; | |
| 3、在备份容灾上,InnoDB支持在线热备,有很成熟的在线热备解决方案; | |
| 4、查询性能上,MyISAM的查询效率高于InnoDB,因为InnoDB在查询过程中,是需要维护数据缓存,而且查询过程是先定位到行所在的数据块, | |
| 然后在从数据块中定位到要查找的行;而MyISAM可以直接定位到数据所在的内存地址,可以直接找到数据; | |
| 5、SELECT COUNT(*)语句,如果行数在千万级别以上,MyISAM可以快速查出,而InnoDB查询的特别慢,因为MyISAM将行数单独存储了, | |
| 而InnoDB需要逐行去统计行数;所以如果使用InnoDB,而且需要查询行数,则需要对行数进行特殊处理,如:离线查询并缓存; | |
| 6、MyISAM的表结构文件包括:.frm(表结构定义),.MYI(索引),.MYD(数据);而InnoDB的表数据文件为:.ibd和.frm(表结构定义); | |
| 选择合适的存储引擎 | |
| 1、使用场景是否需要事务支持; | |
| 2、是否需要支持高并发,InnoDB的并发度远高于MyISAM; | |
| 3、是否需要支持外键; | |
| 4、高效缓冲数据,InnoDB对数据和索引都做了缓冲,而MyISAM只缓冲了索引; | |
| 5、索引,不同存储引擎的索引并不太一样; | |
| 怎么sql优化 | |
| 少用子查询 多用左连接 | |
| 使用索引 | |
| 合理的使用表锁和行锁 | |
| 少用大事务 多用小事务 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| union / union all: 可以拼接两个语句 查询的结果不会显示重复的数据(all会) | |
| select name,age from user union select name,age from users | |
| inner join内连接 / left join左连接 / right join右连接 | |
| select id,name from stu inner join the on stu.id = the.stu_id | |
| 内连接只会显示左右两个表有关系的数据 | |
| 左连接一定会显示左表所有的数据 但是不会管右表有没有与其对应的数据, 右表若没有与左表对应的数据 则显示null | |
| on / where / group by | |
| on后面跟的是连接条件 | |
| where后面跟的是筛选条件 | |
| group by后面跟的是分组条件 | |
| 在创建表时 int(5)的(5)是什么意思? | |
| 搭配' zerofill '使用 表示显示宽度 不足部位以零填充, 不是代表能存放多少位数。 | |
| 比如' int(5) '表示显示宽度为5, 当存储一个'1'时 表中数据就是'00001' | |
| 数据库设计的三范式 | |
| 第一范式: 每一个表都应该有主键 并且每一个字段原子性不可再分 | |
| 第二范式: 建立在第一范式的基础上, 所有非主键字段完全依赖主键 不能产生部分依赖, | |
| 部分依赖: 有多个主键时 非主键字段只依赖一个主键, 完全依赖: 有多个主键时 非主键字段完全依赖多个主键。 | |
| 多对多的时候, 三张表 关系表两个外键 | |
| 第三范式: 建立在第二范式的基础上, 所有非主键字段直接依赖主键 不能产生传递依赖 | |
| 传递依赖: 一个表中的a字段依赖b字段 b字段又依赖了c字段 | |
| 一对多的时候, 两张表 多的表加外键 | |
| 三范式可以解决数据的冗余, 但是多表查询时连接的表越多 执行速度越慢, | |
| 所以有的时候要拿数据的冗余换取执行速度 | |
| 一对一: 比如有一张表有很多字段 但是常用的字段只有两个, 此时就可以把这两个字段组成一个表, 但是怎么让两个表关联? | |
| 方案一: 主键共享 即让两张表产生关联的属性的主键一致 | |
| 方案二: 外键唯一 即让一张表的外键字段加上'unique' 让其绑定另一张表的主键 | |
| mysql优化 | |
| 内存中的数据 需要使用'地址'来进行读取 使用电流信号可以马上找到数据的地址, 所以读取速度很快 但是没电就不行了 | |
| 磁盘中的数据 需要让磁头转到数据存储的地方 才可以读取到, 所以读取速度比较慢 | |
| 磁盘预读特性 | |
| 硬盘分为读写磁头、磁道、扇区。一个盘片有正反两面 需要两个磁头, 盘片上一圈磁头工作路径为一个磁道 三个盘面重叠的磁道称为柱面, | |
| 每个磁道上的一个弧段称为一个扇区。磁盘的容量为: 磁头数 × 磁道(柱面)数 × 盘片的扇区数 × 每个扇区的容量 | |
| 当需要从磁盘读取数据时, 系统会将逻辑地址发给磁盘, 磁盘的控制电路将逻辑地址转换为物理地址(哪个磁道, 哪个扇区)这时候就会有磁头的机械运动, | |
| 磁头找到相应磁道(寻道), 时间称为寻道时间, 磁头找到对应磁道的对应扇区, 称为旋转时间。这是很大的时间消耗, 所以系统一般采取预读的方式, 减少磁盘I/O | |
| 系统是分页读取和存储的 一般一页为4KB, 每次读取和存取的最小单元为一页, 预读即在读取的起始地址连续读取多个页面 | |
| (现在不需要的页面也读取了 这样以后用时就不用再读取, 当一个页面用到时 大多数情况下 它周围的页面也会被用到) | |
| 磁盘分页: 参考计算机操作系统的分页, 分段存储管理逻辑地址和物理地址被分为大小相同的页面, 逻辑地址中叫页, 物理地址中叫块 | |
| 索引 | |
| b+树的查找过程 | |
| 假设磁盘块1包含数据项17和35,包含指针P1、P2、P3。指针P1表示小于17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于35的磁盘块。 | |
| 真实的数据存在于叶子节点即3、5、 9、10、 13、15、 28、29、 36、60、 75、79、 90、99。 | |
| (非叶子节点只不存储真实的数据,只存储指引搜索方向的数据项,如17、35并不真实存在于数据表中。) | |
| 如果要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存, | |
| 此时发生一次IO。在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存, | |
| 发生第二次IO。29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存, | |
| 发生第三次IO,同时内存中做二分查找找到29,结束查询,总计三次IO。真实的情况是,3层的b+树可以表示上百万的数据, | |
| 如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。 | |
| 为什么要建立索引? | |
| 因为数据库进行全表遍历速度会很慢, 索引可以建立一个B+树的结构 B+树的每一个节点都是索引列的值 由上而下的去查询 速度就很快了。 | |
| 为什么使用B+树而不用B树? | |
| B+树所有数据都存在叶子节点上 叶子节点之间相互都有指针指向下一个叶子, 所以全表遍历会很方便。 | |
| 数据放在普通的节点上 会增加普通节点的体积, 普通节点如果只放索引的字段可以放好多 但是放数据就放不了多少了。 | |
| 根据磁盘的预读性原理, 每一次内存都是从磁盘上读取一页的数据(4k), 这一页可以存放更多的索引列 而存放数据就存放的比较少 | |
| 所以每一次拿到的索引ID越多 B+树的层高就越低, 需要的磁盘IO次数就越少 | |
| B-Tree、hash | |
| 索引的实现方法分为两种 B-Tree、hash, 这两种索引方法都可以创建索引 且创建的索引类型也一样, 区别就是底层的算法不一致 | |
| B-Tree: 创建基于B树结构的索引 具有范围查找和前缀查找的能力, 对于有N节点的B树 检索一条记录的复杂度为o(logN), 相当于二分查找 | |
| hash: 创建基于hash表结构的索引 由于hash是散列算法无序 所以只能做等于查找, 不管多大的hash表 查找的复杂度都是o(1), | |
| 如果值的差异性大, 并且以等值查找(=、<、>、in)为主 Hash索引是更高效的选择 它有o(1)的查找复杂度。 | |
| 如果值的差异性相对较差, 并組以范围查找为主 B树是更好的选择 它支持范围查找。 | |
| 优缺点 | |
| 优点: | |
| 索引可以极大的加快查询的效率 | |
| 可以加速表和表之间的连接, 特别是在实现数据的参考完整性方面特别有意义 | |
| 在使用分组和排序子句进行数据检索时, 同样可以显著减少查询中分组和排序的时间 | |
| 缺点: | |
| 索引是占用空间的 | |
| 当对表中的数据进行update insert delete的时候, 索引也要动态的维护, 这样就降低了数据的维护速度。 | |
| 注意事项 | |
| 索引要创建在where和join用到的字段上 | |
| 以下操作符号可以应用索引:<,<=,=,>,>=,BETWEEN,IN,LIKE不以%_开头 | |
| 以下需要注意不使用索引: <>, NOT IN, LIKE %_开头, <>可以用a>1 or a<3代替, NOT IN可以用NOT exists代替 | |
| 在使用max() min()时最好加上索引 | |
| 单索引要创建在确实需要的地方, 多列索引 有最佳左前缀特性 所以尽量左边的字段是最常用的 | |
| 索引不会包括有NULL值, 就是有NULL, 索引就失效(因为B+树的叶子节点需要节点中索引字段来排序, 非要传null就可以用其他数据代替null) | |
| 使用短索引, 一个字段字太多, 可以建立部分索引, 只取前十个字节约空间 | |
| 不要在列上运算 例如:where MD5("password") = "myz" | |
| 索引失效 | |
| 索引包括有NULL值 | |
| 复合索引不满足最左原则就不能使用索引 | |
| 如果条件中有or 那么所有索引都会失效!如果想让or和索引都生效 需要给or条件中的每个列都加上索引 | |
| like查询以'%'开头的 索引会失效!例如 a like '%aaa' | |
| mysql估计使用全表扫描比使用索引快 就不使用索引 | |
| 参与了列计算的列 索引会失效, 因为参与了计算 索引的值就变得不可定了, 不可定的索引无法作为叶子节点数据排序的依据 | |
| 排序的索引问题 | |
| mysql查询只使用一个索引, 因此如果where子句中已经使用了索引的话, 那么order by中的列是不会使用索引的。 | |
| 因此数据库默认排序可以符合要求的情况下不要使用排序操作; 尽量不要包含多个列的排序, 如果需要最好给这些列创建复合索引。 | |
| 覆盖索引 | |
| 根据id去聚簇索引中查找真正的数据,这个过程叫做回表, 如果你要的数据索引都有了不需要回表,就叫索引覆盖。 | |
| 什么样的字段适合创建索引? | |
| 频繁作为where语句查询的字段 | |
| 关联字段需要创建索引 例如外键字段 | |
| 排序字段可以建立索引 | |
| 分组字段可以建立索引 因为分组的前提就是排序 | |
| 统计字段可以建立索引 例如count() max() | |
| 什么样的字段不适合创建索引? | |
| 频繁更新的字段不适合建立索引 | |
| where条件中用不到的字段不适合创建索引 | |
| 表数据可以确定比较少的不需要创建索引 | |
| 对表的修改性能大于检索性能时 不应该创建索引 因为索引对检索比较差 | |
| 数据重复度较高且发布比较均匀的字段不适合创建索引(唯一性太差的字段) 例如性别 真假值 | |
| 参与列计算的列不适合加索引 索引会失效 | |
| 对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列, | |
| 在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。 | |
| 增加索引,并不能明显加快检索速度。 | |
| 对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为, 这些列的数据量要么相当大, 要么取值很少。 | |
| ------------------------------------------------------------------------------------------------------------------------------------------------------- | |
| 聚簇索引 | |
| 聚簇索引具有唯一性,由于聚簇索引是将数据跟索引结构放到一块,因此一个表仅有一个聚簇索引。 | |
| 表中行的物理顺序和索引中行的物理顺序是相同的,在创建任何非聚簇索引之前创建聚簇索引, | |
| 这是因为聚簇索引改变了表中行的物理顺序,数据行按照一定的顺序排列,并且自动维护这个顺序 | |
| 聚簇索引查找数据 | |
| InnoDB使用的是聚簇索引,将主键组织到一棵B+树中,而行数据就储存在叶子节点上,若使用"where id = 14"这样的条件查找主键, | |
| 则按照B+树的检索算法即可查找到对应的叶子节点,之后获得行数据。 | |
| 聚簇索引默认是主键,如果表中没有定义主键,InnoDB 会选择一个唯一且非空的索引代替。如果没有这样的索引, | |
| InnoDB 会隐式定义一个主键(类似oracle中的RowId)来作为聚簇索引。如果已经设置了主键为聚簇索引又希望再单独设置聚簇索引, | |
| 必须先删除主键,然后添加我们想要的聚簇索引,最后恢复设置主键即可 | |
| 非聚簇索引查找数据 | |
| 若对Name列进行条件搜索,则需要两个步骤:第一步在'次索引B+树'中检索Name,到达其叶子节点获取对应的主键(次索引的B+树叶子节点存放的是主键的位置)。 | |
| 第二步进行'回表'操作, 使用'次索引B+树'中检索到的主键 在'主索引B+树'中再执行一次B+树检索操作, | |
| 最终到达叶子节点即可获取整行数据。(重点在于通过其他键需要建立次索引) | |
| 为什么非聚簇索引的叶子节点要放聚簇索引的id? | |
| 因为数据占的空间大,本来一个聚簇索引就占了不少空间 现在又要再创建个跟聚簇索引一样大的次索引,肯定是不行的 | |
| 主键索引(primary key) | |
| 简称主键。它可以提高查询效率, 并提供唯一性约束。 一张表中只能有一个主键。被标志为自动增长的字段一定是主键(非主键字段不可自增), | |
| 但主键不一定自动增长。一般把主键定义在无意义的字段上(如: 编号), 主键的数据类型最好是数值。 | |
| 全文索引(fulltext) | |
| 做全文检索使用的索引, 我们有更好的替代品ElasticSearch,所以实际使用不多,只当了解。 | |
| 通过数值比较、范围过滤等就可以完成绝大多数我们需要的查询, 但是 如果希望通过关键字的匹配来进行查询过滤, | |
| 那么就需要基于相似度的查询, 不是原来的精确数值比较。全文索引就是为这种场景设计的。 | |
| 为什么不用like + %实现模糊匹配, 要全文索引? | |
| like + %在文本比较少时是合适的, 但是对于大量的文本数据检索是不可想象的。 | |
| 全文索引在大量的数据面前能比like + %快N倍, 速度不是一个数量级, 但是全文索引可能存在精度问题。 | |
| 你可能没有注意过全文索引, 不过至少应该对一种全文索引技术比较熟悉:各种的搜索引擎。虽然搜索引擎的索引对象是超大的数据, | |
| 并且通常其背后都不是关系型数据库, 不过全文索引的基本原理是一样的。 | |
| 创建全文索引 | |
| create fulltext index 索引名称 on 表名(字段名) | |
| alter table 表名 add fulltext(字段名) | |
| 空间索引(spatial) | |
| 这是在地理位置领域使用的一种索引 | |
| hash索引 | |
| hash索引速度快 可以快速定位到目标 时间复杂度为o(1), 但是hash是无序的。 | |
| 由于是无序的 所以有相同特征的key计算出来可能相隔很远 连续查询效率底下, 即不支持范围查询 | |
| hash索引存储的是计算得到的hash值和行指针, 而不存储具体的行值, 所以通过hash索引查询数据需要进行两次查询(首先查询行的位置,然后找到具体的数据) | |
| hash索引查询数据的前提就是计算hash值, 也就是要求key为一个能准确指向一条数据的key, 所以对于like等一类的匹配查询是不支持的。 | |
| 所以我们可以知道的是hash索引适用于快速选取某一行的数据, 超级大表中定位某一行特别快。 | |
| 只要是只需要做等值比较查询, 而不包含排序或范围查询的需求, 都适合使用哈希索引。 | |
| 普通索引/常规索引(normal) | |
| 创建普通索引 | |
| 创建表时添加: index 索引名称 (字段名称) | |
| 创建完表添加: create index 索引名称 on 表名称(字段名称) | |
| 创建短索引(短索引可以减少索引的体积 减少检索的时间提升查询的效率) | |
| 创建完表添加: create index 索引名称 on 表名称(字段名称(length)) | |
| 删除索引 | |
| drop index 索引名称 on 表名称 | |
| 唯一索引(unique) | |
| 主键是一种约束, 唯一索引是一种索引, 两者在本质上是不同的。 | |
| 主键创建后一定包含一个唯一性索引, 唯一性索引并不一定就是主键。 | |
| 主键列不允许为空值, 而唯一性索引列允许空值。 | |
| 主键列在创建时, 已经默认为非空值+唯一索引了。 | |
| 主键可以被其他表引用为外键, 而唯一索引不能。 | |
| 一个表最多只能创建一个主键, 可以创建多个唯一索引。 | |
| 主键更适合那些不容易更改的唯一标识, 如自动递增列、身份证号等。 | |
| 唯一索引列不能有重复的值, 唯一索引不一定非要有唯一约束 | |
| 创建唯一索引 | |
| create unique index 索引名称 on 表名称(字段名) | |
| 复合索引 | |
| 索引的组合使用(索引合并) 效率是低于复合索引的。当有多个查询条件时,推荐使用复合索引。 | |
| 比如:我们经常按照A列B列C列进行查询时, 通常的做法是建立一个由三个列共同组成的复合索引而不是对每一个列建立普通索引。 | |
| 创建索引 | |
| create index 索引名称 on 表名(字段名1,字段名2) | |
| 注意事项 | |
| 1.最左前缀匹配原则, mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配, 后面的索引将全部失效。 | |
| 比如a=1 and b=2 and c>3 and d=4, 如果建立(a,b,c,d)顺序的索引 c是范围查询 d的索引就失效了, | |
| 如果建立(a,b,d,c)的索引则都可以用到, a,b,d的顺序可以任意调整。 | |
| 2.=和in可以乱序,比如a=1 and b=2 and c=3建立(a,b,c)索引可以任意顺序, mysql的查询优化器会帮你优化成索引可以识别的形式。 | |
| 3.等值的字段放前面, 范围查询的字段一定要放到最后 | |
| 最左前缀匹配原则: | |
| 左边的条件一定要是定值 不可以是范围, 比如A列索引是2, 3,3,3, 12,12,12,12 B列对应的数据是99, 3,4,2, 2,3,1,4。 | |
| 此时进行排序时B列数据就可以依赖A列数据进行排序为: 99, 2,3,4, 1,2,3,4。A在等值的情况下, 依赖A列的B列数据是有序的。 | |
| 如果条件是范围查询 A>3 and A<99, B列就不知道具体的值了 也就无法根据A的值进行排序了 | |
| ------------------------------------------------------------------------------------------------------------------------------------------------------- | |
| explain | |
| explain关键字可以模拟mysql优化器执行sql语句 可以很好的分析sql语句或表结构的性能瓶颈 | |
| 用途: 表的读取顺序如何 数据读取操作有哪些操作类型 哪些索引可以使用 哪些索引被实际使用 表之间是如何引用 每张表有多少行被优化器查询 | |
| 用法: explain 要分析的sql语句 | |
| id select查询的序列号, 表示查询中执行select子句或操作表的顺序 | |
| select_type 查询的类型(是简单查询还是子查询等) | |
| table 正在访问哪个表 | |
| partitions 匹配的分区 | |
| * type 访问的类型 | |
| Null > system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL | |
| const: 表示通过索引一次就找到了(唯一索引定值查) | |
| ref: 非唯一性索引扫描, 返回匹配某个单独值的所有行(普通索引定值查) | |
| range: 只检索给定范围的行(索引范围查 索引在key中显示) | |
| index: 索引全扫描 只扫描索引树(如果搜索的数据大于总数据的50% 就会全表扫) | |
| all: 全表扫 差率最差 | |
| possible_keys 显示可能应用在这张表中的索引,一个或多个,但不一定实际使用到 | |
| * key 实际使用到的索引,如果为NULL,则没有使用索引 | |
| key_len 表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度 | |
| ref 显示索引的哪一列被使用了,如果可能的话,是一个常数,哪些列或常量被用于查找索引列上的值 | |
| * rows 根据表统计信息及索引选用情况,大致估算出找到所需的记录所需读取的行数 | |
| filtered 查询的表行占表的百分比 | |
| Extra 包含不适合在其它列中显示但十分重要的额外信息 | |
| ------------------------------------------------------------------------------------------------------------------------------------------------------- | |
| 事务 | |
| 在mysql中只有使用了innodb数据库引擎的数据库或表才支持事务 | |
| 事务处理可以用来维护数据库的完整性 保证成批的sql语句要么全部执行 要么全部不执行 | |
| 事务用来管理insert update delete语句 | |
| 事务的四大特性: | |
| 原子性(Atomicity): | |
| 一个事务 要么全部完成 要么全部失败, 不会结束在中间的某个环节。如果执行中发生错误 会回滚(Rollback)到事务开始前的状态 | |
| 一致性(Consistency): | |
| 在事务开始之前和事务结束以后, 数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则, | |
| 这包含资料的精确度串联性以及后续数据库可以自发性地完成预定的工作。(比如: A向B转账,不可能A扣了钱,B却没有收到) | |
| 隔离性(Isolation): | |
| 数据库允许多个并发事务同时对其数据进行读写和修改的能力, 隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。 | |
| 事务隔离分为不同级别, 包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。 | |
| (比如: A正在从一张银行卡里面取钱, 在A取钱的过程中, B不能向这张银行卡打钱) | |
| 持久性(Durability): | |
| 事务处理完毕后 对数据的修改是永久性的, 即使系统故障也不会丢失 | |
| begin 开启事务、 commit 提交事务、 rollback 回滚事务 | |
| 设置隔离级别 | |
| set session transaction isolation level repeatable read; 设置 会话 事务 隔离 级别 为可重复读 | |
| 事务的隔离性级别 | |
| 查看隔离级别: show variables like '%iso%' | |
| 读未提交: read uncommitted | |
| 在该隔离级别, 所有事务都可以看到其他未提交事务的执行结果 | |
| 会出现的问题: 脏读 不可重复读 幻读 | |
| 脏读(Dirty Read): 对于两个事务T1与T2, T1读取了已经被T2更新但是还没有提交的字段之后, 若此时T2回滚, T1读取的内容就是临时并且无效的 | |
| 读已提交: read committed (针对delete update) | |
| 事务只能看到别的事务已提交的数据 | |
| 会出现的问题: 不可重复读 幻读 | |
| 不可重复读(NonRepeatable Read): 同一事务的其他实例在该实例处理期间可能会有新的commit, 所以同一select可能返回不同结果。 | |
| 可重复读: repeatable read (针对delete insert) | |
| 确保同一事务的多个实例在并发读取数据时, 其值都和事务开始时候的内容是一致, 禁止读取到别的事务未提交的数据 | |
| 会出现的问题: 幻读 | |
| 幻读(Phantom Read): 幻读指当用户读取某一范围的数据行时, 另一个事务又在该范围内插入了新行, 导致结果不一致的情况发生(mysql的MVCC已解决此问题) | |
| 串行化: serializable | |
| 这是最高的隔离级别, 它通过强制事务排序, 使之不可能相互冲突, 从而解决幻读问题。 | |
| 简言之, 它是在每个读的数据行上加上共享锁。在这个级别, 可能导致大量的超时现象和锁竞争。 | |
| 会出现的问题: 无 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Spring框架 | |
| Spring是为了解决企业开发的难度的 减轻对项目模块之间的管理 类和类之间的管理 帮助开发人员创建对象 管理对象之间的关系 | |
| <<!! Spring的核心: ioc , aop 能实现模块之间 类之间的解耦合 !!>> | |
| 概述: | |
| Spring本质上就是一个"Map"容器 在Spring配置文件的<bean id="" class="">中 指定要使用的类的路径 Spring就会把这个类路径 | |
| 作为map的value值保存到一个map集合中。这个map集合的key值就是<bean>中自定义的id属性 value值就是<bean>中的class属性 Spring执行时 | |
| 会把自动把这个value值创建为一个对象 当调用这个容器的key值时 就可以获得这个由Spring创建好的对象 | |
| 优势 | |
| 低侵入 / 低耦合 (降低组件之间的耦合度,实现软件各层之间的解耦) | |
| 声明式事务管理(基于切面和惯例) | |
| 方便集成其他框架(如MyBatis、Hibernate) | |
| 降低 Java 开发难度 | |
| Spring 框架中包括了 J2EE 三层的每一层的解决方案(一站式) | |
| ================================================================================================================================== | |
| 一些概念 | |
| javaBean | |
| javaBean是一种Java语言写成的可重用组件。为写成JavaBean,类必须是具体和公共的,并且具有无参数的构造器。还要实现Serializable接口 | |
| JavaBean通过提供符合一致性设计模式的公共方法将内部域暴露成员属性。更多的是一种规范,即包含一组set和get方法的java对象。 | |
| javaBean可以使应用程序更加面向对象,可以把数据封装起来,把应用的业务逻辑和显示逻辑分离开,降低了开发的复杂程度和维护成本。 | |
| pojo | |
| Plain Ordinary Java Object 简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称。 | |
| 其中有一些属性及其getter、setter方法的类,没有业务逻辑,有时可以作为VO(value-object)或DTO(Data Transfer Object)来使用。 | |
| 不允许有业务方法,也不能携带connection之类的方法。与javaBean相比,javaBean则复杂很多,JavaBean是可复用的组件,对JavaBean并没有严格的规范, | |
| 理论上讲,任何一个Java类都可以是一个Bean。但通常情况下,由于JavaBean是被容器创建的,所以JavaBean应具有一个无参的构造器。 | |
| 另外,通常JavaBean还要实现Serializable接口用于实现Bean的持久性。一般在web应用程序中建立一个数据库的映射对象时,我们只能称他为POJO。 | |
| 用来强调它是一个普通的对象,而不是一个特殊的对象,其主要用来指代哪些没有遵从特定的java对象模型、约定或框架(如EJB)的java对象。 | |
| 理想的讲,一个POJO是一个不受任何限制的java对象 | |
| entity | |
| 实体bean,一般是用于ORM对象关系映射,一个实体映射成一张表,一般无业务逻辑代码。负责将数据库中的表记录映射为内存中的Entity对象, | |
| 事实上,创建一个EntityBean对象相当于创建一条记录,删除一个EntityBean对象会同时从数据库中删除对应记录,修改一个Entity Bean时, | |
| 容器会自动将Entity Bean的状态和数据库同步 | |
| 传统javabean与spring中的bean的区别 | |
| javabean已经没人用了, spring bean可以说是javabean的发展, 但已经完全不是一回事儿了 | |
| 用处不同:传统javabean更多地作为值传递参数,而spring中的bean用处几乎无处不在,任何组件都可以被称为bean。 | |
| 写法不同:传统javabean作为值对象,要求每个属性都提供getter和setter方法;但spring中的bean只需为接受设值注入的属性提供setter方法。 | |
| 生命周期不同:传统javabean作为值对象传递,不接受任何容器管理其生命周期;spring中的bean有spring管理其生命周期行为。 | |
| 所有可以被spring容器实例化并管理的java类都可以称为bean。 | |
| 原来服务器处理页面返回的值都是直接使用request对象,后来增加了javabean来管理对象,所有页面值只要是和javabean对应,就可以用类.GET属性方法来获取值。 | |
| javabean不只可以传参数,也可以处理数据,相当与把一个服务器执行的类放到了页面上,使对象管理相对不那么乱(对比jsp的时候所有内容都在页面上完成)。 | |
| spring中的bean,是通过配置文件、javaConfig等的设置,由spring自动实例化,用完后自动销毁的对象。让我们只需要在用的时候使用对象就可以, | |
| 不用考虑如何创建类对象(这就是spring的注入)。一般是用在服务器端代码的执行上 | |
| Bean的生命周期 | |
| 先调用构造方法,然后使用set方法注入,之后init初始化,然后使用Bean,最后销毁 | |
| ================================================================================================================================== | |
| spring框架结构 | |
| 核心容器(Spring core) | |
| 核心容器提供Spring框架的基本功能。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用BeanFactory来产生和管理Bean, | |
| 它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开。BeanFactory使用依赖注入的方式提供给组件依赖。 | |
| Spring上下文(Spring context) | |
| Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能。 | |
| Spring面向切面编程(Spring AOP)通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以, | |
| 可以很容易地使 Spring框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。 | |
| 通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。 | |
| Spring DAO模块 | |
| DAO模式主要目的是将持久层相关问题与一般的的业务规则和工作流隔离开来。Spring 中的DAO提供一致的方式访问数据库,不管采用何种持久化技术, | |
| Spring都提供一直的编程模型。Spring还对不同的持久层技术提供一致的DAO方式的异常层次结构。 | |
| Spring面向切面编程(Spring AOP) | |
| 通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以,可以很容易地使 Spring框架管理的任何对象支持 AOP。 | |
| Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。 | |
| Spring ORM模块 | |
| Spring 与所有的主要的ORM映射框架都集成的很好,包括Hibernate、JDO实现、TopLink和IBatis SQLMap等。 | |
| Spring为所有的这些框架提供了模板之类的辅助类,达成了一致的编程风格。 | |
| Spring Web模块 | |
| Web上下文模块建立在应用程序上下文模块之上,为基于Web的应用程序提供了上下文。Web层使用Web层框架, | |
| 可选的,可以是Spring自己的MVC框架,或者提供的Web框架,如Struts、Webwork、tapestry和jsf。 | |
| Spring MVC框架(Spring WebMVC) | |
| MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。 | |
| Spring的MVC框架提供清晰的角色划分:控制器、验证器、命令对象、表单对象和模型对象、分发器、处理器映射和视图解析器。Spring支持多种视图技术 | |
| Bean的作用域 | |
| Spring IOC容器创建一个Bean实例时,可以为Bean指定实例的作用域, | |
| 作用域包括singleton(单例模式)、prototype(原型模式)、request(HTTP请求)、session(会话)、global-session(全局会话)。 | |
| (1)Singleton | |
| 当一个bean的作用域为Singleton那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配, | |
| 则只会返回bean的同一实例。Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了, | |
| 每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成singleton,可以这样配置: | |
| <bean id="userServiceImpl" class=""xx.xxx.xxxImpl"> | |
| (2)Prototype | |
| 当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求 | |
| (将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器 | |
| 的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。 | |
| 根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在XML中将bean定义成prototype,可以这样配置: | |
| <bean id="account" class="xxx.xxx.entity.User" scope="1 prototype"/> | |
| (3)Request | |
| 当一个bean的作用域为Request表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP请求都会有各自的bean实例, | |
| 它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义: | |
| <bean id="loginAction" class="com.xinzhi.entity.User" scope="request"/> | |
| (4)Session | |
| 当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。 | |
| 考虑下面bean定义: | |
| <bean id="userPreferences" class="com.xinzhi.entity.User" scope="session"/> | |
| 针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的 | |
| userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作 | |
| 用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的HTTP Session中根据 | |
| userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session | |
| 最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃掉。 | |
| ================================================================================================================================== | |
| IOC容器 | |
| IoC(Inversion of Control: 控制反转): | |
| <<!!是一个理论/概念/思想 把对象的创建 赋值 管理工作都交给"容器"来创建/实现!!>> 自己只需要在配置文件中写参数即可 此功能是由DI实现的 | |
| 就像servlet的对象是浏览器完成创建的 使用IoC的目的就是减少对代码的改动 也能实现不同的功能 对业务对象之间的解耦合 例如service和dao对象之间的耦合 | |
| 控制: 创建对象 对对象的属性赋值 对象之间的关系管理。当前对象对内成员的控制权 | |
| 反转: 把原来开发人员管理 创建对象的权限交给容器实现, 由容器代替开发人员管理创建对象 给属性赋值 | |
| 正转: 由开发人员在代码中 使用new构造方法创建对象 给属性赋值。开发人员主动管理对象 | |
| 容器: 是一个服务器软件 一个框架(spring) | |
| DI: | |
| DI(Dependency Injection:依赖注入)是ioc的技术实现 只需要在程序中提供要使用的对象名称就可以了 | |
| spring是使用DI实现的IoC功能的 spring底层是使用反射机制创建对象的 | |
| DI的实现有两种: | |
| 1.在spring的配置文件中 使用标签属性完成 叫做基于XML的di实现 | |
| 2.使用spring中的注解 完成属性赋值 叫做基于注解的di实现 | |
| 使用DI创建SpringBean对象: | |
| 在spring配置文件中配置<bean>标签: <bean id=" " class=" "/> | |
| id: 自定义的别名 代表了class属性指定的类 | |
| class: 类的全限定名称(spring使用的反射机制创建的对象 所以只能写类名) | |
| spring会把<bean>创建成对象并且保存进map集合中 这个集合中的key值就是<bean>的id属性 value就是<bean>的Class属性 | |
| Spring封装的<bean>的Map集合: map.put("XXX","new com.xu.Student()") | |
| ApplicationContext: 表示Spring容器 在创建spring容器的时候 会创建配置文件中标识的所有对象, 并且把创建好的对象保存到spring容器的value值中 | |
| ClassPathXmlApplicationContext:从类路径加载spring的配置文件 | |
| --- ApplicationContext ac = new ClassPathXmlApplicationContext(config.xml); | |
| 通过Spring容器的key值拿到对应的value值的对象(此时value表示的类已经是一个对象了) | |
| "getBean"这个方法返回的对象就是Spring容器中创建好的对象 | |
| --- SomeServlet someServlet = (SomeServlet) ac.getBean(bean标签的id); | |
| 基于xml的DI实现 给SpringBean的属性赋值: | |
| <property>和<constructor-arg>都是在<bean>中编写的,就是在bean创建时对其成员参数进行赋值 | |
| 1.set注入: spring调用Bean的set方法 往set方法传入参数对其进行赋值。如果只有属性 没有set方法 此时给属性赋值就会报错 | |
| <property name="" value=""/>: name是Bean的参数名 | |
| 2.构造注入: Spring调用Bean中的构造方法 往构造方法中传入参数完成赋值。构造方法中如果没有对应的形参 则会编译报错 | |
| <constructor-arg name="" value=""/>: 按参数名称注入 | |
| <constructor-arg index="" value=""/>: 按位置注入,index是构造方法的形参列表的位置 从零开始 | |
| <constructor-arg value=""/>: 直接注入 按照形参列表的顺序注入 | |
| <constructor-arg type="" value=""/>: 按照构造方法的参数的数据类型注入 | |
| set注入和构造注入都可以注入其他类型的数据 | |
| <property name="" value="" /> 基本数据注入 | |
| <property name="user" ref="userREF"/> 引用类型注入(引用类型注入 需要使用自动注入或者使用<bean>声明出引用 把引用的id放到这里) | |
| <bean id="userREF" class="com.xu.userDao"> <property name='' value=''></property> </bean> | |
| <property name=""> <array> <value></value> </array> </property> 数组注入 | |
| <property name=""> <list> <value></value> </list> </property> list注入 | |
| <property name=""> <set> <value></value> </set> </property> set注入 | |
| <property name="familyTies"> <map> <entry key="" value="" /> </map> </property> map注入 | |
| <property name="workExperience"> <props> <prop key="">xxxx</prop> </props> </property> property注入 | |
| <property name="daughter"><null /></property> null注入 | |
| 标签中ref引用类型的自动注入 | |
| 3.自动注入(按属性名称注入): 当bean中的"ref引用类型"的参数名称和<bean>的id名称一致时 在<bean>中 | |
| 使用"autowire="byName"" spring就会把id属性表示的类赋值给当前bean中的引用类型 | |
| 如果使用了自动注入,spring就会把下面那个<bean id="AAA">自动注入到当前这个Bean中 | |
| 当前这个bean就不需要写<property id="aaa" ref="AAA">引入AAA了 | |
| <bean id="user" class="com.xu.user" autowire="byName"> | |
| <property id="aaa" ref="AAA"> | |
| </bean> | |
| <bean id="AAA" class="xxx"> | |
| <property id="xxx" class="xxx"> | |
| </bean> | |
| 从javaBean的set方法获取名字,如setAAA,就去spring容器中找名字为AAA的bean。如果有,就取出注入; | |
| 如果没有,就不注入。所有名称不能出现错误,名称错了就找不到要注入的这个bean了 | |
| 4.自动注入(按类型注入): 当bean中的"ref引用类型"的参数和<bean>的class属性类型是同源关系时在<bean>中 | |
| 使用"autowire="byType"" spring就会把class属性表示的类赋值给当前bean中的引用类型 | |
| 同源: 同一类 | |
| java类中引用类型的数据类型和<bean>的class属性的值是一样的 | |
| java类中引用类型的数据类型和<bean>的class属性的值是父子关系 | |
| java类中引用类型的数据类型和<bean>的class属性的值是接口和实现类关系 | |
| 主配置文件: | |
| 当配置文件多了以后 可以使用一个只存放配置文件路径的主配置文件包裹所有配置文件 读取时只需要读取主配置文件即可 | |
| <import resource="classpath:配置文件的路径">: 指定配置文件的路径 多个配置文件中的<bean>不可以发生冲突! | |
| <import resource="classpath:*.*">: 通配符的读取形式 | |
| 1.多个配置文件必须在同一级文件中 否则读取不到 | |
| 2.通配符的匹配结果中不可以包括主配置文件自身 会出现死循环 | |
| 基于注解的DI实现 给SpringBean的属性赋值: | |
| 1.在配置文件中创建一个组件扫描器: | |
| <context:component-scan base-package="使用了注解的类"/> | |
| 组件扫描器会扫描指定的包和子包中的所有类 查找带有注解的类 将其创建为对象或者赋值 | |
| 2.注解给属性赋值: | |
| 给普通类型赋值: | |
| @Value(value=""): 声明在类中的属性上 给这个属性直接赋值(必须先声明当前类 把当前类创建为对象), 声明在set方法上 使用set方法进行赋值 | |
| 给引用类型赋值: | |
| @Autowired: 声明在引用类型上 使用的是按类型自动注入(byType) 需要先把引用类型的类声明创建为对象 | |
| required属性: 如果为true 表示如果引用类型赋值失败 程序报错并终止(建议使用 可以尽早发现问题) | |
| 如果为false 表示如果引用类型赋值失败 程序正常执行 引用类型赋值null | |
| @Qualifier(value=""): 和@Autowired注解一起声明 使用的是按属性自动注入(byName) value值要和引用类型指定的名称一致 | |
| @Resource: 来自jdk javax.annotation包中的注解 需要导入依赖 可以用来给引用类型赋值 默认使用的是"byName"自动注入 | |
| spring会先使用"byName"自动注入 如果byName注入失败 就会使用byType自动注入。如果指定"name"属性 则只使用byName注入 | |
| 注意: 必须先使用配置文件/注解把类声明为对象才可以对其进行赋值操作 | |
| 3.使用"ClassPathXmlApplicationContext"对象的"getBean"方法 读取在@Component注解中给的别名"value" 获得被注解标识的类的对象 | |
| @Component如果没有指定value的别名 spring会默认使用类名(首字母小写)的方式进行命名 | |
| 使用配置类给Bean的属性赋值初始化 | |
| 类上需要使用@Configuration, 此注解会把此类放入到容器中。方法上是使用@Bean | |
| 使用classPathXmlApplication()的getBean("usera")方法获取方法即可。 | |
| @Configuration | |
| public class userConfig { | |
| @Bean | |
| public User usera(){ | |
| return new User(){{ | |
| setName("小怜"); | |
| setAge(18); | |
| setEx("test"); | |
| }}; | |
| } | |
| } | |
| 分层开发 | |
| 三层架构: controller: 界面层 service: 业务逻辑层 dao: 持久层。 | |
| 区分层次的目的即为了"高内聚低耦合"的思想。在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。 | |
| 微软推荐的分层式结构一般分为三层,从下至上分别为:数据访问层、业务逻辑层(又或称为领域层)、表示层。 | |
| 注解(创建对象): | |
| @Mapper: 持久层的注解 放在dao的实现类上面 表示创建dao对象 dao对象是能访问数据库的 | |
| @Service: 放在业务层类的上面 在service的实现类上面 表示创建service对象 service对象是做业务处理 可以有事务等功能 | |
| @Controller: 放在控制器的上面 放在控制器(处理器)类上面 表示创建控制器对象的 控制器对象能接受用户提交的参数 显示请求的处理结果 | |
| @Component: 创建对象的 等同于<bean>的功能 value是对象的名称 也就是<bean>的id值(如果不指定 默认就是类名的首字母小写"student") | |
| value值是唯一的 创建的对象在整个spring容器中就一个 此注解必须在类的上面定义 等同于创建了一个Student的对象并存入到容器 | |
| 当一个类不是这三个注解所表示的范围内 使用"@Component"注解 | |
| ========================================================================================================================== | |
| AOP(Aspect Orient Programming: 面向切面编程): | |
| 什么是AOP | |
| AOP(Aspect Oriented Programming)称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待。 | |
| 在不改变原有的逻辑的基础上,增加一些额外的功能。代理也是这个功能。 | |
| AOP可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构, | |
| 用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布 | |
| 在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此, | |
| 这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。 | |
| AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块, | |
| 并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来, | |
| 便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。 | |
| 使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。 | |
| 横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。 | |
| AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。 | |
| AOP就是动态代理的规范化 AOP把动态代理的实现步骤 方式都定义好了 让使用者用一种统一的方式进行操作 | |
| AOP可以在目标类源代码不改变的情况下增加功能 较少代码的重复 专注业务逻辑代码 解耦合让业务功能和非业务功能分离 | |
| 什么时候用AOP? | |
| 例如有一个类 需要给他增加功能, 但是没有源代码 此时就可以使用AOP给他增加切面 | |
| 项目中有多个类都需要实现相同的功能 使用AOP | |
| 给项目增加事务 日志输出 | |
| Aspect(切面): 给你的目标类"增加的功能"就是切面 像日志 事务等都是切面 | |
| 切面的特点: 一般都是非业务方法(业务就是处理逻辑的 非业务就是跟业务逻辑没关系的,可以独立使用的) | |
| 切面的三个关键要素: | |
| 1.切面的功能代码 切面要干什么 | |
| 2.切面的执行代码 使用Pointcut(切入点)表示切面执行的位置 | |
| 3.切面的执行时间 使用Advice(通知/增强)表示执行时间 是在目标方法之前还是在之后 | |
| AOP的实现 底层使用的是动态代理模式实现的 有两种: | |
| 1.JDK的动态代理: 使用的是jdk中的Proxy Method InvocationHandler创建代理对象 jdk的动态代理要求目标类必须实现接口 | |
| 2.CGLIB的动态代理: 使用的是第三方的工具库创建代理对象 原理是继承 通过继承目标类创建子类 子类就是代理对象 要求目标类不可以是final的 | |
| CGLIB(Code Generator Library)是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架(Spring、dynaop)中,用以提供方法拦截操作。 | |
| 自动选择: | |
| 当有接口时 AOP会选择"JDK"动态代理(必须实现接口) 当没有接口时 AOP会使用"CGLIB"动态代理(目标类不可以时final的) | |
| 当有接口时还想使用"CGLIB"时 在配置文件中使用"<aop:aspectj-autoproxy proxy-target-class="true"/>"即可 | |
| 和AOP相关的名词: | |
| 通知、增强处理(Advice) | |
| 就是你想要的功能,也就是上说的安全、事物、日子等。你给先定义好,然后再想用的地方用一下。包含Aspect的一段处理代码 | |
| 连接点(JoinPoint) | |
| 就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的钱、后(两者都有也行),或抛出异常是时都可以是连接点, | |
| spring只支持方法连接点。其他如AspectJ还可以让你在构造器或属性注入时都行,不过那不是咱们关注的,只要记住,和方法有关的前前后后都是连接点。 | |
| 切入点(Pointcut) | |
| 上面说的连接点的基础上,来定义切入点,你的一个类里,有15个方法,那就有十几个连接点了对吧,但是你并不想在所有方法附件 | |
| 都使用通知(使用叫织入),你只是想让其中几个,在调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切入点来定义这几个方法, | |
| 让切点来筛选连接点,选中那几个你想要的方法。 | |
| 切面(Aspect) | |
| 切面是通知和切入点的结合。现在发现了吧,没连接点什么事,连接点就是为了让你好理解切点搞出来的,明白这个概念就行了。 | |
| 通知说明了干什么和什么时候干(什么时候通过方法名中的before,after,around等就能知道),二切入点说明了在哪干(指定到底是哪个方法), | |
| 这就是一个完整的切面定义。 | |
| 引入(introduction) | |
| 允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗 | |
| 目标(target) | |
| 引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面。二自己专注于业务本身的逻辑。 | |
| 织入(weaving) | |
| 把切面应用到目标对象来创建新的代理对象的过程。SpringAOP中,通过Advice定义横切逻辑, | |
| Spring中支持5种类型的Advice:即 Aop 在 不改变原有代码的情况下 , 去增加新的功能 | |
| AOP的aspectJ框架 | |
| aspectJ: 一个开源的专门做AOP的框架 来自eclipse的一个项目 Spring中集成了aspectj框架 通过spring就能直接使用aspectj | |
| 实现: | |
| 0.pom依赖: org.aspectj aspectjweaver | |
| 1.使用' @Aspect '注解声明一个切面类, 切面类中创建切面方法,切面方法上使用切入点表达式指定要给谁加切面 | |
| 2.创建目标对象 目标对象需要实现一个接口(JDK动态代理实现接口 CGlib继承类) | |
| 3.在配置文件中使用"<aop:aspectj-autoproxy/>"标签创建一个"自动代理生成器" | |
| aspect就会在内存中修改"目标对象"的结构 给其增加切面方法 | |
| 注意事项: | |
| 使用getBean()时 只能转换为同级的接口 不能转换为接口的实现类, 否则会报错 | |
| AopTest aopTestImpl = (AopTest) ac.getBean("aopTestImpl"); | |
| 切入点表达式(切入点表达式所表示的方法就是"目标对象" 被切入注解标注的方法就是"连接点"): | |
| execution(方法的修饰符列表 方法的返回值 接口中的方法名(方法的形参列表)) | |
| "*" : 匹配任何数量字符 | |
| "+" : 匹配指定类型的子类型 仅能作为后缀放在类型模式后边 | |
| ".." : 匹配任何数量字符的重复 如在类型模式中匹配任何数量子包 而在方法参数模式中匹配任何数量参数 | |
| 1.切面的执行时间 这个执行时间叫做Advice(通知/增强) 在aspectj框架中使用注解表示 | |
| @After: 在类上声明 可以把类变成一个切面类。在方法上声明 可以让方法变为最终通知(总会被执行 在业务代码后执行 一般做资源清除工作的) | |
| @After(value = "execution()") public void A(){} | |
| @Before: 切入时间 在切面执行之前执行 | |
| @Before(value = "execution()") public void A(JoinPoint jp) {} | |
| @AfterReturning: 切入时间 在切面之后执行 需要指定一个"returning = " ""属性 表示目标方法的返回值 | |
| @AfterReturning(value = "execution()", returning = "name") public void A(JoinPoint join, Object name) {} | |
| @Around: 环绕通知 可以在目标方法之前和之后增加功能, 控制目标方法是否被调用, 修改原来的目标方法的执行结果 | |
| @Around(value = "execution()") public Object A(ProceedingJoinPoint pj){ | |
| pj.proceed(); 执行目标方法 | |
| } | |
| @AfterThrowing: 异常通知 当程序出现异常之后 会执行这个切面 | |
| @AfterThrowing(value = "execution()", throwing = "ex") public void A(Exception ex){} | |
| @Pointcut: 这个注解是用来定义和管理切入点的 如果项目中有多个重复的切入点表达式 就可以使用"@Pointcut"声明 | |
| @Pointcut(value = "execution()") | |
| public void Pointcut(){} | |
| @Before(value = "Pointcut()") | |
| public void A() {} | |
| ========================================================================================================================== | |
| Spring整合MyBatis: | |
| 1.使用spring的IOC技术 把MyBatis框架中使用的对象交给Spring统一创建和管理 | |
| 数据源DataSource对象: 连接数据库的 java中规定实现了javax.sql.DataSource接口的都是数据源 这个接口是用来获取Connection连接的 | |
| SqlSessionFactory对象: 使用的是"SqlSessionFactoryBean"在内部创建"SqlSessionFactory"对象 | |
| DAO代理对象: 使用的"MapperScannerConfigurer"对象 在此对象内部调用"gatMapper()"方法 创建接口的Dao对象并保存进Spring容器中 | |
| 2.把MyBatis的getMapper方法创建对象 的工作交给了Spring的"MapperScannerConfigurer"类来完成 | |
| 3.MyBatis获取"SqlSessionFactory"对象 创建DAO对象 等操作都是在Spring配置文件中完成的 | |
| 实现: | |
| 1.创建一个Spring的配置文件 在Spring配置文件中使用<bean>指定mybatis的信息(这个配置文件的操作是固定的) | |
| 1) 声明数据库的连接信息和"数据源"信息 | |
| 创建"DruidDataSource"数据源对象 | |
| <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> | |
| <property name="username" value="mysql账号"/> | |
| <property name="password" value="mysql密码"/> | |
| <property name="url" value="jdbc:mysql://localhost:3306/数据库?useSSL=false&useUnicode=true&characterEncoding=utf8"/> | |
| <property name="driverClassName" value="com.mysql.jdbc.Driver"/> | |
| </bean> | |
| 创建"jdbcTemplate"对象(不创建也可以) | |
| <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> | |
| <property name="dataSource" ref="dataSource"/> | |
| </bean> | |
| 2) 创建sqlSessionFactory对象 使用"SqlSessionFactoryBean"类 | |
| <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> | |
| <property name="dataSource" ref="dataSource"/> | |
| <property name="mapperLocations" value="classpath:com/xu/mapper/*.xml"/> 扫描mapper.xml文件 | |
| </bean> | |
| 3) 创建DAO对象 使用"MapperScannerConfigurer"类 | |
| <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> | |
| <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> | |
| <property name="basePackage" value="mapper文件的包"/> | |
| </bean> | |
| ========================================================================================================================== | |
| spring的事务处理 | |
| 事务是指:一组sql语句的集合 集合中有多条sql语句 可能是insert update select delete 我们希望这些多个sql语句都能成功或者都失败 | |
| 这些sql语句的执行是一致的 作为一个整体执行 | |
| 在什么时候想到使用事务? | |
| 当我的操作 涉及得到多个表 或者是多个sql语句的insert update delete 需要保证这些语句都是成功才能完成我的功能,或者都失败 保证操作是符合要求的 | |
| 在java代码中写程序 控制事务 此时事务应该放在那里呢? | |
| service类的业务方法上,因为业务方法会调用多个dao方法,执行多个sql语句 | |
| 不同的数据库访问技术 处理事务的对象 方法不同 需要了解不同数据库访问技术使用事务的原理 | |
| 所以Spring提供了一种处理事务的统一模型 能使用统一步骤 方式完成多种不同数据库访问技术的事务处理 | |
| 实现: | |
| spring处理事务的模型 使用的步骤都是固定的 把事务使用的信息提供给spring就可以了 | |
| 1 事务内部提交 回滚事务 使用的事务管理器对象 代替你完成commit rollback | |
| 事务管理器是一个接口和他的众多实现类 | |
| 接口: PlatformTransactionManager 定义了事务重要方法commit rollback | |
| 实现类: spring把每一种数据库访问技术对应的事务处理类都创建好了 | |
| mybatis访问数据库---spring创建好的是DataSourceTransactionManager | |
| hibernate访问数据库----spring创建的是HibernateTransactionManager | |
| 怎么使用: | |
| 你需要告诉spring 你用是那种数据库的访问技术 声明数据库访问技术对于的事务管理器实现类 | |
| 在spring的配置文件中使用<bean>声明就可以了 例如: 要使用mybatis访问数据库 应该在xml配置文件中 | |
| <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> | |
| <property name="dataSource" ref="dataSource"/> | |
| </bean> | |
| 2 你的业务方法需要什么样的事务,说明需要事务的类型 | |
| 说明方法需要的事务: | |
| 事务的隔离级别: 有4个值 | |
| DEFAULT:采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ; Oracle默认为 READ_COMMITTED。 | |
| ➢ READ_UNCOMMITTED:读未提交。未解决任何并发问题。 | |
| ➢ READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。 | |
| ➢ REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读 | |
| ➢ SERIALIZABLE:串行化。不存在并发问题。 | |
| 事务的超时时间: 表示一个方法最长的执行时间 如果方法执行时超过了时间 事务就回滚。单位是秒 整数值 默认是 -1 | |
| 3 事务的传播行为: 控制业务方法是不是有事务的 是什么样的事务的 | |
| 7个传播行为 表示你的业务方法调用时 事务在方法之间是如果使用的 | |
| * PROPAGATION_REQUIRED: | |
| 方法必须在事务内执行 如果当前方法有事务就加入到当前事务中,如果当前方法没有事务则新建一个新事务 | |
| * PROPAGATION_REQUIRES_NEW: | |
| 指定的方法支持当前事务 如果当前方法没有事务 也可以执行 | |
| * PROPAGATION_SUPPORTS: | |
| 指定的方法总是会新建一个事务 如果当前存在事务 则将其挂起,执行完指定方法的事务后才执行当前事务 | |
| PROPAGATION_MANDATORY | |
| PROPAGATION_NESTED | |
| PROPAGATION_NEVER | |
| PROPAGATION_NOT_SUPPORTED | |
| 4 事务提交事务,回滚事务的时机 | |
| 当你的业务方法 执行成功 没有异常抛出 当方法执行完毕 spring在方法执行后提交事务。事务管理器commit(提交) | |
| 当你的业务方法抛出"运行时异常"或ERROR spring执行回滚 调用事务管理器的rollback(回滚) | |
| 运行时异常的定义: RuntimeException 和他的子类都是运行时异常 例如NullPointException NumberFormatException | |
| 当你的业务方法抛出非运行时异常 主要是受查异常时 提交事务 | |
| 受查异常: 在你写代码中 必须处理的异常 例如IOException, SQLException | |
| @Transactional实现: | |
| 适合中小项目使用的注解方案 Spring框架自己用aop实现给业务方法增加事务的功能 使用@Transactional注解添加事务 此注解 | |
| 是Spring框架自己的注解 放在public方法上面 表示当前方法具有事务 可以给注解的属性赋值 表示具体的隔离级别 传播行为 异常信息等等 | |
| 1.在<bean>中声明事务管理器对象 | |
| <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> | |
| <property name="dataSource" ref="dataSource"/> | |
| </bean> | |
| 2.开启事务注解驱动 告诉Spring 要使用注解的方式管理事务 | |
| <tx:annotation-driven transaction-manager="transactionManager"/> | |
| Spring使用aop机制 创建@Transactional所在的类代理对象 给方法加入事务的功能 | |
| Spring给业务方法加入事务: 在业务方法执行之前先开启事务 在业务方法之后提交或者回滚事务 使用aop的环绕通知 | |
| 3.如果事务执行失败了 检查一下application.xml配置文件头有没有 xmlns:tx="http://www.springframework.org/schema/tx" 属性 | |
| 配置文件实现: | |
| 适合大型项目 有很多的类/方法 需要大量的配置事务,使用aspectj框架功能 在spring配置文件中声明类/方法需要的事务 这种方式业务方法和事务配置完全分离 | |
| 1.声明事务管理器对象:<bean id="" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> | |
| 2 声明方法需要的事务类型(配置方法的事务属性【隔离级别 传播行为 超时】) | |
| 3 配置aop: 指定哪些哪类要创建代理 | |
| 总结spring的事务 | |
| 1.管理事务的是 事务管理和他的实现类 | |
| 2.spring的事务是一个统一模型 | |
| 1)指定要使用的事务管理器实现类,使用<bean> | |
| 2)指定哪些类,哪些方法需要加入事务的功能 | |
| 3)指定方法需要的隔离级别,传播行为,超时 | |
| 你需要告诉spring,你的项目中类信息,方法的名称,方法的事务传播行为。 | |
| ======================================================================================================================================= | |
| web项目中使用容器对象 | |
| 怎么实现: | |
| 使用监听器 当全局作用域对象被创建时 创建容器 存入ServletContext | |
| * 使用监听器创建的容器对象 只会被创建一次 可以一直使用, 不适用监听器 程序运行一次 容器对象创建一次 很浪费内存!!! | |
| 1.在web.xml配置文件中注册监听器"ContextLoaderListener" | |
| 监听器被创建对象后会读取"applicationContext.xml"文件 因为在监听器中要创建"ApplicationContext"对象 创建这个对象需要加载配置文件 | |
| 读取配置文件的默认的路径就是"WEB-INF/applicationContext.xml" 如果配置文件不在此目录可以用<context-param>修改这个默认值 | |
| <context-param> | |
| <param-name>contextConfigLocation</param-name> contextConfigLocation:表示配置文件的路径 | |
| <param-value>classpath:applicationContext.xml</param-value> 配置文件的路径 | |
| </context-param> | |
| 注册监听器 | |
| <listener> | |
| <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> | |
| </listener> | |
| 2.从全局作用域"ServletContext"中获取容器对象"WebApplicationContext"即可 | |
| 监听器作用: | |
| 1 创建容器对象: 执行ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); | |
| 2 把容器对象放入到ServletContext: ServletContext.setAttribute(key,ctx) | |
| key: WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE | |
| value: this.context(容器对象) | |
| 监听器会把"容器对象"保存在全局作用域对象中 想要获得"容器对象"就需要使用"getAttribute"方法 通过key值获得全局作用域中保存的 | |
| 这个对象"WebApplicationContext容器对象" 使用这个容器对象的"getBean"方法获得对象 | |
| 监听器可以自己创建, 也可以使用框架中提供好的ContextLoaderListener | |
| ApplicationContext: javaSE项目中使用的容器对象 | |
| WebApplicationContext: web项目中的使用的容器对象 | |
| WebApplicationContext在底层继承了Application类 | |
| Spring官网: sprint.io |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <project xmlns="http://maven.apache.org/POM/4.0.0" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
| <modelVersion>4.0.0</modelVersion> | |
| <groupId>com.xu</groupId> | |
| <artifactId>spring</artifactId> | |
| <version>1.0.1</version> | |
| <properties> | |
| <maven.compiler.source>8</maven.compiler.source> | |
| <maven.compiler.target>8</maven.compiler.target> | |
| </properties> | |
| <dependencies> | |
| <dependency> | |
| <groupId>org.springframework</groupId> | |
| <artifactId>spring-context</artifactId> | |
| <version>5.3.2</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>org.springframework</groupId> | |
| <artifactId>spring-beans</artifactId> | |
| <version>5.3.2</version> | |
| </dependency> | |
| <!-- aspectj切面 --> | |
| <dependency> | |
| <groupId>org.springframework</groupId> | |
| <artifactId>spring-aspects</artifactId> | |
| <version>5.2.7.RELEASE</version> | |
| </dependency> | |
| <!-- 数据库 --> | |
| <dependency> | |
| <groupId>com.alibaba</groupId> | |
| <artifactId>druid</artifactId> | |
| <version>1.1.22</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>org.springframework</groupId> | |
| <artifactId>spring-jdbc</artifactId> | |
| <version>5.2.6.RELEASE</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>mysql</groupId> | |
| <artifactId>mysql-connector-java</artifactId> | |
| <version>5.1.47</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>org.mybatis</groupId> | |
| <artifactId>mybatis</artifactId> | |
| <version>3.5.5</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>org.mybatis</groupId> | |
| <artifactId>mybatis-spring</artifactId> | |
| <version>2.0.5</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>junit</groupId> | |
| <artifactId>junit</artifactId> | |
| <version>4.12</version> | |
| <scope>test</scope> | |
| </dependency> | |
| </dependencies> | |
| <!-- maven中resource文件不会参与编译 | |
| 所以会导致程序运行时读取不了配置文件 加入插件解决 --> | |
| <build> | |
| <resources> | |
| <resource> | |
| <directory>src/main/java</directory> | |
| <includes> | |
| <include>**/*.properties</include> | |
| <include>**/*.xml</include> | |
| </includes> | |
| <filtering>false</filtering> | |
| </resource> | |
| </resources> | |
| </build> | |
| </project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.xu.Aspectj; | |
| import org.springframework.stereotype.Component; | |
| public interface AopTest { | |
| public void AopT(String str); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.xu.Aspectj; | |
| import org.springframework.stereotype.Component; | |
| /* | |
| * 目标类 | |
| * */ | |
| @Component | |
| public class AopTestImpl implements AopTest { | |
| @Override | |
| public void AopT(String str) { | |
| System.out.println("程序执行了....."); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.xu.Aspectj; | |
| import org.aspectj.lang.JoinPoint; | |
| import org.aspectj.lang.ProceedingJoinPoint; | |
| import org.aspectj.lang.annotation.*; | |
| import org.springframework.stereotype.Component; | |
| /* | |
| * 切面类 | |
| * */ | |
| @Aspect | |
| @Component | |
| public class AspectTest { | |
| @Pointcut(value = "execution(public void com.xu.Aspectj.AopTestImpl.AopT(String))") | |
| public void Pointcut(){} | |
| @Before(value = "Pointcut()") | |
| public void A(JoinPoint joinPoint){ | |
| System.out.println("Before AOP执行了==========="); | |
| } | |
| @AfterReturning(value = "Pointcut()") | |
| public void B(JoinPoint joinPoint){ | |
| System.out.println("afterRetuning AOP执行了==========="); | |
| } | |
| @Around(value = "Pointcut()") | |
| public void Around(ProceedingJoinPoint pj){ | |
| System.out.println("环绕通知================="); | |
| try { | |
| pj.proceed(); | |
| } catch (Throwable throwable) { | |
| throwable.printStackTrace(); | |
| } | |
| System.out.println("环绕通知结束--------------------"); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.xu.Aspectj; | |
| public class ttest { | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.xu.dao; | |
| //@Component | |
| public class User { | |
| // @Value("asd") | |
| String Name; | |
| // @Value("11") | |
| int Age; | |
| String Ex; | |
| @Override | |
| public String toString() { | |
| return "User{" + | |
| "Name='" + Name + '\'' + | |
| ", age=" + Age + | |
| ", ex='" + Ex + '\'' + | |
| '}'; | |
| } | |
| public User() { | |
| } | |
| public User(String name, int age, String ex) { | |
| Name = name; | |
| this.Age = age; | |
| this.Ex = ex; | |
| } | |
| public String getName() { | |
| return Name; | |
| } | |
| public void setName(String name) { | |
| Name = name; | |
| } | |
| public int getAge() { | |
| return Age; | |
| } | |
| public void setAge(int age) { | |
| this.Age = age; | |
| } | |
| public String getEx() { | |
| return Ex; | |
| } | |
| public void setEx(String ex) { | |
| this.Ex = ex; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.xu.dao; | |
| import org.springframework.context.annotation.Bean; | |
| import org.springframework.context.annotation.Configuration; | |
| @Configuration | |
| public class UserConfig { | |
| @Bean | |
| public User user(){ | |
| return new User(){{ | |
| setName("小怜"); | |
| setAge(18); | |
| setEx("test"); | |
| }}; | |
| } | |
| /* | |
| @Bean | |
| public JdbcTemplate jdbcTemplate(){ | |
| DruidDataSource dds = new DruidDataSource(); | |
| dds.setUsername("root"); | |
| dds.setPassword("love500"); | |
| dds.setUrl("jdbc:mysql://localhost:3306/dd?useSSL=false&useUnicode=true&characterEncoding=utf8"); | |
| dds.setDriverClassName("com.mysql.cj.jdbc.Driver"); | |
| JdbcTemplate jdbcTemplate = new JdbcTemplate(); | |
| jdbcTemplate.setDataSource(dds); | |
| return jdbcTemplate; | |
| } | |
| */ | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.xu.mapper; | |
| import com.xu.dao.User; | |
| import org.apache.ibatis.annotations.Mapper; | |
| import org.apache.ibatis.annotations.Param; | |
| @Mapper | |
| public interface UserTest { | |
| public User selectUser(); | |
| public int updateUser(@Param("upAge") Integer upAge,@Param("age") Integer age); | |
| public int deleteUser(@Param("age") Integer age); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8" ?> | |
| <!DOCTYPE mapper | |
| PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |
| "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |
| <mapper namespace="com.xu.mapper.UserTest"> | |
| <select id="selectUser" resultType="com.xu.dao.User"> | |
| select * from usera; | |
| </select> | |
| <update id="updateUser" parameterType="com.xu.dao.User"> | |
| update usera set age = #{upAge} where age = #{age} | |
| </update> | |
| <delete id="deleteUser" parameterType="com.xu.dao.User"> | |
| delete from usera where age = #{age} | |
| </delete> | |
| </mapper> | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.xu.service; | |
| import org.springframework.stereotype.Service; | |
| @Service | |
| public interface UserService { | |
| void transactionTest(); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.xu.service; | |
| import com.xu.mapper.UserTest; | |
| import org.springframework.transaction.annotation.Isolation; | |
| import org.springframework.transaction.annotation.Propagation; | |
| import org.springframework.transaction.annotation.Transactional; | |
| @Transactional( | |
| propagation = Propagation.REQUIRED, | |
| isolation = Isolation.DEFAULT, | |
| readOnly = false, | |
| rollbackFor = { | |
| ArithmeticException.class, NullPointerException.class | |
| } | |
| ) | |
| public class UserServiceImpl implements UserService { | |
| private UserTest userDao; | |
| public void setUserDao(UserTest userDao) { | |
| this.userDao = userDao; | |
| } | |
| @Override | |
| public void transactionTest() { | |
| userDao.updateUser(1,99); | |
| userDao.deleteUser(12); | |
| throw new NullPointerException(); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <beans xmlns="http://www.springframework.org/schema/beans" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" | |
| xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" | |
| xmlns:aop="http://www.springframework.org/schema/aop" | |
| xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd | |
| http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd | |
| http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd | |
| http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd | |
| http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> | |
| <!-- 注解扫描器 --> | |
| <context:component-scan base-package="com.xu"/> | |
| <!-- 自动代理生成器 --> | |
| <aop:aspectj-autoproxy/> | |
| <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> | |
| <property name="username" value="root"/> | |
| <property name="password" value="love500"/> | |
| <property name="url" value="jdbc:mysql://localhost:3306/dd?useSSL=false&useUnicode=true&characterEncoding=utf8"/> | |
| <property name="driverClassName" value="com.mysql.jdbc.Driver"/> | |
| </bean> | |
| <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> | |
| <property name="dataSource" ref="dataSource"/> | |
| </bean> | |
| <!--配置SqlSessionFactory--> | |
| <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> | |
| <property name="dataSource" ref="dataSource"/> | |
| <!-- mapper.xml文件所在的位置 --> | |
| <property name="mapperLocations" value="classpath:com/xu/mapper/*.xml"/> | |
| </bean> | |
| <!-- mapper扫描器: 扫描包下的mapper.xml文件 --> | |
| <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> | |
| <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> | |
| <property name="basePackage" value="com.xu.mapper"/> | |
| </bean> | |
| <bean id="userServiceImpl" class="com.xu.service.UserServiceImpl"> | |
| <property name="userDao" ref="userTest"/> | |
| </bean> | |
| <!-- 注解使用的 声明事务管理器 | |
| 使用Spring的事务处理 --> | |
| <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> | |
| <!-- 指定数据源 --> | |
| <property name="dataSource" ref="dataSource"/> | |
| </bean> | |
| <!-- 开启事务注解,并配置一个事务管理器 --> | |
| <tx:annotation-driven transaction-manager="transactionManager"/> | |
| </beans> | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8" ?> | |
| <!DOCTYPE configuration | |
| PUBLIC "-//mybatis.org//DTD Config 3.0//EN" | |
| "http://mybatis.org/dtd/mybatis-3-config.dtd"> | |
| <configuration> | |
| <!-- settings: 控制mybatis全局行为 --> | |
| <settings> | |
| <!-- 设置mybatis输出日志 把操作数据库的信息打印到控制台上 | |
| "logImpl":控制日志 "STDOUT_LOGGING":把日志输出到控制台上 --> | |
| <setting name="logImpl" value="STDOUT_LOGGING"/> | |
| </settings> | |
| </configuration> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import com.xu.Aspectj.AopTest; | |
| import com.xu.dao.User; | |
| import com.xu.mapper.UserTest; | |
| import com.xu.service.UserService; | |
| import org.junit.Test; | |
| import org.springframework.beans.factory.annotation.Autowired; | |
| import org.springframework.context.support.ClassPathXmlApplicationContext; | |
| public class test { | |
| @Test | |
| public void transactionTest(){ | |
| ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("application.xml"); | |
| UserService userService = (UserService) ac.getBean("userServiceImpl"); | |
| userService.transactionTest(); | |
| } | |
| @Test | |
| public void MybatisTest(){ | |
| ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("application.xml"); | |
| UserTest userTest = (UserTest) ac.getBean("userTest"); | |
| User user = userTest.selectUser(); | |
| System.out.println(user); | |
| } | |
| @Test | |
| public void m1(){ | |
| ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("application.xml"); | |
| AopTest aopTestImpl = (AopTest) ac.getBean("aopTestImpl"); | |
| aopTestImpl.AopT("a"); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <beans xmlns="http://www.springframework.org/schema/beans" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" | |
| xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" | |
| xmlns:aop="http://www.springframework.org/schema/aop" | |
| xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd | |
| http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd | |
| http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd | |
| http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd | |
| http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> | |
| <!-- 注解扫描器 --> | |
| <context:component-scan base-package="com.xu"/> | |
| <!-- 自动代理生成器 --> | |
| <aop:aspectj-autoproxy/> | |
| <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> | |
| <property name="username" value="root"/> | |
| <property name="password" value="love500"/> | |
| <property name="url" value="jdbc:mysql://localhost:3306/dd?useSSL=false&useUnicode=true&characterEncoding=utf8"/> | |
| <property name="driverClassName" value="com.mysql.jdbc.Driver"/> | |
| </bean> | |
| <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> | |
| <property name="dataSource" ref="dataSource"/> | |
| </bean> | |
| <!--配置SqlSessionFactory--> | |
| <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> | |
| <property name="dataSource" ref="dataSource"/> | |
| <!-- mapper.xml文件所在的位置 --> | |
| <property name="mapperLocations" value="classpath:com/xu/mapper/*.xml"/> | |
| </bean> | |
| <!-- mapper扫描器: 扫描包下的mapper.xml文件 --> | |
| <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> | |
| <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> | |
| <property name="basePackage" value="com.xu.mapper"/> | |
| </bean> | |
| <bean id="userServiceImpl" class="com.xu.service.UserServiceImpl"> | |
| <property name="userDao" ref="userTest"/> | |
| </bean> | |
| <!-- 注解使用的 声明事务管理器 | |
| 使用Spring的事务处理 --> | |
| <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> | |
| <!-- 指定数据源 --> | |
| <property name="dataSource" ref="dataSource"/> | |
| </bean> | |
| <!-- 开启事务注解,并配置一个事务管理器 --> | |
| <tx:annotation-driven transaction-manager="transactionManager"/> | |
| </beans> | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8" ?> | |
| <!DOCTYPE mapper | |
| PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |
| "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |
| <mapper namespace="com.xu.mapper.UserTest"> | |
| <select id="selectUser" resultType="com.xu.dao.User"> | |
| select * from usera; | |
| </select> | |
| <update id="updateUser" parameterType="com.xu.dao.User"> | |
| update usera set age = #{upAge} where age = #{age} | |
| </update> | |
| <delete id="deleteUser" parameterType="com.xu.dao.User"> | |
| delete from usera where age = #{age} | |
| </delete> | |
| </mapper> | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8" ?> | |
| <!DOCTYPE configuration | |
| PUBLIC "-//mybatis.org//DTD Config 3.0//EN" | |
| "http://mybatis.org/dtd/mybatis-3-config.dtd"> | |
| <configuration> | |
| <!-- settings: 控制mybatis全局行为 --> | |
| <settings> | |
| <!-- 设置mybatis输出日志 把操作数据库的信息打印到控制台上 | |
| "logImpl":控制日志 "STDOUT_LOGGING":把日志输出到控制台上 --> | |
| <setting name="logImpl" value="STDOUT_LOGGING"/> | |
| </settings> | |
| </configuration> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| SpringMVC | |
| SpringMVC是基于Spring的一个框架 是专门做WEB开发的 是对Servlet的封装升级 | |
| SpringMVC也可以创建对象 放入到SpringMVC容器中(WebApplicationContext), SpringMVC容器是创建和管理控制器对象的 | |
| 使用"@Controller"注解创建的是一个普通的对象 不是Servlet, 这个对象被SpringMVC赋予了控制器对象的一些功能 | |
| Web开发的底层是Servlet, Spring中有一个对象是Servlet: DispatcherServlet(中央调度器) | |
| SpringMVC的组成: | |
| M 代表模型(Model) 模型就是数据, 就是dao、bean | |
| V 代表视图(View) 就是网页, JSP用来展示模型中的数据 | |
| C 代表两个控制器 前端控制器(DispatcherServlet)和后端控制器(Controller), 控制器的作用就是把不同的Model显示在不同的View上 | |
| spring mvc 有哪些组件? | |
| DispatcherServlet:中央控制器 | |
| 用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心, | |
| 由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。 | |
| 这玩意是核心,就是门卫传达室,一个请求进来先来传达室,然后一步步来处理问题。就是个servlet。 | |
| HandlerMapping:处理器映射器 | |
| HandlerMapping负责根据用户请求url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,如配置文件方式,实现接口方式,注解方式等。 | |
| 这玩意就是个map,放了一堆数据,key是url,value是你对应的处理器。 | |
| 一个请求来了,调用一下mao.get(url)就知道哪个类的哪个方法处理这个请求了。当然实际上会将这个url多对应的拦截器,处理器都拿到。 | |
| HandelAdapter:处理器适配器 | |
| 通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。 | |
| 这货会调用相应的方法,生成最终能够的modelAndView | |
| Handler:处理器 | |
| Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请 | |
| 求进行处理,由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。 | |
| 这玩意就是你写的controller,别把他想成啥高级玩意,你也能写个处理器。 | |
| ModelAndView 模型和视图 | |
| 视图和模型是两个东西,既然存在ModelAndView就存在Model和View。 | |
| ViewResolver:视图解析器 | |
| View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址, | |
| 再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 | |
| 这货就是解析modelAndView的。有个常用最简单的功能就是拼接字符串,给你加个前缀后缀,让你方便了很多,当然他们解析很多类型的视图。 | |
| 执行流程 | |
| spring mvc 先将用户请求发送给 DispatcherServlet。 | |
| DispatcherServlet 查询一个或多个 HandlerMapping, 'HandlerMapping'返回一个 HandlerExecutionChain 处理器执行链。 | |
| DispatcherServlet 访问HandlerAdapter 由HandlerAdapter去执行具体的处理器方法, Handler(Controller) 进行业务逻辑处理后返回Model View。 | |
| DispatcherServlet 查询一个或多个 ViewResolver 视图解析器, 找到 View 对象指定的视图对象返回。 | |
| View 视图对象负责渲染。 | |
| 渲染完毕后响应给用户 | |
| ===================================================================================================================================== | |
| 实现: | |
| Controller处理器类 | |
| 使用@Controller标注一个类 这个类会被"DispatcherServlet(中央调度器)"创建为处理器对象 保存在SpringMVC容器中 | |
| @ResponseBody: 把处理器方法返回对象转为适合的数据格式后 通过httpServletRequest响应输出给浏览器 | |
| 使用@RequestMapper标注一个方法 此方法就是处理前端请求的方法 | |
| 方法的返回值: | |
| void: 什么也不返回(做AJAX使用) | |
| String: 只返回视图(转发资源 使用return返回资源名称) | |
| 如果方法有"@ResponseBody" 则返回的时数据不是视图(注意ajax的接收数据格式不可以是json) | |
| ModelAndView: 使用MV.addObject返回Model(数据) , MV.setViewName返回View(视图) | |
| forward显示转发: 显示转发不和视图解析器一起工作 需要"视图文件"的完整路径 | |
| 如果视图文件不在视图解析器声明的文件下 可以使用显示转发来访问此视图文件 | |
| redirect重定向 | |
| 不和视图解析器一起工作 重定向是两次请求 两个Request作用域 所以两个页面的数据不共享 但是框架会把model中的 | |
| 简单类型的数据转为String 作为重定向get请求的参数使用(在重定向到"a.jsp"的时候 model中的数据会被作为"参数"传递过去) | |
| 因为作用域不是同一个 数据不共享 所以框架把Model中的数据作为了参数传递过去 | |
| 如果是作为数据发送过去 那么不是同一个作用域的"a.jsp"是不能访问到这个数据的 | |
| 对象: 可以转为json输出到浏览器 响应ajax的请求 | |
| List<对象>: 当有多个对象时使用 响应ajax的请求 | |
| 方法的形参列表: | |
| 可以使用HttpServlet类的方法 例如Request HttpSession HttpCookie等 | |
| 可以使用前端页面的请求参数(参数名称 参数类型必须一致 名称不一致使用"@RequestParam()"进行指定修改) | |
| 可以使用对象接收 对象内的属性必须和请求参数一致 SpringMVC会自动完成赋值(使用的是Set注入) | |
| web.xml配置文件 | |
| 创建DispatcherServlet中央调度器 | |
| <servlet> | |
| <servlet-name>springMvc</servlet-name> | |
| <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> | |
| <init-param> | |
| <param-name>contextConfigLocation</param-name> springmvc默认回去找/WEB-INF/spring-mvc-servlet.xml 这个文件 | |
| <param-value>classpath:springMvc.xml</param-value> 指定中央调度器默认读取"Spring配置文件"的文件路径 | |
| </init-param> | |
| <load-on-startup>1</load-on-startup> 表示这个对象创建的顺序 数字越小创建越早(大于等于零的数字) | |
| </servlet> | |
| <servlet-mapping> | |
| <servlet-name>springMvc</servlet-name> | |
| <url-pattern>*.do</url-pattern> 使用扩展名的方法 让"*.do"这个扩展名结尾的"页面请求URI"全部交给"中央调度器"分配 | |
| </servlet-mapping> | |
| Application配置文件 | |
| MVC注解扫描 | |
| <mvc:annotation-driven/> | |
| spring注解扫描 | |
| <context:component-scan base-package="com.xu"/> | |
| 让Spring MVC不处理静态资源 | |
| <mvc:default-servlet-handler/> | |
| 创建处理器映射器HandlerMapping | |
| <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> | |
| 创建处理器适配器HandlerAdapter | |
| <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> | |
| 创建试图解析器ViewResolver | |
| <bean id="InternalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> | |
| <property name="prefix" value="/WEB-INF/page/"/> | |
| <property name="suffix" value=".jsp"/> | |
| </bean> | |
| 页面的访问地址 | |
| 页面的访问地址没有"/"时 | |
| 访问的地址是: http://localhost:8080/SpringMVC/index.jsp | |
| 路径(参考地址): http://localhost:8080/SpringMVC(tomcat的名称)/ 资源: index.jsp | |
| 在index.jsp发起"user/some.do"请求后 访问地址会变为http://localhost:8080/SpringMVC/ + user/some.do | |
| 页面的访问地址有"/"时 | |
| 在index.jsp发起"/user/some.do"请求后 访问地址会变为http://localhost:8080 + /user/some.do | |
| 参考地址是http://localhost:8080 没有tomcat的服务器名称SpringMVC 所以会访问不到 需要手动在"/user/some.do" | |
| 前添加上"SpringMVC" 也可以使用el表达式"${pageContext.request.contextPath}"动态生成服务器名称 | |
| base标签 表示当前页面中访问地址的基地址 让页面中所有不是以"/"开头的请求地址 都以base标签内的内容作为参考地址 | |
| <base href="http://localhost:8080/XXX(Tomcat项目名)/"> | |
| 无base标签 有/: http://localhost:8080/text/some.do (如果服务器地址只是"/" 那么不加也可以) | |
| MVC的注解 | |
| @Controller: 表示当前类是一个Handler 用来处理请用请求 | |
| @ResponseBody: 能将处理的结果放在响应体中 直接返回, 不走视图解析器 | |
| @RequestMapping("/url"): 放在类上表示当前所有类中所有方法都加上此前缀, 加在方法上表示当前方法的请求路径 | |
| value: 指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明) | |
| method: 指定请求的method类型, GET、POST、PUT、DELETE等 | |
| consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html | |
| produces: 指定返回的内容类型, 仅当request请求头中的(Accept)类型中包含该指定类型才返回, 可以处理乱码 | |
| params: 指定request中必须包含某些参数, 才让该方法处理 | |
| headers: 指定request中必须包含某些指定的header值, 才能让该方法处理请求 | |
| 内置统一的字符集处理 | |
| <filter> | |
| <filter-name>CharacterEncodingFilter</filter-name> | |
| <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> | |
| <init-param> | |
| <param-name>encoding</param-name> | |
| <param-value>utf-8</param-value> | |
| </init-param> | |
| </filter> | |
| <filter-mapping> | |
| <filter-name>CharacterEncodingFilter</filter-name> | |
| <url-pattern>/*</url-pattern> | |
| </filter-mapping> | |
| 返回Json数据 | |
| pom: com.alibaba fastjson | |
| String str = JSONArray.toJSONString(数据) | |
| 返回json字符串数据, 方法上必须有@ResponseBody注解 否则会把这个数据当成view数据去找视图页面 | |
| 数据转换 | |
| @DateTimeFormat(pattern = "yyyy-MM-dd") | |
| private String name; | |
| JSR 303 | |
| JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 6.0 中 JSR 303 通过在 Bean 属性 | |
| 上标注类似于 @NotNull、@Max 等标准的注解指定校验规则,并通过标准的验证接口对 Bean 进行验证 | |
| pom: org.hibernate hibernate-validator 6.0.9.Final | |
| 在属性上添加注解 | |
| @Null 被注释的元素必须为 null | |
| @NotNull 被注释的元素必须不为 null | |
| @AssertTrue 被注释的元素必须为 true | |
| @AssertFalse 被注释的元素必须为 false | |
| @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 | |
| @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 | |
| @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 | |
| @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 | |
| @Size(max, min) 被注释的元素的大小必须在指定的范围内 | |
| @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内 | |
| @Past 被注释的元素必须是一个过去的日期 | |
| @Future 被注释的元素必须是一个将来的日期 | |
| @Pattern(value) 被注释的元素必须符合指定的正则表达式 | |
| Hibernate Validator 是 JSR 303 的一个参考实现,除支持所有标准的校验注解外,它还支持以下的扩展注解 | |
| @Email 被注释的元素必须是电子邮箱地址 | |
| @Length 被注释的字符串的大小必须在指定的范围内 | |
| @NotEmpty 被注释的字符串的必须非空 | |
| @Range 被注释的元素必须在合适的范围内 | |
| application.xml | |
| <mvc:annotation-driven validator="validator"/> | |
| <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> | |
| <property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property> | |
| </bean> | |
| controller | |
| 使用 @Validated 开启数据验证 | |
| 使用 BindingResult 参数获取错误对象们 如果此对象为null就说明没有错误 | |
| public ModelAndView Json(@Validated @Param("User") User user, BindingResult br){ | |
| List<ObjectError> allErrors = br.getAllErrors(); 获取所有错误 | |
| } | |
| 转发和重定向 | |
| mv.setViewName("redirect:/test") | |
| 可以指定返回的视图是转发还是重定向 | |
| forward 显示转发, 显示转发不和视图解析器一起工作 需要视图文件的完整路径 | |
| redirect 重定向, 重定向不和视图解析器一起工作, 重定向是两次请求 两个request作用域 所以两个页面的数据不共享, | |
| 但是框架会把model中的简单类型数据转换为String 作为重定向的get请求的参数使用 | |
| ===================================================================================================================================== | |
| ExceptionHandler:异常处理 | |
| 异常处理步骤: | |
| 1.创建一个继承了Exception的普通类 作用全局异常处理类 | |
| 2.新建一个自定义异常类 再定义它的子类 @Controller中抛出异常到其子类后 会由@ControllerAdvice类来处理 @ControllerAdvice类中 | |
| 需要创建一个 "@ExceptionHandler"来处理"@Controller"类中抛出的异常的方法 并返回到页面告诉用户错误信息 | |
| 3.创建springMvc的配置文件,声明注解驱动 创建组件扫描器扫描@ControllerAdvice所在的包名 | |
| @ControllerAdvice(控制器增强): 定义在类上 用来接收@Controller类抛出的"自定义异常"的(需要使用组件扫描器扫描此类) | |
| @ExceptionHandler(异常的class字节码文件): 定义在方法上 用来处理@Controller类的异常的 | |
| public ModelAndView XXX(Exception exception){}: 处理异常的方法 方法的形参是@Controller中抛出的异常类型 | |
| 返回值是"ModelAndView"用来告诉用户错误信息并跳转到提示页面 | |
| 全局异常捕获 | |
| Spring MVC提供了一个HandlerExceptionResolver 接口,可用于统一异常处理。 | |
| @Component | |
| public class testException implements HandlerExceptionResolver { | |
| @Override | |
| public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { | |
| } | |
| } | |
| =================================================================================================================== | |
| 拦截器: | |
| 1.SpringMVC提供的拦截器类似于JavaWeb中的过滤器,只不过SpringMVC拦截器只拦截被前端控制器拦截的请求,而过滤器拦截从前端发送的任意请求。 | |
| 2.拦截器是SpringMVC中的一种 需要实现HandlerInterceptor接口 | |
| 3.拦截器和过滤器类似, 拦截器是用来拦截用户的请求 对请求做判断处理, 过滤器是用来过滤请求参数 设置编码字符集等 | |
| 4.拦截器是全局的 可以对多个Controller做拦截 可以有一个或多个拦截器 | |
| 自定义拦截器 | |
| 1.定义一个类 实现' HandlerInterceptor '接口 重写三个方法 | |
| preHandle(预处理方法): 此方法在@Controller控制器方法之前先执行, 此方法中可以获取请求信息 对其进行验证 | |
| 此方法返回一个boolean值 为true时表示资源可以通过, 为false表示资源不通过 不会执行后续逻辑代码 | |
| postHandle(后处理方法): 在"处理器方法之后"执行, 此方法能够获取处理器方法的"ModelAndView" 对其进行修改可以影响最后的执行结果 | |
| afterHandle(最后处理方法): 在"请求处理完成后"执行, 框架中规定当视图处理完成后(对视图执行了forward)后请求处理完成 | |
| 2.在springMVC配置文件中声明拦截器 | |
| <mvc:interceptors> | |
| <mvc:interceptor> | |
| <mvc:mapping path="/student/**"/> 要拦截的路径 | |
| <mvc:exclude-mapping path="/toLogin"/> 不拦截的路径 | |
| <bean id="" class="拦截器位置"/> | |
| </mvc:interceptor> | |
| </mvc:interceptors> | |
| 多个拦截器 | |
| 当有多个拦截器时 先执行preHandle方法的拦截器 后执行postHandle afterHandle方法 比如拦截器1和2(都返回true) | |
| 执行结果为: 1-preHandle 2-preHandle,2-postHandle 1-postHandle,2-afterHandle 1-afterHandle | |
| 当拦截器1返回true 2返回false 执行结果为: 1-preHandle 2-preHandle,1-afterHandle 因为拦截器1为true 一定会 | |
| 执行1-afterHandle方法, 但是拦截器2为false 所以不会执行逻辑代码 | |
| 当拦截1返回false 执行结果为: 1-preHandle, 因为拦截器1没有通过 所以不会执行拦截器2 | |
| 拦截器和过滤器的区别 | |
| 过滤器是在拦截器之前执行的 | |
| 拦截器是springMVC容器中创建的对象 实现HandlerInterceptor, 过滤器是tomcat服务器创建的对象 实现Filter接口 | |
| 拦截器是用来验证请求的 能截断请求, 过滤器是用来设置request response的参数 属性的 侧重对数据过滤的 | |
| 拦截器有三个执行时间点, 过滤器是一个执行时间点 | |
| 拦截器是侧重拦截Controller对象 如果你的请求不能被DispatcherServlet接收 这个请求不会执行拦截器的内容, | |
| 过滤器可以处理jsp js html等等 | |
| 拦截器拦截普通类方法执行, 过滤器过滤servlet请求响应 | |
| =================================================================================================================== | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
| <modelVersion>4.0.0</modelVersion> | |
| <groupId>com.xu</groupId> | |
| <artifactId>springMVC</artifactId> | |
| <version>1.0.0</version> | |
| <packaging>war</packaging> | |
| <name>springMVC Maven Webapp</name> | |
| <properties> | |
| <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |
| <maven.compiler.source>1.8</maven.compiler.source> | |
| <maven.compiler.target>1.8</maven.compiler.target> | |
| </properties> | |
| <dependencies> | |
| <!-- SpringMVC依赖 --> | |
| <dependency> | |
| <groupId>org.springframework</groupId> | |
| <artifactId>spring-webmvc</artifactId> | |
| <version>5.2.7.RELEASE</version> | |
| </dependency> | |
| <!--spring依赖--> | |
| <dependency> | |
| <groupId>org.springframework</groupId> | |
| <artifactId>spring-tx</artifactId> | |
| <version>5.2.7.RELEASE</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>org.springframework</groupId> | |
| <artifactId>spring-jdbc</artifactId> | |
| <version>5.2.7.RELEASE</version> | |
| </dependency> | |
| <!-- mybatis --> | |
| <dependency> | |
| <groupId>org.mybatis</groupId> | |
| <artifactId>mybatis-spring</artifactId> | |
| <version>2.0.5</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>org.mybatis</groupId> | |
| <artifactId>mybatis</artifactId> | |
| <version>3.5.5</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>mysql</groupId> | |
| <artifactId>mysql-connector-java</artifactId> | |
| <version>5.1.49</version> | |
| </dependency> | |
| <!-- druid --> | |
| <dependency> | |
| <groupId>com.alibaba</groupId> | |
| <artifactId>druid</artifactId> | |
| <version>1.1.22</version> | |
| </dependency> | |
| <!-- jsp依赖 --> | |
| <dependency> | |
| <groupId>javax.servlet.jsp</groupId> | |
| <artifactId>jsp-api</artifactId> | |
| <version>2.2</version> | |
| </dependency> | |
| <!-- Servlet依赖 --> | |
| <dependency> | |
| <groupId>javax.servlet</groupId> | |
| <artifactId>javax.servlet-api</artifactId> | |
| <version>4.0.1</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>javax.servlet.jsp</groupId> | |
| <artifactId>jsp-api</artifactId> | |
| <version>2.2</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>com.fasterxml.jackson.core</groupId> | |
| <artifactId>jackson-databind</artifactId> | |
| <version>2.9.10.4</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>com.alibaba</groupId> | |
| <artifactId>fastjson</artifactId> | |
| <version>1.2.68</version> | |
| </dependency> | |
| <!-- JSR303依赖 --> | |
| <dependency> | |
| <groupId>org.hibernate</groupId> | |
| <artifactId>hibernate-validator</artifactId> | |
| <version>6.0.9.Final</version> | |
| </dependency> | |
| </dependencies> | |
| <build> | |
| <resources> | |
| <resource> | |
| <directory>src/main/java</directory> | |
| <includes> | |
| <include>**/*.properties</include> | |
| <include>**/*.xml</include> | |
| </includes> | |
| <filtering>false</filtering> | |
| </resource> | |
| </resources> | |
| </build> | |
| </project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.xu.controller; | |
| import com.alibaba.fastjson.JSONArray; | |
| import com.xu.dao.User; | |
| import org.apache.ibatis.annotations.Param; | |
| import org.springframework.stereotype.Controller; | |
| import org.springframework.validation.BindingResult; | |
| import org.springframework.validation.ObjectError; | |
| import org.springframework.validation.annotation.Validated; | |
| import org.springframework.web.bind.annotation.RequestMapping; | |
| import org.springframework.web.bind.annotation.RequestMethod; | |
| import org.springframework.web.bind.annotation.ResponseBody; | |
| import org.springframework.web.servlet.ModelAndView; | |
| import java.util.HashMap; | |
| import java.util.List; | |
| @Controller | |
| public class MvcController { | |
| @RequestMapping(value = "/test",method = RequestMethod.GET, params = "hello") | |
| public ModelAndView test1(String hello){ | |
| ModelAndView mv = new ModelAndView(); | |
| mv.addObject("hello","hello MVC"); | |
| mv.setViewName("test"); | |
| return mv; | |
| } | |
| @RequestMapping(value = "/json") | |
| @ResponseBody | |
| public ModelAndView Json(@Validated @Param("User") User user, BindingResult br){ | |
| List<ObjectError> allErrors = br.getAllErrors(); // 获取所有错误 | |
| for (ObjectError allError : allErrors) { | |
| System.out.println(allError.getObjectName()); | |
| System.out.println(allError.getCode()); | |
| if (allErrors.size() > 0){ | |
| return null; | |
| } | |
| } | |
| ModelAndView mv = new ModelAndView(); | |
| mv.addObject("usera","小怜"); | |
| mv.setViewName("test"); | |
| return mv; | |
| // return JSONArray.toJSONString(); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.xu.controller; | |
| import org.springframework.stereotype.Component; | |
| import org.springframework.web.servlet.HandlerExceptionResolver; | |
| import org.springframework.web.servlet.ModelAndView; | |
| import javax.servlet.http.HttpServletRequest; | |
| import javax.servlet.http.HttpServletResponse; | |
| @Component | |
| public class testException implements HandlerExceptionResolver { | |
| @Override | |
| public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { | |
| System.out.println("异常l "); | |
| return null; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.xu.dao; | |
| import javax.validation.constraints.NotNull; | |
| public class User { | |
| @NotNull | |
| private String name; | |
| public User() { | |
| } | |
| public User(String name) { | |
| this.name = name; | |
| } | |
| public String getName() { | |
| return name; | |
| } | |
| public void setName(String name) { | |
| this.name = name; | |
| } | |
| @Override | |
| public String toString() { | |
| return "User{" + | |
| "name='" + name + '\'' + | |
| '}'; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <beans xmlns="http://www.springframework.org/schema/beans" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xmlns:context="http://www.springframework.org/schema/context" | |
| xmlns:mvc="http://www.springframework.org/schema/mvc" | |
| xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd | |
| http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> | |
| <context:component-scan base-package="com.xu"/> | |
| <!-- 让Spring MVC不处理静态资源 --> | |
| <mvc:default-servlet-handler/> | |
| <!-- 让springmvc自带的注解生效 --> | |
| <mvc:annotation-driven validator="validator"/> | |
| <!-- 处理映射器 --> | |
| <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> | |
| <!-- 处理器适配器 --> | |
| <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> | |
| <!--视图解析器:DispatcherServlet给他的ModelAndView--> | |
| <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> | |
| <property name="prefix" value="/WEB-INF/page/"/> | |
| <property name="suffix" value=".jsp"/> | |
| </bean> | |
| <!-- 效验 --> | |
| <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> | |
| <property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property> | |
| </bean> | |
| </beans> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <beans xmlns="http://www.springframework.org/schema/beans" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xmlns:aop="http://www.springframework.org/schema/aop" | |
| xmlns:context="http://www.springframework.org/schema/context" | |
| xmlns:tx="http://www.springframework.org/schema/tx" | |
| xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd | |
| http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd | |
| http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd | |
| http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> | |
| <!-- 加载外部的数据库信息 classpath:不叫会报错具体原因下边解释--> | |
| <context:property-placeholder location="classpath:db.properties"/> | |
| <!-- 加入springmvc的配置 --> | |
| <import resource="classpath:springmvc-servlet.xml"/> | |
| <context:component-scan base-package="com.xinzhi"/> | |
| <!-- Mapper 扫描器 --> | |
| <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> | |
| <!-- 扫描 cn.wmyskxz.mapper 包下的组件 --> | |
| <property name="basePackage" value="com.xinzhi.dao"/> | |
| </bean> | |
| <!--配置数据源:数据源有非常多,可以使用第三方的,也可使使用Spring的--> | |
| <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> | |
| <property name="driverClassName" value="${jdbc.driver}"/> | |
| <property name="url" value="${jdbc.url}"/> | |
| <property name="username" value="${jdbc.username}"/> | |
| <property name="password" value="${jdbc.password}"/> | |
| <property name="filters" value="${filters}"/> | |
| <!-- 最大并发连接数 --> | |
| <property name="maxActive" value="${maxActive}"/> | |
| <!-- 初始化连接数量 --> | |
| <property name="initialSize" value="${initialSize}"/> | |
| <!-- 配置获取连接等待超时的时间 --> | |
| <property name="maxWait" value="${maxWait}"/> | |
| <!-- 最小空闲连接数 --> | |
| <property name="minIdle" value="${minIdle}"/> | |
| <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> | |
| <property name="timeBetweenEvictionRunsMillis" value | |
| ="${timeBetweenEvictionRunsMillis}"/> | |
| <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> | |
| <property name="minEvictableIdleTimeMillis" value | |
| ="${minEvictableIdleTimeMillis}"/> | |
| <!-- <property name = "validationQuery" value = "${validationQuery}" /> | |
| --> | |
| <property name="testWhileIdle" value="${testWhileIdle}"/> | |
| <property name="testOnBorrow" value="${testOnBorrow}"/> | |
| <property name="testOnReturn" value="${testOnReturn}"/> | |
| <property name="maxOpenPreparedStatements" value | |
| ="${maxOpenPreparedStatements}"/> | |
| <!-- 打开 removeAbandoned 功能 --> | |
| <property name="removeAbandoned" value="${removeAbandoned}"/> | |
| <!-- 1800 秒,也就是 30 分钟 --> | |
| <property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}"/> | |
| <!-- 关闭 abanded 连接时输出错误日志 --> | |
| <property name="logAbandoned" value="${logAbandoned}"/> | |
| </bean> | |
| <!--配置SqlSessionFactory--> | |
| <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> | |
| <property name="dataSource" ref="dataSource"/> | |
| <!--关联Mybatis--> | |
| <property name="configLocation" value="classpath:mybatis-config.xml"/> | |
| <property name="mapperLocations" value="classpath:mappers/*.xml"/> | |
| </bean> | |
| <!--注册sqlSessionTemplate , 关联sqlSessionFactory--> | |
| <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> | |
| <!--利用构造器注入--> | |
| <constructor-arg index="0" ref="sqlSessionFactory"/> | |
| </bean> | |
| <bean id="transactionManager" | |
| class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> | |
| <property name="dataSource" ref="dataSource"/> | |
| </bean> | |
| <!--配置事务通知--> | |
| <tx:advice id="txAdvice" transaction-manager="transactionManager"> | |
| <tx:attributes> | |
| <!--配置哪些方法使用什么样的事务,配置事务的传播特性--> | |
| <tx:method name="add*" propagation="REQUIRED"/> | |
| <tx:method name="delete*" propagation="REQUIRED"/> | |
| <tx:method name="update*" propagation="REQUIRED"/> | |
| <tx:method name="search*" propagation="REQUIRED"/> | |
| <tx:method name="get*" read-only="true"/> | |
| <tx:method name="find*" read-only="true"/> | |
| <tx:method name="*" propagation="REQUIRED"/> | |
| </tx:attributes> | |
| </tx:advice> | |
| <!--配置aop织入事务--> | |
| <aop:config> | |
| <aop:pointcut id="txPointcut" expression="execution(* com.xinzhi.service.impl.*.*(..))"/> | |
| <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> | |
| </aop:config> | |
| </beans> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| jdbc.driver=com.mysql.jdbc.Driver | |
| jdbc.url=jdbc:mysql://localhost:3306/ssm?useSSL=true&useUnicode=true&characterEncoding=utf8 | |
| jdbc.username=root | |
| jdbc.password=root | |
| filters=wall,stat | |
| maxActive=20 | |
| initialSize=3 | |
| maxWait=5000 | |
| minIdle=3 | |
| maxIdle=15 | |
| timeBetweenEvictionRunsMillis=60000 | |
| minEvictableIdleTimeMillis=300000 | |
| validationQuery=SELECT 'x' | |
| testWhileIdle=true | |
| testOnBorrow=false | |
| testOnReturn=false | |
| maxOpenPreparedStatements=20 | |
| removeAbandoned=true | |
| removeAbandonedTimeout=1800 | |
| logAbandoned=true | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <configuration scan="true" scanPeriod="60 seconds" debug="false"> | |
| <!-- 定义参数常量 --> | |
| <!-- 日志级别 TRACE<DEBUG<INFO<WARN<ERROR --> | |
| <!-- logger.trace("msg") logger.debug... --> | |
| <property name="log.level" value="debug" /> | |
| <property name="log.maxHistory" value="30" /> | |
| <property name="log.filePath" value="D:/log" /> | |
| <property name="log.pattern" | |
| value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n" /> | |
| <!-- 控制台输出设置 --> | |
| <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"> | |
| <encoder> | |
| <pattern>${log.pattern}</pattern> | |
| </encoder> | |
| </appender> | |
| <!-- DEBUG级别文件记录 --> | |
| <appender name="debugAppender" | |
| class="ch.qos.logback.core.rolling.RollingFileAppender"> | |
| <!-- 文件路径 --> | |
| <file>${log.filePath}/debug.log</file> | |
| <!-- 滚动日志文件类型,就是每天都会有一个日志文件 --> | |
| <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | |
| <!-- 文件名称 --> | |
| <fileNamePattern>${log.filePath}/debug/debug.%d{yyyy-MM-dd}.log.gz | |
| </fileNamePattern> | |
| <!-- 文件最大保存历史数量 --> | |
| <maxHistory>${log.maxHistory}</maxHistory> | |
| </rollingPolicy> | |
| <encoder> | |
| <pattern>${log.pattern}</pattern> | |
| </encoder> | |
| <filter class="ch.qos.logback.classic.filter.LevelFilter"> | |
| <level>DEBUG</level> | |
| <onMatch>ACCEPT</onMatch> | |
| <onMismatch>DENY</onMismatch> | |
| </filter> | |
| </appender> | |
| <!-- INFO --> | |
| <appender name="infoAppender" | |
| class="ch.qos.logback.core.rolling.RollingFileAppender"> | |
| <!-- 文件路径 --> | |
| <file>${log.filePath}/info.log</file> | |
| <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | |
| <!-- 文件名称 --> | |
| <fileNamePattern>${log.filePath}/info/info.%d{yyyy-MM-dd}.log.gz | |
| </fileNamePattern> | |
| <!-- 文件最大保存历史数量 --> | |
| <maxHistory>${log.maxHistory}</maxHistory> | |
| </rollingPolicy> | |
| <encoder> | |
| <pattern>${log.pattern}</pattern> | |
| </encoder> | |
| <filter class="ch.qos.logback.classic.filter.LevelFilter"> | |
| <level>INFO</level> | |
| <onMatch>ACCEPT</onMatch> | |
| <onMismatch>DENY</onMismatch> | |
| </filter> | |
| </appender> | |
| <!-- com.xinzhi开头的日志对应形式 --> | |
| <logger name="com.xinzhi" level="${log.level}" additivity="true"> | |
| <appender-ref ref="debugAppender"/> | |
| <appender-ref ref="infoAppender"/> | |
| </logger> | |
| <!-- <root> 是必选节点,用来指定最基础的日志输出级别,只有一个level属性 --> | |
| <root level="info"> | |
| <appender-ref ref="consoleAppender"/> | |
| </root> | |
| <!-- 捕捉sql开头的日志 --> | |
| <appender name="MyBatis" class="ch.qos.logback.core.rolling.RollingFileAppender"> | |
| <file>${log.filePath}/sql_log/mybatis-sql.log</file> | |
| <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | |
| <FileNamePattern>${log.filePath}/sql_log/mybatis-sql.log.%d{yyyy-MM-dd} | |
| </FileNamePattern> | |
| <maxHistory>30</maxHistory> | |
| </rollingPolicy> | |
| <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> | |
| <pattern>%thread|%d{yyyy-MM-dd HH:mm:ss.SSS}|%level|%logger{36}|%m%n</pattern> | |
| </encoder> | |
| </appender> | |
| <logger name="sql" level="DEBUG"> | |
| <appender-ref ref="MyBatis"/> | |
| </logger> | |
| </configuration> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8" ?> | |
| <!DOCTYPE configuration | |
| PUBLIC "-//mybatis.org//DTD Config 3.0//EN" | |
| "http://mybatis.org/dtd/mybatis-3-config.dtd"> | |
| <configuration> | |
| <settings> | |
| <setting name="lazyLoadingEnabled" value="true"/> | |
| <setting name="aggressiveLazyLoading" value="false"/> | |
| <!-- 下划线转驼峰式 --> | |
| <setting name="cacheEnabled" value="true"/> | |
| <setting name="mapUnderscoreToCamelCase" value="true"/> | |
| <setting name="logPrefix" value="sql."/> | |
| </settings> | |
| </configuration> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <beans xmlns="http://www.springframework.org/schema/beans" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xmlns:mvc="http://www.springframework.org/schema/mvc" | |
| xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd | |
| http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> | |
| <!-- 让Spring MVC不处理静态资源 --> | |
| <mvc:default-servlet-handler/> | |
| <!-- 让springmvc自带的注解生效 --> | |
| <mvc:annotation-driven> | |
| <mvc:message-converters> | |
| <bean id="fastjson" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"> | |
| <property name="supportedMediaTypes"> | |
| <list> | |
| <value>text/html;charset=UTF-8</value> | |
| <value>application/json;charset=UTF-8</value> | |
| </list> | |
| </property> | |
| </bean> | |
| </mvc:message-converters> | |
| </mvc:annotation-driven> | |
| <!--文件上传配置--> | |
| <bean id="multipartResolver" | |
| class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> | |
| <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO- | |
| 8859-1 --> | |
| <property name="defaultEncoding" value="utf-8"/> | |
| <!-- 上传文件大小上限,单位为字节(10485760=10M) --> | |
| <property name="maxUploadSize" value="10485760"/> | |
| <property name="maxInMemorySize" value="40960"/> | |
| </bean> | |
| <!-- 处理映射器 --> | |
| <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> | |
| <!-- 处理器适配器 --> | |
| <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> | |
| <!--视图解析器:DispatcherServlet给他的ModelAndView--> | |
| <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" | |
| id="InternalResourceViewResolver"> | |
| <!--前缀--> | |
| <property name="prefix" value="/WEB-INF/page/"/> | |
| <!--后缀--> | |
| <property name="suffix" value=".jsp"/> | |
| </bean> | |
| </beans> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <html> | |
| <body> | |
| <h2>Hello World!</h2> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <%@ page contentType="text/html;charset=UTF-8" language="java" %> | |
| <html> | |
| <head> | |
| <title>Title</title> | |
| </head> | |
| <body> | |
| ${hello} | |
| ${usera.usera} | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" | |
| version="4.0"> | |
| <display-name>Archetype Created Web Application</display-name> | |
| <servlet> | |
| <servlet-name>springMvc</servlet-name> | |
| <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> | |
| <init-param> | |
| <param-name>contextConfigLocation</param-name> | |
| <param-value>classpath:application.xml</param-value> | |
| </init-param> | |
| <load-on-startup>1</load-on-startup> | |
| </servlet> | |
| <servlet-mapping> | |
| <servlet-name>springMvc</servlet-name> | |
| <url-pattern>/</url-pattern> | |
| </servlet-mapping> | |
| <filter> | |
| <filter-name>CharacterEncodingFilter</filter-name> | |
| <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> | |
| <init-param> | |
| <param-name>encoding</param-name> | |
| <param-value>utf-8</param-value> | |
| </init-param> | |
| </filter> | |
| <filter-mapping> | |
| <filter-name>CharacterEncodingFilter</filter-name> | |
| <url-pattern>/*</url-pattern> | |
| </filter-mapping> | |
| </web-app> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <beans xmlns="http://www.springframework.org/schema/beans" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xmlns:context="http://www.springframework.org/schema/context" | |
| xmlns:mvc="http://www.springframework.org/schema/mvc" | |
| xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd | |
| http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> | |
| <context:component-scan base-package="com.xu"/> | |
| <!-- 让Spring MVC不处理静态资源 --> | |
| <mvc:default-servlet-handler/> | |
| <!-- 让springmvc自带的注解生效 --> | |
| <mvc:annotation-driven validator="validator"/> | |
| <!-- 处理映射器 --> | |
| <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> | |
| <!-- 处理器适配器 --> | |
| <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> | |
| <!--视图解析器:DispatcherServlet给他的ModelAndView--> | |
| <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> | |
| <property name="prefix" value="/WEB-INF/page/"/> | |
| <property name="suffix" value=".jsp"/> | |
| </bean> | |
| <!-- 效验 --> | |
| <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> | |
| <property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property> | |
| </bean> | |
| </beans> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <html> | |
| <body> | |
| <h2>Hello World!</h2> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Manifest-Version: 1.0 | |
| Created-By: IntelliJ IDEA | |
| Built-By: xu172 | |
| Build-Jdk: version 1.8.0_221 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <beans xmlns="http://www.springframework.org/schema/beans" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xmlns:context="http://www.springframework.org/schema/context" | |
| xmlns:mvc="http://www.springframework.org/schema/mvc" | |
| xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd | |
| http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> | |
| <context:component-scan base-package="com.xu"/> | |
| <!-- 让Spring MVC不处理静态资源 --> | |
| <mvc:default-servlet-handler/> | |
| <!-- 让springmvc自带的注解生效 --> | |
| <mvc:annotation-driven validator="validator"/> | |
| <!-- 处理映射器 --> | |
| <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> | |
| <!-- 处理器适配器 --> | |
| <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> | |
| <!--视图解析器:DispatcherServlet给他的ModelAndView--> | |
| <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> | |
| <property name="prefix" value="/WEB-INF/page/"/> | |
| <property name="suffix" value=".jsp"/> | |
| </bean> | |
| <!-- 效验 --> | |
| <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> | |
| <property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property> | |
| </bean> | |
| </beans> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <%@ page contentType="text/html;charset=UTF-8" language="java" %> | |
| <html> | |
| <head> | |
| <title>Title</title> | |
| </head> | |
| <body> | |
| ${hello} | |
| ${usera.usera} | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" | |
| version="4.0"> | |
| <display-name>Archetype Created Web Application</display-name> | |
| <servlet> | |
| <servlet-name>springMvc</servlet-name> | |
| <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> | |
| <init-param> | |
| <param-name>contextConfigLocation</param-name> | |
| <param-value>classpath:application.xml</param-value> | |
| </init-param> | |
| <load-on-startup>1</load-on-startup> | |
| </servlet> | |
| <servlet-mapping> | |
| <servlet-name>springMvc</servlet-name> | |
| <url-pattern>/</url-pattern> | |
| </servlet-mapping> | |
| <filter> | |
| <filter-name>CharacterEncodingFilter</filter-name> | |
| <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> | |
| <init-param> | |
| <param-name>encoding</param-name> | |
| <param-value>utf-8</param-value> | |
| </init-param> | |
| </filter> | |
| <filter-mapping> | |
| <filter-name>CharacterEncodingFilter</filter-name> | |
| <url-pattern>/*</url-pattern> | |
| </filter-mapping> | |
| </web-app> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 递归的经验总结: | |
| 使用Entity、Bean、对象等封装数据会发生数据覆盖的情况, 不要在递归B中修改递归A的数据 会发生数据覆盖的情况。 | |
| 多个对象的引用地址一样就会发生覆盖的问题 即文件B的对象覆盖掉了文件A的对象。 | |
| 所以可以把对象转换成json串保存在起来 json串时String没有内存地址所以不存在对象覆盖的问题 | |
| 出现的异常 | |
| Invalid bound statement (not found) 找不到绑定语句 | |
| mapper配置文件没有编译到target文件中 | |
| GET请求URI中有特殊字符和中文则需要进行编码 | |
| 前端传输数据时 会出现请求URI出现乱码的情况 导致后端接收到的数据也是乱码, 因为网络标准RFC 1738做了硬性规定: | |
| 只有字母和数字[0-9a-zA-Z]、一些特殊符号“$-_.+!*'(),”[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL | |
| encodeURI和decodeURI: 返回编码为有效的统一资源标识符(URI)的字符串,不会被编码的字符:! @ # $ & * ( ) = : / ; ? + ' | |
| springboot中 读取application配置文件内的中文出现乱码, 在application文件中配置 | |
| banner.charset=UTF-8 | |
| server.tomcat.uri-encoding=UTF-8 | |
| spring.http.encoding.charset=UTF-8 | |
| spring.http.encoding.enabled=true | |
| spring.http.encoding.force=true | |
| spring.messages.encoding=UTF-8 | |
| 设置中的 Editor --> File Encodings修改编码格式 | |
| 非法字符: '\ufeff' | |
| idea右下角编码 先转换为GBK再转为UTF8 | |
| 后台如果要接收JSON类型的字符串 则必须在形参上添加@RequestBody注解 | |
| web端WebSocket对象的ip地址如果是localhost 访问页面时就填localhost, 如果是IP地址 就填IP地址 | |
| WebSocket配置类中sec.getUserProperties()添加session对象时出现null, | |
| 可能是因为页面在创建WebSocket对象的时候 session对象还没有创建完成 然后sec.getUserProperties()方法就添加了session 导致添加了空对象 | |
| 解决: 在web页面创建WebSocket对象之前 手动创建一个Session对象 | |
| thymeleaf模板出现" Error resolving templ ate [XXX], template might not exist "模板可能不存在 | |
| controller访问模板的请求是"/file" 而thymeleaf在构建URL时默认是"classpath:/templates/", 就导致了Controller请求URL变成了"//file" | |
| 修改Application.properties配置文件: spring.thymeleaf.prefix=classpath:/templates; spring.thymeleaf.suffix=.html | |
| springboot无法直接读取jar包中的文件 只能使用流来进行读取 | |
| 但是只可以读取文件 不可以读取文件夹, 所以要把文件的名称保存成一个文件 然后读取这个文件 | |
| ClassPathResource resource = new ClassPathResource("static/directory.txt"); classes下的文件 | |
| byte[] keywordsData = FileCopyUtils.copyToByteArray(resource.getInputStream()); 使用流读取到文件并复制给一个byte数组 | |
| String s = new String(keywordsData, Charset.forName("utf-8")); 把数组转换为字符串 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| JVM | |
| 说一下 JVM 的主要组成部分?及其作用? | |
| 组件的作用: 首先通过类加载器(ClassLoader)会把 Java 代码转换成字节码,运行时数据区(Runtime Data Area)再把字节码加载到内存中, | |
| 而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine), | |
| 将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。 | |
| 类加载器(ClassLoader) | |
| 运行时数据区(Runtime Data Area) | |
| 执行引擎(Execution Engine) | |
| 本地库接口(Native Interface) | |
| 说一下 JVM 运行时数据区? | |
| 不同虚拟机的运行时数据区可能略微有所不同,但都会遵从 Java 虚拟机规范, Java 虚拟机规范规定的区域分为以下 5 个部分: | |
| 程序计数器(Program Counter Register):当前线程所执行的字节码的行号指示器,字节码解析器的工作是通过改变这个计数器的值, | |
| 来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能,都需要依赖这个计数器来完成; | |
| Java 虚拟机栈(Java Virtual Machine Stacks):用于存储局部变量表、操作数栈、动态链接、方法出口等信息; | |
| 本地方法栈(Native Method Stack):与虚拟机栈的作用是一样的,只不过虚拟机栈是服务 Java 方法的,而本地方法栈是为虚拟机调用 Native 方法服务的; | |
| Java 堆(Java Heap):Java 虚拟机中内存最大的一块,是被所有线程共享的,几乎所有的对象实例都在这里分配内存; | |
| 方法区(Methed Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。 | |
| 说一下堆栈的区别? | |
| 功能方面:堆是用来存放对象的,栈是用来执行程序的。 | |
| 共享性:堆是线程共享的,栈是线程私有的。 | |
| 空间大小:堆大小远远大于栈。 | |
| 队列和栈是什么?有什么区别? | |
| 队列和栈都是被用来预存储数据的。 | |
| 队列允许先进先出检索元素,但也有例外的情况,Deque 接口允许从两端检索元素。 | |
| 栈和队列很相似,但它运行对元素进行后进先出进行检索。 | |
| 什么是双亲委派模型? | |
| 在介绍双亲委派模型之前先说下类加载器。对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立在 JVM 中的唯一性,每一个类加载器, | |
| 都有一个独立的类名称空间。类加载器就是根据指定全限定名称将 class 文件加载到 JVM 内存,然后再转化为 class 对象。 | |
| 类加载器分类: | |
| 启动类加载器(Bootstrap ClassLoader),是虚拟机自身的一部分,用来加载Java_HOME/lib/目录中的, | |
| 或者被 -Xbootclasspath 参数所指定的路径中并且被虚拟机识别的类库; | |
| 其他类加载器: | |
| 扩展类加载器(Extension ClassLoader):负责加载\lib\ext目录或Java. ext. dirs系统变量指定的路径中的所有类库; | |
| 应用程序类加载器(Application ClassLoader)。负责加载用户类路径(classpath)上的指定类库,我们可以直接使用这个类加载器。 | |
| 一般情况,如果我们没有自定义类加载器默认就是用这个加载器。 | |
| 双亲委派模型:如果一个类加载器收到了类加载的请求,它首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每一层的类加载器都是如此, | |
| 这样所有的加载请求都会被传送到顶层的启动类加载器中,只有当父加载无法完成加载请求(它的搜索范围中没找到所需的类)时,子加载器才会尝试去加载类。 | |
| 说一下类装载的执行过程? | |
| 类装载分为以下 5 个步骤: | |
| 加载:根据查找路径找到相应的 class 文件然后导入; | |
| 检查:检查加载的 class 文件的正确性; | |
| 准备:给类中的静态变量分配内存空间; | |
| 解析:虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用就理解为一个标示,而在直接引用直接指向内存中的地址; | |
| 初始化:对静态变量和静态代码块执行初始化工作。 | |
| 怎么判断对象是否可以被回收? | |
| 一般有两种方法来判断: | |
| 引用计数器:为每个对象创建一个引用计数,有对象引用时计数器 +1,引用被释放时计数 -1,当计数器为 0 时就可以被回收。它有一个缺点不能解决循环引用的问题; | |
| 可达性分析:从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的。 | |
| Java 中都有哪些引用类型? | |
| 强引用:发生 gc 的时候不会被回收。 | |
| 软引用:有用但不是必须的对象,在发生内存溢出之前会被回收。 | |
| 弱引用:有用但不是必须的对象,在下一次GC时会被回收。 | |
| 虚引用(幽灵引用/幻影引用):无法通过虚引用获得对象,用 PhantomReference 实现虚引用,虚引用的用途是在 gc 时返回一个通知。 | |
| 说一下 JVM 有哪些垃圾回收算法? | |
| 标记-清除算法:标记无用对象,然后进行清除回收。缺点:效率不高,无法清除垃圾碎片。 | |
| 标记-整理算法:标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。 | |
| 复制算法:按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半。 | |
| 分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理算法。 | |
| 说一下 JVM 有哪些垃圾回收器? | |
| Serial:最早的单线程串行垃圾回收器。 | |
| Serial Old:Serial 垃圾回收器的老年版本,同样也是单线程的,可以作为 CMS 垃圾回收器的备选预案。 | |
| ParNew:是 Serial 的多线程版本。 | |
| Parallel 和 ParNew 收集器类似是多线程的,但 Parallel 是吞吐量优先的收集器,可以牺牲等待时间换取系统的吞吐量。 | |
| Parallel Old 是 Parallel 老生代版本,Parallel 使用的是复制的内存回收算法,Parallel Old 使用的是标记-整理的内存回收算法。 | |
| CMS:一种以获得最短停顿时间为目标的收集器,非常适用 B/S 系统。 | |
| G1:一种兼顾吞吐量和停顿时间的 GC 实现,是 JDK 9 以后的默认 GC 选项。 | |
| 详细介绍一下 CMS 垃圾回收器? | |
| CMS 是英文 Concurrent Mark-Sweep 的简称,是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器。对于要求服务器响应速度的应用上, | |
| 这种垃圾回收器非常适合。在启动 JVM 的参数加上“-XX:+UseConcMarkSweepGC”来指定使用 CMS 垃圾回收器。 | |
| CMS 使用的是标记-清除的算法实现的,所以在 gc 的时候回产生大量的内存碎片,当剩余内存不能满足程序运行要求时, | |
| 系统将会出现 Concurrent Mode Failure,临时 CMS 会采用 Serial Old 回收器进行垃圾清除,此时的性能将会被降低。 | |
| 新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别? | |
| 新生代回收器:Serial、ParNew、Parallel Scavenge | |
| 老年代回收器:Serial Old、Parallel Old、CMS | |
| 整堆回收器:G1 | |
| 新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;老年代回收器一般采用的是标记-整理的算法进行垃圾回收。 | |
| 简述分代垃圾回收器是怎么工作的? | |
| 分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是 2/3。 | |
| 新生代使用的是复制算法,新生代里有 3 个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1,它的执行流程如下: | |
| 把 Eden + From Survivor 存活的对象放入 To Survivor 区; | |
| 清空 Eden 和 From Survivor 分区; | |
| From Survivor 和 To Survivor 分区交换,From Survivor 变 To Survivor,To Survivor 变 From Survivor。 | |
| 每次在 From Survivor 到 To Survivor 移动时都存活的对象,年龄就 +1,当年龄到达 15(默认配置是 15)时,升级为老生代。大对象也会直接进入老生代。 | |
| 老生代当空间占用到达某个值之后就会触发全局垃圾收回,一般使用标记整理的执行算法。以上这些循环往复就构成了整个分代垃圾回收的整体执行流程。 | |
| 说一下 JVM 调优的工具? | |
| JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,其中最常用的是 jconsole 和 jvisualvm 这两款视图监控工具。 | |
| jconsole:用于对 JVM 中的内存、线程和类等进行监控; | |
| jvisualvm:JDK 自带的全能分析工具,可以分析:内存快照、线程快照、程序死锁、监控内存的变化、gc 变化等。 | |
| 常用的 JVM 调优的参数都有哪些? | |
| -Xms2g:初始化推大小为 2g; | |
| -Xmx2g:堆最大内存为 2g; | |
| -XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4; | |
| -XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2; | |
| –XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合; | |
| -XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合; | |
| -XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合; | |
| -XX:+PrintGC:开启打印 gc 信息; | |
| -XX:+PrintGCDetails:打印 gc 详细信息。 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| MySQL | |
| 数据库的三范式是什么? | |
| 第一范式:强调的是列的原子性,即数据库表的每一列都是不可分割的原子数据项。 | |
| 第二范式:要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性。 | |
| 第三范式:任何非主属性不依赖于其它非主属性。 | |
| 一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 MySQL 数据库,又插入了一条数据,此时 id 是几? | |
| InnoDB 表只会把自增主键的最大 id 记录在内存中,所以重启之后会导致最大 id 丢失。 | |
| 表类型如果是 MyISAM ,那 id 就是 8。 | |
| 表类型如果是 InnoDB,那 id 就是 6。 | |
| 说一下 ACID 是什么? | |
| Atomicity(原子性):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。 | |
| Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。 | |
| Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。 | |
| Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。 | |
| char 和 varchar 的区别是什么? | |
| char(n) :固定长度类型,比如订阅 char(10),当你输入"abc"三个字符的时候,它们占的空间还是 10 个字节,其他 7 个是空字节。 | |
| chat 优点:效率高;缺点:占用空间;适用场景:存储密码的 md5 值,固定长度的,使用 char 非常合适。 | |
| varchar(n) :可变长度,存储的值是每个值占用的字节再加上一个用来记录其长度的字节的长度。 | |
| 所以,从空间上考虑 varchar 比较合适;从效率上考虑 char 比较合适,二者使用需要权衡。 | |
| float 和 double 的区别是什么? | |
| float 最多可以存储 8 位的十进制数,并在内存中占 4 字节。 | |
| double 最可可以存储 16 位的十进制数,并在内存中占 8 字节。 | |
| MySQL 的内连接、左连接、右连接有什么区别? | |
| 内连接关键字:inner join;左连接:left join;右连接:right join。 | |
| 内连接是把匹配的关联数据显示出来;左连接是左边的表全部显示出来,右边的表显示出符合条件的数据;右连接正好相反。 | |
| MySQL 索引是怎么实现的? | |
| 索引是满足某种特定查找算法的数据结构,而这些数据结构会以某种方式指向数据,从而实现高效查找数据。 | |
| 具体来说 MySQL 中的索引,不同的数据引擎实现有所不同,但目前主流的数据库引擎的索引都是 B+ 树实现的, | |
| B+ 树的搜索效率,可以到达二分法的性能,找到数据区域之后就找到了完整的数据结构了,所有索引的性能也是更好的。 | |
| 怎么验证 MySQL 的索引是否满足需求? | |
| 使用 explain 查看 SQL 是如何执行查询语句的,从而分析你的索引是否满足需求。 | |
| explain 语法:explain select * from table where type=1。 | |
| 说一下数据库的事务隔离? | |
| MySQL 的事务隔离是在 MySQL. ini 配置文件里添加的,在文件的最后添加:transaction-isolation = REPEATABLE-READ | |
| sql命令: set session transaction isolation level 隔离级别 | |
| 可用的配置值:READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE。 | |
| read uncommitted:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读)。 | |
| read committed:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读)。 | |
| repeatable read:可重复读,默认级别,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读)。 | |
| serializable:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。 | |
| 脏读 :表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录 A,此时该事务还未提交,然后另一个事务尝试读取到了记录 A。 | |
| 不可重复读 :同一事务的其他实例在该实例处理期间可能会有新的commit, 所以同一select可能返回不同结果。 | |
| 幻读 :指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。 | |
| 发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或者变少了。 | |
| 说一下 MySQL 常用的引擎? | |
| InnoDB 引擎:MySQL 5.1 后默认的数据库引擎,提供了对数据库 acid 事务的支持,并且还提供了行级锁和外键的约束,它的设计的目标就是处理大数据容量的数据库系统。 | |
| MySQL 运行的时候,InnoDB 会在内存中建立缓冲池,用于缓冲数据和索引。但是该引擎是不支持全文搜索,同时启动也比较的慢,它是不会保存表的行数的, | |
| 所以当进行 select count(*) from table 指令的时候,需要进行扫描全表。由于锁的粒度小,写操作是不会锁定全表的,所以在并发度较高的场景下使用会提升效率的。 | |
| MyISAM 引擎:不提供事务的支持,也不支持行级锁和外键。因此当执行插入和更新语句时,即执行写操作的时候需要锁定这个表,所以会导致效率会降低。 | |
| 不过和 InnoDB 不同的是,MyISAM 引擎是保存了表的行数,于是当进行 select count(*) from table 语句时,可以直接的读取已经保存的值而不需要进行扫描全表。 | |
| 所以,如果表的读操作远远多于写操作时,并且不需要事务的支持的,可以将 MySQL 作为数据库引擎的首选。 | |
| 说一下 MySQL 的行锁和表锁? | |
| MySQL 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁。 | |
| 表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低。 | |
| 行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高。 | |
| 说一下乐观锁和悲观锁? | |
| 乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。 | |
| 悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻止,直到这个锁被释放。 | |
| 数据库的乐观锁需要自己实现,在表里面添加一个 version 字段,每次修改成功值加 1,这样每次修改的时候先对比一下, | |
| 自己拥有的 version 和数据库现在的 version 是否一致,如果不一致就不修改,这样就实现了乐观锁。 | |
| MySQL 问题排查都有哪些手段? | |
| 使用 show processlist 命令查看当前所有连接信息。 | |
| 使用 explain 命令查询 SQL 语句执行计划。 | |
| 开启慢查询日志,查看慢查询的 SQL。 | |
| 如何做 MySQL 的性能优化? | |
| 为搜索字段创建索引。 | |
| 避免使用 select *,列出需要查询的字段。 | |
| 垂直分割分表。 | |
| 选择正确的存储引擎。 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| RabbitMQ | |
| RabbitMQ 中重要的角色有:生产者、消费者和代理: | |
| 生产者:消息的创建者,负责创建和推送数据到消息服务器; | |
| 消费者:消息的接收方,用于处理数据和确认消息; | |
| 代理:就是 RabbitMQ 本身,用于扮演“快递”的角色,本身不生产消息,只是扮演“快递”的角色。 | |
| RabbitMQ 有哪些重要的组件? | |
| ConnectionFactory(连接管理器):应用程序与Rabbit之间建立连接的管理器,程序代码中使用。 | |
| Channel(信道):消息推送使用的通道。 | |
| Exchange(交换器):用于接受、分配消息。 | |
| Queue(队列):用于存储生产者的消息。 | |
| RoutingKey(路由键):用于把生产者的数据分配到交换器上。 | |
| BindingKey(绑定键):用于把交换器的消息绑定到队列上。 | |
| RabbitMQ 中 vhost 的作用是什么? | |
| vhost:每个 RabbitMQ 都能创建很多 vhost,我们称之为虚拟主机,每个虚拟主机其实都是 mini 版的RabbitMQ,它拥有自己的队列, | |
| 交换器和绑定,拥有自己的权限机制。 | |
| vhost通过在各个实例间提供逻辑上分离,允许你为不同应用程序安全保密地运行数据; | |
| RabbitMQ 的消息是怎么发送的? | |
| 首先客户端必须连接到 RabbitMQ 服务器才能发布和消费消息,客户端和 rabbit server 之间会创建一个 tcp 连接, | |
| 一旦 tcp 打开并通过了认证(认证就是你发送给rabbit服务器的用户名和密码),你的客户端和RabbitMQ就创建了一条amqp信道(channel), | |
| 信道是创建在"真实" tcp 上的虚拟连接,amqp 命令都是通过信道发送出去的,每个信道都会有一个唯一的 id,不论是发布消息, | |
| 订阅队列都是通过这个信道完成的。 | |
| RabbitMQ 怎么保证消息的稳定性? | |
| 提供了事务的功能。 | |
| 通过将 channel 设置为 confirm(确认)模式。 | |
| RabbitMQ 怎么避免消息丢失? | |
| 把消息持久化磁盘,保证服务器重启消息不丢失。 | |
| 每个集群中至少有一个物理磁盘,保证消息落入磁盘。 | |
| 要保证消息持久化成功的条件有哪些? | |
| 以下四个条件都满足才能保证消息持久化成功。 | |
| 声明队列必须设置持久化 durable 设置为 true. | |
| 消息推送投递模式必须设置持久化,deliveryMode 设置为 2(持久)。 | |
| 消息已经到达持久化交换器。 | |
| 消息已经到达持久化队列。 | |
| RabbitMQ 持久化有什么缺点? | |
| 持久化的缺地就是降低了服务器的吞吐量,因为使用的是磁盘而非内存存储,从而降低了吞吐量。可尽量使用 ssd 硬盘来缓解吞吐量的问题。 | |
| RabbitMQ 有几种广播类型? | |
| direct(默认方式):最基础最简单的模式,发送方把消息发送给订阅方,如果有多个订阅者,默认采取轮询的方式进行消息发送。 | |
| headers:与 direct 类似,只是性能很差,此类型几乎用不到。 | |
| fanout:分发模式,把消费分发给所有订阅者。 | |
| topic:匹配订阅模式,使用正则匹配到消息队列,能匹配到的都能接收到。 | |
| RabbitMQ 怎么实现延迟消息队列? | |
| 延迟队列的实现有两种方式: | |
| 通过消息过期后进入死信交换器,再由交换器转发到延迟消费队列,实现延迟功能; | |
| 使用 RabbitMQ-delayed-message-exchange 插件实现延迟功能。 | |
| RabbitMQ 集群有什么用? | |
| 集群主要有以下两个用途: | |
| 高可用:某个服务器出现问题,整个 RabbitMQ 还可以继续使用; | |
| 高容量:集群可以承载更多的消息量。 | |
| RabbitMQ 节点的类型有哪些? | |
| 磁盘节点:消息会存储到磁盘。 | |
| 内存节点:消息都存储在内存中,重启服务器消息丢失,性能高于磁盘类型。 | |
| RabbitMQ 对集群节点停止顺序有要求吗? | |
| RabbitMQ 对集群的停止的顺序是有要求的,应该先关闭内存节点,最后再关闭磁盘节点。如果顺序恰好相反的话,可能会造成消息的丢失。 | |
| RabbitMQ 集群搭建需要注意哪些问题? | |
| 各节点之间使用“--link”连接,此属性不能忽略。 | |
| 各节点使用的 erlang cookie 值必须相同,此值相当于“秘钥”的功能,用于各节点的认证。 | |
| 整个集群中必须包含一个磁盘节点。 | |
| RabbitMQ 每个节点是其他节点的完整拷贝吗?为什么? | |
| 不是,原因有以下两个: | |
| 存储空间的考虑:如果每个节点都拥有所有队列的完全拷贝,这样新增节点不但没有新增存储空间,反而增加了更多的冗余数据; | |
| 性能的考虑:如果每条消息都需要完整拷贝到每一个集群节点,那新增节点并没有提升处理消息的能力,最多是保持和单节点相同的性能甚至是更糟。 | |
| RabbitMQ 集群中唯一一个磁盘节点崩溃了会发生什么情况? | |
| 如果唯一磁盘的磁盘节点崩溃了,不能进行以下操作: | |
| 不能创建队列 | |
| 不能创建交换器 | |
| 不能创建绑定 | |
| 不能添加用户 | |
| 不能更改权限 | |
| 不能添加和删除集群节点 | |
| 唯一磁盘节点崩溃了,集群是可以保持运行的,但你不能更改任何东西。 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Redis | |
| Redis 是什么?都有哪些使用场景? | |
| Redis 是一个使用 C 语言开发的高速缓存数据库。 | |
| Redis 使用场景: | |
| 记录帖子点赞数、点击数、评论数; | |
| 缓存近期热帖; | |
| 缓存文章详情信息; | |
| 记录用户会话信息。 | |
| Redis 有哪些功能? | |
| 数据缓存功能 | |
| 分布式锁的功能 | |
| 支持数据持久化 | |
| 支持事务 | |
| 支持消息队列 | |
| Redis 和 memcache 有什么区别? | |
| 存储方式不同:memcache 把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小;Redis 有部份存在硬盘上,这样能保证数据的持久性。 | |
| 数据支持类型:memcache 对数据类型支持相对简单;Redis 有复杂的数据类型。 | |
| 使用底层模型不同:它们之间底层实现方式,以及与客户端之间通信的应用协议不一样,Redis 自己构建了 vm 机制,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。 | |
| value 值大小不同:Redis 最大可以达到 512mb;memcache 只有 1mb。 | |
| Redis 为什么是单线程的? | |
| 因为 cpu 不是 Redis 的瓶颈,Redis 的瓶颈最有可能是机器内存或者网络带宽。既然单线程容易实现,而且 cpu 又不会成为瓶颈,那就顺理成章地采用单线程的方案了。 | |
| 关于 Redis 的性能,官方网站也有,普通笔记本轻松处理每秒几十万的请求。 | |
| 而且单线程并不代表就慢 nginx 和 nodejs 也都是高性能单线程的代表。 | |
| 什么是缓存穿透?怎么解决? | |
| 缓存穿透:指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。 | |
| 解决方案:最简单粗暴的方法如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们就把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。 | |
| Redis 支持的数据类型有哪些? | |
| Redis 支持的数据类型:string(字符串)、list(列表)、hash(字典)、set(集合)、zset(有序集合)。 | |
| Redis 支持的 Java 客户端都有哪些? | |
| 支持的 Java 客户端有 Redisson、jedis、lettuce 等。 | |
| jedis 和 Redisson 有哪些区别? | |
| jedis:提供了比较全面的 Redis 命令的支持。 | |
| Redisson:实现了分布式和可扩展的 Java 数据结构,与 jedis 相比 Redisson 的功能相对简单,不支持排序、事务、管道、分区等 Redis 特性。 | |
| 怎么保证缓存和数据库数据的一致性? | |
| 合理设置缓存的过期时间。 | |
| 新增、更改、删除数据库操作时同步更新 Redis,可以使用事物机制来保证数据的一致性。 | |
| Redis 持久化有几种方式? | |
| Redis 的持久化有两种方式,或者说有两种策略: | |
| RDB(Redis Database):指定的时间间隔能对你的数据进行快照存储。 | |
| AOF(Append Only File):每一个收到的写命令都通过write函数追加到文件中。 | |
| Redis 怎么实现分布式锁? | |
| Redis 分布式锁其实就是在系统里面占一个“坑”,其他程序也要占“坑”的时候,占用成功了就可以继续执行,失败了就只能放弃或稍后重试。 | |
| 占坑一般使用 setnx(set if not exists)指令,只允许被一个程序占有,使用完调用 del 释放锁。 | |
| Redis 分布式锁有什么缺陷? | |
| Redis 分布式锁不能解决超时的问题,分布式锁有一个超时时间,程序的执行如果超出了锁的超时时间就会出现问题。 | |
| Redis 如何做内存优化? | |
| 尽量使用 Redis 的散列表,把相关的信息放到散列表里面存储,而不是把每个字段单独存储,这样可以有效的减少内存使用。 | |
| 比如将 Web 系统的用户对象,应该放到散列表里面再整体存储到 Redis,而不是把用户的姓名、年龄、密码、邮箱等字段分别设置 key 进行存储。 | |
| Redis 淘汰策略有哪些? | |
| volatile-lru:从已设置过期时间的数据集(server. db[i]. expires)中挑选最近最少使用的数据淘汰。 | |
| volatile-ttl:从已设置过期时间的数据集(server. db[i]. expires)中挑选将要过期的数据淘汰。 | |
| volatile-random:从已设置过期时间的数据集(server. db[i]. expires)中任意选择数据淘汰。 | |
| allkeys-lru:从数据集(server. db[i]. dict)中挑选最近最少使用的数据淘汰。 | |
| allkeys-random:从数据集(server. db[i]. dict)中任意选择数据淘汰。 | |
| no-enviction(驱逐):禁止驱逐数据。 | |
| Redis 常见的性能问题有哪些?该如何解决? | |
| 主服务器写内存快照,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以主服务器最好不要写内存快照。 | |
| Redis 主从复制的性能问题,为了主从复制的速度和连接的稳定性,主从库最好在同一个局域网内。 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 为什么要使用 spring? | |
| spring 提供 ioc 技术,容器会帮你管理依赖的对象,从而不需要自己创建和管理依赖对象了,更轻松的实现了程序的解耦。 | |
| spring 提供了事务支持,使得事务操作变的更加方便。 | |
| spring 提供了面向切片编程,这样可以更方便的处理某一类的问题。 | |
| 更方便的框架集成,spring 可以很方便的集成其他框架,比如 MyBatis、hibernate 等。 | |
| aop | |
| aop 是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。 | |
| 简单来说就是统一处理某一“切面”(类)的问题的编程思想,比如统一处理日志、异常等。 | |
| ioc | |
| ioc:Inversion of Control(控制反转)是 spring 的核心,对于 spring 框架来说,就是由 spring 来负责控制对象的生命周期和对象间的关系。 | |
| 简单来说,控制指的是当前对象对内部成员的控制权;控制反转指的是,这种控制权不由当前对象管理了,由其他(类,第三方容器)来管理。 | |
| spring 有哪些主要模块? | |
| spring core:框架的最基础部分,提供 ioc 和依赖注入特性。 | |
| spring context:构建于 core 封装包基础上的 context 封装包,提供了一种框架式的对象访问方法。 | |
| spring dao:Data Access Object 提供了JDBC的抽象层。 | |
| spring aop:提供了面向切面的编程实现,让你可以自定义拦截器、切点等。 | |
| spring Web:提供了针对 Web 开发的集成特性,例如文件上传,利用 servlet listeners 进行 ioc 容器初始化和针对 Web 的 ApplicationContext。 | |
| spring Web mvc:spring 中的 mvc 封装包提供了 Web 应用的 Model-View-Controller(MVC)的实现。 | |
| spring 中的 bean 是线程安全的吗? | |
| spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线程的封装处理。 | |
| 实际上大部分时候 spring bean 无状态的(比如 dao 类),所有某种程度上来说 bean 也是安全的,但如果 bean 有状态的话(比如 view model 对象), | |
| 那就要开发者自己去保证线程安全了,最简单的就是改变 bean 的作用域,把“singleton”变更为“prototype”,这样请求 bean 相当于 new Bean()了,所以就可以保证线程安全了。 | |
| 有状态就是有数据存储功能。 | |
| 无状态就是不会保存数据。 | |
| 修改spring的Bean的作用域 | |
| <bean id="accountDao" class="com.mt.dao.impl.AccountDaoImpl" scope="prototype"></bean> | |
| spring 支持几种 bean 的作用域? | |
| spring 支持 5 种作用域,如下: | |
| singleton:spring ioc 容器中只存在一个 bean 实例,bean 以单例模式存在,是系统默认值; | |
| prototype:每次从容器调用 bean 时都会创建一个新的示例,既每次 getBean()相当于执行 new Bean()操作; | |
| 注意: 使用 prototype 作用域需要慎重的思考,因为频繁创建和销毁 bean 会带来很大的性能开销。 | |
| Web 环境下的作用域: | |
| request:每次 http 请求都会创建一个 bean; | |
| session:同一个 http session 共享一个 bean 实例; | |
| global-session:用于 portlet 容器,因为每个 portlet 有单独的 session,globalsession 提供一个全局性的 http session。 | |
| spring 自动装配 bean 有哪些方式? | |
| no:默认值,表示没有自动装配,应使用显式 bean 引用进行装配。 | |
| byName:它根据 bean 的名称注入对象依赖项。 | |
| byType:它根据类型注入对象依赖项。 | |
| 构造函数:通过构造函数来注入依赖项,需要设置大量的参数。 | |
| autodetect:容器首先通过构造函数使用 autowire 装配,如果不能,则通过 byType 自动装配。 | |
| spring 事务实现方式有哪些? | |
| 声明式事务:声明式事务也有两种实现方式,基于 xml 配置文件的方式和注解方式(在类上添加 @Transaction 注解)。 | |
| 编码方式:提供编码的形式管理和维护事务。 | |
| 说一下 spring 的事务隔离? | |
| spring 有五大隔离级别,默认值为 ISOLATION_DEFAULT(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致: | |
| ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么; | |
| ISOLATION READ UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读); | |
| ISOLATION READ COMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别; | |
| ISOLATION REPEATABLE READ:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别; | |
| ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。 | |
| 脏读:表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录A,此时该事务还未提交,然后另一个事务尝试读取到了记录A。 | |
| 不可重复读:同一事务的其他实例在该实例处理期间可能会有新的commit, 所以同一select可能返回不同结果。 | |
| 幻读:指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。 | |
| 发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或者变少了。 | |
| ======================================================springMVC====================================================== | |
| spring mvc 运行流程 | |
| spring mvc 先将用户请求发送给 DispatcherServlet。 | |
| DispatcherServlet 查询一个或多个 HandlerMapping,HandlerMapping返回一个Handler链。 | |
| DispatcherServlet 访问HandlerAdapter,由HandlerAdapter去执行处理器方法,Controller 进行业务逻辑处理后,会返回一个ModelAndView。 | |
| DispatcherServlet 查询一个或多个 ViewResolver 视图解析器,找到 ModelAndView 对象指定的视图对象。 | |
| View 视图对象负责渲染。 | |
| 渲染完毕后响应给用户 | |
| spring mvc 有哪些组件? | |
| DispatcherServlet:中央控制器 | |
| 用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心, | |
| 由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。 | |
| 这玩意是核心,就是门卫传达室,一个请求进来先来传达室,然后一步步来处理问题。就是个servlet。 | |
| HandlerMapping:处理器映射器 | |
| HandlerMapping负责根据用户请求url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,如配置文件方式,实现接口方式,注解方式等。 | |
| 这玩意就是个map,放了一堆数据,key是url,value是你对应的处理器。一个请求来了,调用一下mao.get(url)就知道哪个类的哪个方法处理这个请求了。 | |
| 当然实际上会将这个url多对应的拦截器,处理器都拿到。 | |
| HandelAdapter:处理器适配器 | |
| 通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。 | |
| 这货会调用相应的方法,生成最终能够的modelAndView | |
| Controller 处理器 | |
| 处理用户请求的方法,编写后端的逻辑代码 | |
| ModelAndView 模型和视图 | |
| 视图和模型是两个东西,既然存在ModelAndView就存在Model和View。 | |
| ViewResolver:视图解析器 | |
| View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址, | |
| 再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 | |
| 这货就是解析modelAndView的。有个常用最简单的功能就是拼接字符串,给你加个前缀后缀,让你方便了很多,当然他们解析很多类型的视图。 | |
| @RequestMapping 的作用是什么? | |
| 将http请求映射到相应的类/方法上。 | |
| @Autowired的作用是什么? | |
| @Autowired 它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作,通过@Autowired 的使用来消除 set/get 方法。 | |
| ======================================================Spring Boot====================================================== | |
| 什么是 spring boot? | |
| spring boot 是为 spring 服务的,是用来简化新 spring 应用的初始搭建以及开发过程的。 | |
| 为什么要用 spring boot? | |
| 配置简单 | |
| 独立运行 | |
| 自动装配 | |
| 无代码生成和 xml 配置 | |
| 提供应用监控 | |
| 易上手 | |
| 提升开发效率 | |
| spring boot核心配置文件是什么? | |
| spring boot核心的两个配置文件: | |
| bootstrap (. yml 或者 . properties):boostrap 由父 ApplicationContext 加载的,比 application 优先加载,且 boostrap 里面的属性不能被覆盖; | |
| application (. yml 或者 . properties):用于 spring boot 项目的自动化配置 | |
| spring boot 有哪些方式可以实现热部署? | |
| 使用 devtools 启动热部署,添加 devtools 库,在配置文件中把 spring. devtools. restart. enabled 设置为 true; | |
| 使用 Intellij Idea 编辑器,勾上自动编译或手动重新编译。 | |
| jpa 和 hibernate 有什么区别? | |
| jpa 全称 Java Persistence API,是 Java 持久化接口规范,hibernate 属于 jpa 的具体实现。 | |
| ======================================================Spring Cloud====================================================== | |
| 什么是 spring cloud? | |
| spring cloud 是一系列框架的有序集合。它利用 spring boot 的开发便利性巧妙地简化了分布式系统基础设施的开发, | |
| 如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 spring boot 的开发风格做到一键启动和部署。 | |
| spring cloud 的核心组件有哪些? | |
| Eureka:服务注册于发现。 | |
| Feign:基于动态代理机制,根据注解和选择的机器,拼接请求 url 地址,发起请求。 | |
| Ribbon:实现负载均衡,从一个服务的多台机器中选择一台。 | |
| Hystrix:提供线程池,不同的服务走不同的线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题。 | |
| Zuul:网关管理,由 Zuul 网关转发请求给对应的服务。 | |
| spring cloud Alibaba 的核心组件有哪些? | |
| Sentinel: 把流量作为切入点, 从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 | |
| Nacos: 一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 | |
| Seata: 阿里巴巴开源产品, 一个易于使用的高性能微服务分布式事务解决方案 | |
| GetWay: 网关 | |
| Openfeign: 远程调用 | |
| spring cloud 断路器的作用是什么? | |
| 在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝), | |
| 向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延 | |
| ======================================================Mybatis====================================================== | |
| MyBatis 和 hibernate 的区别有哪些? | |
| 灵活性:MyBatis 更加灵活,自己可以写 SQL 语句,使用起来比较方便。 | |
| 可移植性:MyBatis 有很多自己写的 SQL,因为每个数据库的 SQL 可以不相同,所以可移植性比较差。 | |
| 学习和使用门槛:MyBatis 入门比较简单,使用门槛也更低。 | |
| 二级缓存:hibernate 拥有更好的二级缓存,它的二级缓存可以自行更换为第三方的二级缓存 | |
| MyBatis 中 #{}和 ${}的区别是什么? | |
| #{}是预编译处理,${}是字符替换。在使用 #{}时,MyBatis会将 SQL 中的 #{}替换成“?”, | |
| 配合 PreparedStatement 的 set 方法赋值,这样可以有效的防止 SQL 注入,保证程序的运行安全。 | |
| MyBatis 有几种分页方式? | |
| 分页方式:逻辑分页和物理分页。 | |
| 逻辑分页:使用 MyBatis 自带的 RowBounds 进行分页,它是一次性查询很多数据,然后在数据中再进行检索。 | |
| 物理分页:自己手写 SQL 分页或使用分页插件 PageHelper,去数据库查询指定条数的分页数据的形式。 | |
| RowBounds(Mybatis的分页) 是一次性查询全部结果吗?为什么? | |
| RowBounds表面是在“所有”数据中检索数据,其实并非是一次性查询出所有数据,因为 MyBatis 是对 jdbc 的封装,在 jdbc 驱动中有一个 Fetch Size 的配置, | |
| 它规定了每次最多从数据库查询多少条数据,假如你要查询更多数据,它会在你执行 next()的时候,去查询更多的数据。就好比你去自动取款机取 10000 元, | |
| 但取款机每次最多能取 2500 元,所以你要取 4 次才能把钱取完。只是对于 jdbc 来说,当你调用 next()的时候会自动帮你完成查询工作。这样做的好处可以有效的防止内存溢出。 | |
| MyBatis 逻辑分页和物理分页的区别是什么? | |
| 逻辑分页是一次性查询很多数据,然后再在结果中检索分页的数据。这样做弊端是需要消耗大量的内存、有内存溢出的风险、对数据库压力较大。 | |
| 物理分页是从数据库查询指定条数的数据,弥补了一次性全部查出的所有数据的种种缺点,比如需要大量的内存,对数据库查询压力较大等问题。 | |
| MyBatis 是否支持延迟加载?延迟加载的原理是什么? | |
| MyBatis 支持延迟加载,设置 lazyLoadingEnabled=true 即可。 | |
| 延迟加载的原理的是调用的时候触发加载,而不是在初始化的时候就加载信息。比如调用 a. getB(). getName(),这个时候发现 a. getB() 的值为 null, | |
| 此时会单独触发事先保存好的关联 B 对象的 SQL,先查询出来 B,然后再调用 a. setB(b),而这时候再调用 a. getB(). getName() 就有值了,这就是延迟加载的基本原理。 | |
| 说一下 MyBatis 的一级缓存和二级缓存? | |
| 一级缓存:基于 PerpetualCache 的 HashMap 本地缓存,它的声明周期是和 SQLSession 一致的,有多个 SQLSession 或者分布式的环境中数据库操作,可能会出现脏数据。 | |
| 当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认一级缓存是开启的。 | |
| 二级缓存:也是基于 PerpetualCache 的 HashMap 本地缓存,不同在于其存储作用域为 Mapper 级别的,如果多个SQLSession之间需要共享缓存,则需要使用到二级缓存, | |
| 并且二级缓存可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现 Serializable 序列化接口(可用来保存对象的状态)。 | |
| 开启二级缓存数据查询流程:二级缓存 -> 一级缓存 -> 数据库。 | |
| 缓存更新机制:当某一个作用域(一级缓存 Session/二级缓存 Mapper)进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。 | |
| MyBatis 有哪些执行器(Executor)? | |
| MyBatis 有三种基本的Executor执行器: | |
| SimpleExecutor:每执行一次 update 或 select 就开启一个 Statement 对象,用完立刻关闭 Statement 对象; | |
| ReuseExecutor:执行 update 或 select,以 SQL 作为 key 查找 Statement 对象,存在就使用,不存在就创建, | |
| 用完后不关闭 Statement 对象,而是放置于 Map 内供下一次使用。简言之,就是重复使用 Statement 对象; | |
| BatchExecutor:执行 update(没有 select,jdbc 批处理不支持 select),将所有 SQL 都添加到批处理中(addBatch()),等待统一执行(executeBatch()), | |
| 它缓存了多个 Statement 对象,每个 Statement 对象都是 addBatch()完毕后,等待逐一执行 executeBatch()批处理,与 jdbc 批处理相同。 | |
| MyBatis 分页插件的实现原理是什么? | |
| 分页插件的基本原理是使用 MyBatis 提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的 SQL,然后重写 SQL,根据 dialect 方言,添加对应的物理分页语句和物理分页参数。 | |
| MyBatis 如何编写一个自定义插件? | |
| 自定义插件实现原理 | |
| MyBatis 自定义插件针对 MyBatis 四大对象(Executor、StatementHandler、ParameterHandler、ResultSetHandler)进行拦截: | |
| Executor:拦截内部执行器,它负责调用 StatementHandler 操作数据库,并把结果集通过 ResultSetHandler 进行自动映射,另外它还处理了二级缓存的操作; | |
| StatementHandler:拦截 SQL 语法构建的处理,它是 MyBatis 直接和数据库执行 SQL 脚本的对象,另外它也实现了 MyBatis 的一级缓存; | |
| ParameterHandler:拦截参数的处理; | |
| ResultSetHandler:拦截结果集的处理。 | |
| 自定义插件实现关键 | |
| MyBatis 插件要实现 Interceptor 接口,接口包含的方法,如下: | |
| public interface Interceptor { | |
| Object intercept(Invocation invocation) throws Throwable; | |
| Object plugin(Object target); | |
| void setProperties(Properties properties); | |
| } | |
| intercept 方法就是要进行拦截的时候要执行的方法。 | |
| setProperties 方法是在 MyBatis 进行配置插件的时候可以配置自定义相关属性,即:接口实现对象的参数配置; | |
| plugin 方法是插件用于封装目标对象的,通过该方法我们可以返回目标对象本身,也可以返回一个它的代理, | |
| 可以决定是否要进行拦截进而决定要返回一个什么样的目标对象,官方提供了示例:return Plugin. wrap(target, this); | |
| 自定义插件实现示例 | |
| 官方插件实现: | |
| @Intercepts({@Signature(type = Executor.class, method = "query", | |
| args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})}) | |
| public class TestInterceptor implements Interceptor { | |
| public Object intercept(Invocation invocation) throws Throwable { | |
| Object target = invocation. getTarget(); 被代理对象 | |
| Method method = invocation. getMethod(); 代理方法 | |
| Object[] args = invocation. getArgs(); 方法参数 | |
| // do something . . . . . . 方法拦截前执行代码块 | |
| Object result = invocation. proceed(); | |
| // do something . . . . . . . 方法拦截后执行代码块 | |
| return result; | |
| } | |
| public Object plugin(Object target) { | |
| return Plugin. wrap(target, this); | |
| } | |
| } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 怎么解决线程安全问题 | |
| 不要一上来就使用Synchronized,这样会让程序的执行效率降低 在不得已的情况下再使用Synchronized | |
| 尽量使用局部变量来代替实例变量(全局变量)和静态变量(局部变量在栈内存中 不共享数据 没有线程安全问题) | |
| 如果必须使用全局变量 那么应该考虑创建多个对象 这样全局变量的内存就不共享了(一个线程对应一个对象 一百个线程对应一百个对象 对象不共享就没有线程安全问题) | |
| 线程的五种状态 | |
| 新建状态:刚new出来的线程状态 | |
| start() 方法进入就绪状态 | |
| 就绪状态:就绪状态又叫可运行状态,表示当前线程具有抢夺CPU时间片的权力。当一个线程抢夺到CPU时间片就会执行 run() 方法,run() 方法的开始执行标示着线程进入运行状态 | |
| JVM开始调度(yield),分配线程开始执行 | |
| 运行状态:run()方法中的编写的代码开始执行,当当前占有的CPU时间片用完之后会重新回到就绪状态继续抢夺CPU时间片,当再次抢夺到CPU时间片之后会重新进入run()方法接着上一次的代码继续往下执行 | |
| 当遭遇到堵塞事件后 进入到堵塞状态 | |
| 堵塞状态:当一个线程遇到堵塞事件(接收用户键盘输入、sleep()等)后会进入到堵塞状态并放弃之前占有的CPU时间片 | |
| 堵塞状态解除,会再次回到就绪状态抢夺CPU时间片 | |
| 死亡状态:run()执行结束 线程死亡 | |
| 线程有哪些状态? | |
| NEW 尚未启动 | |
| RUNNABLE 正在执行中 | |
| BLOCKED 阻塞的(被同步锁或者IO锁阻塞) | |
| WAITING 永久等待状态 | |
| TIMED_WAITING 等待指定的时间重新被唤醒的状态 | |
| TERMINATED 执行完成 | |
| 在 Java 程序中怎么保证多线程的运行安全? | |
| 方法一:使用安全类,比如 Java. util. concurrent 下的类。 | |
| 方法二:使用自动锁 synchronized。 | |
| 方法三:使用手动锁 Lock。 | |
| Lock lock = new ReentrantLock(); | |
| try { | |
| lock. lock(); 获取锁 | |
| } catch (Exception e) { | |
| } finally { | |
| lock. unlock(); 释放锁 | |
| } | |
| 多线程中 synchronized 锁升级的原理是什么? | |
| 在锁对象的对象头里面有一个threadid字段,在第一次访问的时候threadid为空,jvm 让其持有偏向锁,并将threadid设置为其线程id, | |
| 再次进入的时候会先判断threadid是否与其线程id一致,如果一致则可以直接使用此对象,如果不一致,则升级偏向锁为轻量级锁,通过自旋循环一定次数来获取锁, | |
| 执行一定次数之后,如果还没有正常获取到要使用的对象,此时就会把锁从轻量级升级为重量级锁,此过程就构成了synchronized锁的升级。 | |
| 锁的升级的目的: | |
| 锁升级是为了减低了锁带来的性能消耗。在Java 6之后优化synchronized的实现方式,使用了偏向锁升级为轻量级锁再升级到重量级锁的方式,从而减低了锁带来的性能消耗。 | |
| 怎么防止死锁? | |
| 尽量使用tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),设置超时时间,超时可以退出防止死锁。 | |
| 尽量使用Java. util. concurrent并发类代替自己手写锁。 | |
| 尽量降低锁的使用粒度,尽量不要几个功能用同一把锁。 | |
| 尽量减少同步的代码块。 | |
| synchronized底层实现原理? | |
| synchronized是由一对' monitorenter/monitorexit '指令实现的,monitor对象是同步的基本实现单元。在Java 6之前,monitor的实现完全是依靠操作系统内部的互斥锁, | |
| 因为需要进行用户态到内核态的切换,所以同步操作是一个无差别的重量级操作,性能也很低。但在Java 6的时候,Java虚拟机对此进行了大刀阔斧地改进, | |
| 提供了三种不同的monitor实现,也就是常说的三种不同的锁:偏向锁(Biased Locking)、轻量级锁和重量级锁,大大改进了其性能。 | |
| synchronized 和 volatile 的区别是什么? | |
| volatile 是变量修饰符;synchronized 是修饰类、方法、代码段。 | |
| volatile 仅能实现变量的修改可见性,不能保证原子性;而 synchronized 则可以保证变量的修改可见性和原子性。 | |
| volatile 不会造成线程的阻塞;synchronized 可能会造成线程的阻塞 | |
| synchronized 和 Lock 有什么区别? | |
| synchronized 可以给类、方法、代码块加锁;而lock只能给代码块加锁。 | |
| synchronized 不需要手动获取锁和释放锁,使用简单,发生异常会自动释放锁,不会造成死锁;而lock需要自己加锁和释放锁,如果使用不当没有unLock()去释放锁就会造成死锁。 | |
| 通过Lock可以知道有没有成功获取锁,而 synchronized 却无法办到 | |
| 说一下 atomic 的原理? | |
| atomic 主要利用 CAS (Compare And Wwap) 和 volatile 和 native 方法来保证原子操作,从而避免 synchronized 的高开销,执行效率大为提升 | |
| ================================================================================================================================================================================ | |
| 反射 | |
| 什么是反射? | |
| 反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; | |
| 对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制 | |
| 什么是 Java 序列化?什么情况下需要序列化? | |
| Java 序列化是为了保存各种对象在内存中的状态,并且可以把保存的对象状态再读出来。 | |
| 以下情况需要使用Java序列化: | |
| 想把的内存中的对象状态保存到一个文件中或者数据库中时候; | |
| 想用套接字在网络上传送对象的时候; | |
| 想通过RMI(远程方法调用)传输对象的时候。 | |
| 对象拷贝 | |
| 为什么要使用克隆? | |
| 克隆的对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠克隆方法了。 | |
| 如何实现对象克隆? | |
| 实现 Cloneable 接口并重写 Object 类中的 clone() 方法。 | |
| 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。 | |
| 深拷贝和浅拷贝区别是什么? | |
| 浅克隆:当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。 | |
| 深克隆:除了对象本身被复制外,对象所包含的所有成员变量也将复制。 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| session 和 cookie 有什么区别? | |
| 存储位置不同:session 存储在服务器端;cookie 存储在浏览器端。 | |
| 安全性不同:cookie 安全性一般,在浏览器存储,可以被伪造和修改。 | |
| 容量和个数限制:cookie 有容量限制,每个站点下的 cookie 也有个数限制。 | |
| 存储的多样性:session 可以存储在 Redis 中、数据库中、应用程序中;而 cookie 只能存储在浏览器中。 | |
| session的工作原理 | |
| 客户端登录完成之后,服务器会创建对应的session,session创建完之后,会把session的id发送给客户端,客户端再存储到浏览器中。 | |
| 这样客户端每次访问服务器时,都会带着sessionId,服务器拿到sessionId之后,在内存找到与之对应的session这样就可以正常工作了。 | |
| 如果客户端禁止cookie能实现session还能用吗? | |
| 可以用,session只是依赖cookie存储sessionId,如果cookie被禁用了,可以使用url中添加sessionId的方式保证session能正常使用。 | |
| 如何避免 SQL 注入? | |
| 使用预处理 PreparedStatement。 | |
| 使用正则表达式过滤掉字符中的特殊字符。 | |
| 什么是 XSS 攻击,如何避免? | |
| XSS 攻击:即跨站脚本攻击,它是 Web 程序中常见的漏洞。原理是攻击者往 Web 页面里插入恶意的脚本代码(css 代码、Javascript 代码等), | |
| 当用户浏览该页面时,嵌入其中的脚本代码会被执行,从而达到恶意攻击用户的目的,如盗取用户 cookie、破坏页面结构、重定向到其他网站等。 | |
| 预防 XSS 的核心是必须对输入的数据做过滤处理。 | |
| 什么是 CSRF 攻击,如何避免? | |
| CSRF:Cross-Site Request Forgery(中文:跨站请求伪造),可以理解为攻击者盗用了你的身份,以你的名义发送恶意请求, | |
| 比如:以你名义发送邮件、发消息、购买商品,虚拟货币转账等。 | |
| 防御手段:验证请求来源地址;关键操作添加验证码;在请求地址添加 token 并验证。 | |
| final、finally、finalize 有什么区别? | |
| final:是修饰符,如果修饰类,此类不能被继承;如果修饰方法和变量,则表示此方法和此变量不能在被改变,只能使用。 | |
| finally:是 try{} catch{} finally{} 最后一部分,表示不论发生任何情况都会执行,finally 部分可以省略,但如果 finally 部分存在,则一定会执行 finally 里面的代码。 | |
| finalize: 是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法。 | |
| try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗? | |
| finally 一定会执行,即使是 catch 中 return 了,catch 中的 return 会等 finally 中的代码执行完之后,才会执行。 | |
| 如果try和catch的return是一个变量时且函数的是从其中一个返回时,后面finally中语句即使有对返回的变量进行赋值的操作时,也不会影响try和catch返回的值。 | |
| 网络 | |
| http 响应码 301 和 302 代表的是什么?有什么区别? | |
| 301:永久重定向。 | |
| 302:暂时重定向。 | |
| 它们的区别是,301 对搜索引擎优化(SEO)更加有利;302 有被提示为网络拦截的风险。 | |
| forward 和 redirect 的区别? | |
| forward 是转发 和 redirect 是重定向: | |
| 地址栏 url 显示:forward url 不会发生改变,redirect url 会发生改变; | |
| 数据共享:forward 可以共享 request 里的数据,redirect 不能共享; | |
| 效率:forward 比 redirect 效率高。 | |
| 简述 tcp 和 udp的区别? | |
| tcp 和 udp 是 OSI 模型中的运输层中的协议。tcp 提供可靠的通信传输,而 udp 则常被用于让广播和细节控制交给应用的通信传输。 | |
| 两者的区别大致如下: | |
| tcp 面向连接,udp 面向非连接即发送数据前不需要建立链接; | |
| tcp 提供可靠的服务(数据传输),udp 无法保证; | |
| tcp 面向字节流,udp 面向报文; | |
| tcp 数据传输慢,udp 数据传输快; | |
| TCP三次握手: | |
| 第一次握手:客户端发送syn包(syn=x)到服务器,并进入SYN_SEND状态,等待服务器确认; | |
| 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态; | |
| 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(建立了)状态,完成三次握手。 | |
| 握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下 TCP连接一旦建立 在通信双方中的任何一方主动关闭连接之前,TCP连接都将被一直保持下去。 | |
| TCP四次挥手 | |
| 与建立连接的“三次握手”类似,断开一个TCP连接则需要“四次握手”。 | |
| 第一次挥手:主动关闭方发送一个FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不 会再给你发数据了 | |
| (当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,主动关闭方依然会重发这些数据),但是,此时主动关闭方还可 以接受数据。 | |
| 第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。 | |
| 第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。 | |
| 第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。 | |
| TCP为什么要三次握手,两次不行吗?为什么? | |
| 如果采用两次握手,那么只要服务器发出确认数据包就会建立连接,但由于客户端此时并未响应服务器端的请求,那此时服务器端就会一直在等待客户端, | |
| 这样服务器端就白白浪费了一定的资源。若采用三次握手,服务器端没有收到来自客户端的再此确认,则就会知道客户端并没有要求建立请求,就不会浪费服务器的资源。 | |
| 说一下 tcp 粘包是怎么产生的? | |
| tcp 粘包可能发生在发送端或者接收端,分别来看两端各种产生粘包的原因: | |
| 发送端粘包:发送端需要等缓冲区满才发送出去,造成粘包; | |
| 接收方粘包:接收方不及时接收缓冲区的包,造成多个包接收。 | |
| OSI 的七层模型都有哪些? | |
| 物理层:利用传输介质为数据链路层提供物理连接,实现比特流的透明传输。 | |
| 数据链路层:负责建立和管理节点间的链路。 | |
| 网络层:通过路由选择算法,为报文或分组通过通信子网选择最适当的路径。 | |
| 传输层:向用户提供可靠的端到端的差错和流量控制,保证报文的正确传输。 | |
| 会话层:向两个实体的表示层提供建立和使用连接的方法。 | |
| 表示层:处理用户信息的表示问题,如编码、数据格式转换和加密解密等。 | |
| 应用层:直接向用户提供服务,完成用户希望在网络上完成的各种工作。 | |
| get 和 post 请求有哪些区别? | |
| get 请求会被浏览器主动缓存,而 post 不会。 | |
| get 传递参数有大小限制,而 post 没有。 | |
| post 参数传输更安全,get 的参数会明文限制在 url 上,post 不会。 | |
| 如何实现跨域? | |
| 实现跨域有以下几种方案: | |
| 服务器端运行跨域 设置 CORS 等于 *; | |
| 在单个接口使用注解 @CrossOrigin 运行跨域; | |
| 使用 jsonp 跨域; | |
| 87. 说一下 JSONP 实现原理? | |
| jsonp:JSON with Padding,它是利用script标签的 src 连接可以访问不同源的特性,加载远程返回的“JS 函数”来执行的。 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| course: 课程 scores: 分数 student: 学生 teacher: 老师 | |
| -- ======================================================================== | |
| drop TABLE if EXISTS student; | |
| CREATE TABLE student ( | |
| id INT(10) PRIMARY key, | |
| name VARCHAR (10), | |
| age INT (10) NOT NULL, | |
| gander varchar(2) | |
| ); | |
| drop TABLE if EXISTS course; | |
| CREATE TABLE course ( | |
| id INT (10) PRIMARY key, | |
| name VARCHAR (10) , | |
| t_id INT (10) | |
| ) ; | |
| drop TABLE if EXISTS teacher; | |
| CREATE TABLE teacher( | |
| id INT (10) PRIMARY key, | |
| name VARCHAR (10) | |
| ); | |
| drop TABLE if EXISTS scores; | |
| CREATE TABLE scores( | |
| s_id INT , | |
| score INT (10), | |
| c_id INT (10) , | |
| PRIMARY key(s_id,c_id) | |
| ); | |
| insert into student (id,name,age,gander)VALUES(1,'白杰',19,'男'),(2,'连宇栋',19,'男'),(3,'邸志伟',24,'男'),(4,'李兴',11,'男'), | |
| (5,'张琪',18,'男'),(6,'武三水',18,'女'),(7,'张志伟',16,'男'),(8,'康永亮',23,'男'),(9,'杨涛瑞',22,'女'),(10,'王杰',21,'男'); | |
| insert into course (id,name,t_id)VALUES(1,'数学',1),(2,'语文',2),(3,'c++',3),(4,'java',4),(5,'php',null); | |
| insert into teacher (id,name)VALUES(1,'张楠'),(2,'老孙'),(3,'薇薇姐'),(4,'磊磊哥'),(5,'大微姐'); | |
| insert into scores (s_id,score,c_id)VALUES(1,80,1),(1,56,2),(1,95,3),(1,30,4),(1,76,5),(2,35,1),(2,86,2),(2,45,3),(2,94,4), | |
| (2,79,5),(3,65,2),(3,85,3),(3,37,4),(3,79,5),(4,66,1),(4,39,2),(4,85,3),(5,66,2),(5,89,3),(5,74,4),(6,80,1),(6,56,2),(6,95,3),(6,30,4), | |
| (6,76,5),(7,35,1),(7,86,2),(7,45,3),(7,94,4),(7,79,5),(8,65,2),(8,85,3),(8,37,4),(8,79,5),(9,66,1),(9,39,2),(9,85,3),(9,79,5),(10,66,2),(10,89,3),(10,74,4),(10,79,5); | |
| -- ======================================================================== | |
| 查询‘01’号学生的姓名和各科成绩。 | |
| select stu.name '学生姓名',c.name '课程名称',s.score '成绩' | |
| from course c inner join scores s on c.id=s.c_id | |
| inner join student stu on stu.id = s.s_id | |
| where stu.id=1; | |
| 2、查询各个学科的平均成绩,最高成绩。 | |
| select c.name '课程',avg(s.score) '平均成绩', max(s.score) '最高值' | |
| from course c inner join scores s | |
| on c.id = s.c_id | |
| group by c.name | |
| 3、查询每个同学的最高成绩及科目名称。 | |
| -- 首先使用子查询把最高的成绩算出来然后分组删除多余数据。 | |
| -- 然后拿scores成绩表的成绩最高成绩的数据 | |
| (使用内连接算出的最高分和成绩表的分数做比较 如果相等就拿出来,因为需要成绩表中的s_id和c_id来关联数据, | |
| 查出来的数据会出问题 因为只是比较的分数所以会产生笛卡尔积,所以还需要拿内连接的s_id和s_id关联) | |
| -- 拿到scores分数表的结果后 用这个结果中的s_id c_id和student course表关联绑定 | |
| select stu.id 'ID', stu.name '姓名', s.score '成绩', c.name '课程' | |
| from (select s_id,max(score) max from scores group by s_id) test | |
| inner join scores s on s.score = test.max and test.s_id = s.s_id | |
| inner join student stu on stu.id = s.s_id | |
| inner join course c on c.id = s.c_id | |
| order by stu.id | |
| select stu.id 'ID', stu.name '姓名', s.score '成绩', c.name '课程' | |
| from (select s_id,max(score) max from scores group by s_id) test,scores s,student stu, course c | |
| where (s.score = test.max and test.s_id = s.s_id) and stu.id = s.s_id and c.id = s.c_id | |
| order by stu.id | |
| 4、查询所有姓张的同学的各科成绩。 | |
| select stu.name '姓名',s.score '成绩',c.name '课程名称' | |
| from student stu, scores s, course c | |
| where stu.id = s.s_id and s.c_id = c.id and stu.name like '张%' | |
| order by stu.name | |
| 5、查询每个课程最高分的同学信息。 | |
| -- 暂时不会 | |
| select s.s_id, s.c_id, s.score | |
| from (select c_id,max(score) scoreMax from scores group by c_id) sm | |
| inner join scores s on sm.scoreMax = s.score and sm.c_id = s.c_id | |
| 6、查询名字中含有“张”和‘李’字的学生信息和各科成绩。 | |
| select stu.name '姓名',stu.age '年龄',stu.gander '性别',s.score '分数',c.name '课程' | |
| from student stu | |
| inner join scores s on s.s_id = stu.id | |
| inner join course c on s.c_id = c.id | |
| where stu.name like '张%' or stu.name like '李%' | |
| order by stu.id | |
| 7、查询平均成绩及格的同学的信息。 | |
| -- 使用子查询查询出平均成绩及格的同学,再连接学生表查询学生的信息 | |
| select stu.id, stu.name, stu.age, stu.gander,test.scoreAvg '平均成绩及格了的同学' | |
| from ( | |
| select s_id,avg(score) scoreAvg | |
| from scores | |
| group by s_id | |
| having avg(score) > 60 | |
| ) test | |
| inner join student stu on test.s_id = stu.id | |
| 8、将学生按照总分数进行排名。 | |
| select stu.name,test.scoreSum '总成绩' | |
| from ( | |
| select *,sum(score) scoreSum | |
| from scores | |
| group by s_id | |
| ) test | |
| inner join student stu on stu.id = test.s_id | |
| group by test.scoreSum | |
| 9、查询数学成绩的最高分、最低分、平均分。 | |
| select c.name,max(s.score) '最高分',min(s.score) '最低分',avg(s.score) '平均分' | |
| from scores s | |
| inner join course c on s.c_id = c.id | |
| where c.name = '数学' | |
| 10、将各科目按照平均分排序。 | |
| select c.name,avg(s.score) '平均分' | |
| from scores s | |
| inner join course c on c.id = s.c_id | |
| group by s.c_id | |
| order by '平均分' | |
| 11、查询老师的信息和他所带科目的平均分。 | |
| select t.name '教师',c.name '课程',avg(s.score) '老师所教的课程的平均分' | |
| from teacher t | |
| inner join course c on c.t_id = t.id | |
| inner join scores s on c.t_id = s.c_id | |
| group by t.name | |
| 12、查询被“张楠”和‘‘老孙’叫的课程的最高分和平均分。 | |
| select t.name '老师',c.name '课程',max(s.score) '最高分',avg(s.score) '平均分' | |
| from teacher t | |
| inner join course c on t.id = c.t_id | |
| inner join scores s on s.c_id = c.id | |
| where t.name = '张楠' or t.name = '老孙' | |
| group by s.c_id | |
| 13、查询查询每个同学的最好成绩的科目名称。 | |
| -- 先使用子查询查询每个同学的最高得分,使用这个结果集的最高得分来匹配scores成绩表 获取成绩表中学生和科目的外键 | |
| select test.name '姓名',c.name '课程名',test.scoreMax '最高得分' | |
| from ( | |
| select s.s_id,stu.name,max(s.score) scoreMax | |
| from scores s | |
| inner join student stu on s.s_id = stu.id | |
| group by stu.name | |
| ) test | |
| inner join scores s on test.scoreMax = s.score and test.s_id = s.s_id | |
| inner join course c on s.c_id = c.id | |
| order by test.scoreMax | |
| 14、查询所有学生的课程及分数。 | |
| select stu.name '学生',c.name '课程',s.score '成绩' | |
| from student stu | |
| inner join scores s on s.s_id = stu.id | |
| inner join course c on s.c_id = c.id | |
| order by stu.id | |
| 15、查询课程编号为01且课程成绩在80分以上的学生的学号和姓名 | |
| select stu.id '学号',stu.name '姓名',s.score '成绩(大于80分的)' | |
| from course c | |
| inner join scores s on c.id = s.c_id | |
| inner join student stu on stu.id = s.s_id | |
| where c.id = 1 and s.score > 80 | |
| 16、查询平均成绩大于等于70的所有学生的学号、姓名和平均成绩。 ** | |
| select stu.id '学号',stu.name '姓名',test.scoreAvg '平均成绩' | |
| from ( | |
| select *,avg(s.score) scoreAvg | |
| from scores s | |
| group by s.s_id | |
| having avg(s.score) > 70 | |
| ) test | |
| inner join student stu on test.s_id = stu.id | |
| order by stu.id | |
| 17、查询有不及格课程的同学信息。 ** | |
| select stu.name '姓名',stu.age '年龄',stu.gander '性别',c.name '不及格的课程',test.score '分数' | |
| from ( | |
| select * from scores s | |
| where s.score < 60 | |
| ) test | |
| inner join student stu on test.s_id = stu.id | |
| inner join course c on test.c_id = c.id | |
| order by stu.id | |
| 18、求每门课程的学生人数。 | |
| select c.name '课程', test.numberCount '人数' | |
| from ( | |
| select *, count(s.c_id) numberCount | |
| from scores s | |
| group by s.c_id | |
| ) test | |
| inner join course c on test.c_id = c.id | |
| 19、查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列 。 | |
| select c.id '课程编号', c.name '课程名', test.scoreAvg '平均成绩' | |
| from ( | |
| select s.c_id,avg(s.score) scoreAvg | |
| from scores s | |
| group by s.c_id | |
| ) test | |
| inner join course c on test.c_id = c.id | |
| order by test.scoreAvg,c.id | |
| 20、查询平均成绩大于等于70分的同学的学生编号和学生姓名和平均成绩。 | |
| select stu.id '学生编号',stu.name '学生姓名',test.scoresAvg '平均成绩' | |
| from ( | |
| select s.s_id,avg(s.score) scoresAvg | |
| from scores s | |
| group by s.s_id | |
| having avg(s.score) >= 70 | |
| ) test, student stu | |
| where test.s_id = stu.id | |
| 21、查询有一门课程成绩在90分以上的学生信息。 | |
| select stu.name '姓名', c.name '课程名称', test.score '成绩' | |
| from ( | |
| select * from scores where score > 90 | |
| ) test, student stu, course c | |
| where test.s_id = stu.id and test.c_id = c.id | |
| 22、查询出只有三门课程的全部学生的学号和姓名。 | |
| select stu.id,stu.name '姓名', count(s.c_id) '课程' | |
| from scores s,student stu | |
| where s.s_id = stu.id | |
| group by s.s_id | |
| having count(s.c_id) = 3 | |
| 23、查询有不及格课程的课程信息。 | |
| select stu.name '姓名', c.name '课程名', s.score '成绩(不及格的)' | |
| from scores s, course c, student stu | |
| where s.score < 60 and s.c_id = c.id and stu.id = s.s_id | |
| order by stu.id | |
| 24、检索至少选修四门课程的学生学号。 | |
| select stu.id '学号',stu.name '姓名', count(s.c_id) '选修课程数' | |
| from scores s, student stu | |
| where s.s_id = stu.id | |
| group by s.s_id | |
| having count(s.c_id) >= 4 | |
| 25、查询没有学全所有课程的同学的信息。 | |
| select test.s_id '学号', stu.name '姓名', test.courseCount '实修课程数' | |
| from ( | |
| select s_id,count(s_id) courseCount | |
| from scores | |
| group by s_id | |
| ) test, (select count(id) countId from course) test2, student stu | |
| where stu.id = test.s_id | |
| and test.courseCount != test2.countId | |
| 26、查询学全所有课程的同学的信息。 | |
| 把25题最后的and条件修改一下即可 | |
| 27、 查询各学生都选了多少门课。 | |
| select stu.id, stu.name '姓名', test.courseCount '课程数' | |
| from ( | |
| select *,count(s.c_id) courseCount | |
| from scores s | |
| group by s.s_id | |
| ) test, student stu | |
| where test.s_id = stu.id | |
| 28、查询课程名称为”java”,且分数低于60的学生姓名和分数 | |
| select stu.id, stu.name '姓名', s.score '成绩', c.name '课程名' | |
| from course c,scores s,student stu | |
| where s.c_id = c.id and s.s_id = stu.id and c.name = 'java' and s.score < 60 | |
| 29、查询学过”张楠”老师授课的同学的信息 | |
| select s.s_id '学号', stu.name '姓名', c.name '科目', t.name '授课老师' | |
| from scores s, course c, student stu, teacher t | |
| where s.c_id = c.t_id and s.c_id = 1 and s.s_id = stu.id and c.t_id = t.id | |
| 30、查询没学过”张楠”老师授课的同学的信息 | |
| 上面的where条件改一下即可 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment