MySQL规范
MySQL规范数据库命名规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用 MySQL 保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名识意,并且最好不要超过 32 个字符 临时库表必须以 tmp 为前缀并以日期为后缀,备份表必须以 bak 为前缀并以日期 (时间戳) 为后缀 所有存储相同数据的列名和列类型必须一致(一般作为关联列,如果查询时关联列类型不一致会自动进行数据类型隐式转换,会造成列上的索引失效,导致查询效率降低) 数据库基本设计规范所有表必须使用 InnoDB 存储引擎没有特殊要求(即 InnoDB 无法满足的功能如:列存储,存储空间数据等)的情况下,所有表必须使用 InnoDB 存储引擎 数据库和表的字符集统一使用 UTF8兼容性更好,统一字符集可以避免由于字符集转换产生的乱码,不同的字符集进行比较前需要进行转换会造成索引失效,如果数据库中有存储 emoji 表情的需要,字符集需要采用 utf8mb4 字符集。 所有表和字段都需要添加注释使用 comment 从句添加表和列的备注,从一开始就进 ...
MySQL锁
MySQL锁表级锁和行级锁MyISAM (MySQL5.5版本以前默认的存储引擎) 仅仅支持表级锁,一锁就锁整张表,这在并发写的情况下性非常差。 InnoDB (MySQL5.5版本后默认的存储引擎) 不光支持表级锁,还支持行级锁,默认为行级锁。行级锁的粒度更小,仅对相关的记录上锁即可(对一行或者多行记录加锁),所以对于并发写入操作来说, InnoDB 的性能更高。 表级锁和行级锁对比: 表级锁: MySQL 中锁定粒度最大的一种锁(全局锁除外),是针对非索引字段加的锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。不过,触发锁冲突的概率最高,高并发下效率极低。表级锁和存储引擎无关,MyISAM 和 InnoDB 引擎都支持表级锁。 行级锁: MySQL 中锁的粒度最小的一种锁,是 针对索引字段加的锁 ,只针对当前操作的行记录进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。行级锁和存储引擎有关,是在存储引擎层面实现的。 InnoDB 的行锁是针对索引字段加的锁,表级锁是针对非索引字段加的 ...
MySQL事务
MySQL事务什么是事务事务是逻辑上的一组操作,要么都执行,要么都不执行。 事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账 1000 元,这个转账会涉及到两个关键操作,这两个操作必须都成功或者都失败。 将小明的余额减少 1000 元 将小红的余额增加 1000 元 事务会把这两个操作看成逻辑上的一个整体,这个整体包含的操作要么都成功,要么都要失败。这样就不会出现小明余额减少而小红的余额却并没有增加的情况。 数据库事务大多数情况下,我们在谈论事务的时候,如果没有特指分布式事务,往往指的就是数据库事务。 数据库事务在我们日常开发中接触的最多了。如果你的项目属于单体架构的话,你接触到的往往就是数据库事务了。那数据库事务有什么作用呢? 简单来说,数据库事务可以保证多个对数据库的操作(也就是 SQL 语句)构成一个逻辑上的整体。构成这个逻辑上的整体的这些数据库操作遵循:要么全部执行成功,要么全部不执行 。 事务的 ACID 特性ACID,是指关系型数据库事务正确执行的四个基本要素的缩写。包含: 原子性(Atomicity) 一致性(Consistency) 隔离性(Iso ...
类加载机制
类加载机制现在,我们已经了解了字节码文件的结构,以及JVM如何对内存进行管理,现在只剩下最后一个谜团等待解开了,也就是我们的类字节码文件到底是如何加载到内存中的,加载之后又会做什么事情。 类加载过程首先,要加载一个类,一定是出于某种目的的,比如我们要运行我们的Java程序,那么就必须要加载主类才能运行主类中的主方法,又或是我们需要加载数据库驱动,那么可以通过反射来将对应的数据库驱动类进行加载。 所以,一般在这些情况下,如果类没有被加载,那么会被自动加载: 使用new关键字创建对象时 使用某个类的静态成员(包括方法和字段)的时候(当然,final类型的静态字段有可能在编译的时候被放到了当前类的常量池中,这种情况下是不会触发自动加载的) 使用反射对类信息进行获取的时候(之前的数据库驱动就是这样的) 加载一个类的子类时 加载接口的实现类,且接口带有default的方法默认实现时 比如这种情况,那么需要用到另一个类中的成员字段,所以就必须将另一个类加载之后才能访问: 12345678910111213public class Main { public static voi ...
类文件结构
类文件结构在我们学习C语言的时候,我们的编程过程会经历如下几个阶段:写代码、保存、编译、运行。实际上,最关键的一步是编译,因为只有经历了编译之后,我们所编写的代码才能够翻译为机器可以直接运行的二进制代码,并且在不同的操作系统下,我们的代码都需要进行一次编译之后才能运行。 如果全世界所有的计算机指令集只有x86一种,操作系统只有Windows一种,那也许就不会有Java语言的出现。 随着时代的发展,人们迫切希望能够在不同的操作系统、不同的计算机架构中运行同一套编译之后的代码。本地代码不应该是我们编程的唯一选择,所以,越来越多的语言选择了与操作系统和机器指令集无关的中立格式作为编译后的存储格式。 “一次编写,到处运行”,Java最引以为傲的口号,标志着平台不再是限制编程语言的阻碍。 实际上,Java正式利用了这样的解决方案,将源代码编译为平台无关的中间格式,并通过对应的Java虚拟机读取和运行这些中间格式的编译文件,这样,我们只需要考虑不同平台的虚拟机如何编写,而Java语言本身很轻松地实现了跨平台。 现在,越来越多的开发语言都支持将源代码编译为.class字节码文件格式,以便能够直接 ...
JVM垃圾回收机制
垃圾回收机制我们前面提到,Java会自动管理和释放内存,它不像C/C++那样要求我们手动管理内存,JVM提供了一套全自动的内存管理机制,当一个Java对象不再用到时,JVM会自动将其进行回收并释放内存,那么对象所占内存在什么时候被回收,如何判定对象可以被回收,以及如何去进行回收工作也是JVM需要关注的问题。 对象存活判定算法首先我们来套讨论第一个问题,也就是:对象在什么情况下可以被判定为不再使用已经可以回收了?这里就需要提到以下几种垃圾回收算法了。 引用计数法我们知道,如果我们要经常操作一个对象,那么首先一定会创建一个引用变量: 1234//str就是一个引用类型的变量,它持有对后面字符串对象的引用,可以代表后面这个字符串对象本身String str = "lbwnb";//str.xxxxx... 实际上,我们会发现,只要一个对象还有使用价值,我们就会通过它的引用变量来进行操作,那么可否这样判断一个对象是否还需要被使用: 每个对象都包含一个 引用计数器,用于存放引用计数(其实就是存放被引用的次数) 每当有一个地方引用此对象时,引用计数+1 当引用失效( 比如离 ...