堆组织表、索引组织表、索引聚簇表

堆组织表、索引组织表、索引聚簇表 版权声明: 本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/pianzif/article/details/32106971 堆组织表就不说了,其索引中记录了记录所在位置的rowid,查找的时候先找索引,然后再根据索引rowid找到块中的行数据 索引组织表,其行数据以索引形式存放,因此找到索引,就等于找到了行数据。 堆组织表的数据是散放的,索引和表的数据是分离的 索引组织表的索引和数据是在一起的 堆组织表的存储速度因为不用考虑排序, 所以存储速度会比较快. 但是要查找符合某个条件的记录, 就必须得读取全部的记录以便筛选. 而这个时候为了加快查询速度, 索引就出现了, 索引是针对少量特定字段的值拿出来进行排序存储, 并记录在表中的位置, 而因为索引是有序的, 所以就会很容易通过索引查询到具体的记录位置, 然后再根据记录位置直接从表中读取该记录. 同时因为索引的字段较少, 所以索引通常会比其基表小得多. 从上面通过索引访问表记录的方式可以看出, 当要访问的数据量较大时, 通过每一条记录的位置去访问原始记录, 每一条符合条件的记录都需要经过索引访问后再访问基表这样一个复杂的过程, 这会花费很多时间, 同样, 如果不经过索引而直接查询表, 也可能因为表字段太多, 记录较大的情况下把全部的数据读取进来, 这也会花费很多时间. 那怎么办呢? 这个时候就会想到, 如果表中数据本身就是有序的, 这样查询表的时候就可以快速的找到符合条件的记录位置, 而很容易判断符合条件记录的位置, 这样只需要读取一小部分数据出来就可以了, 不需要全表记录都读取出来进行判断. 索引表就这样产生了.当然索引表中插入,更新资料的时候可能会因为需要排序而将数据重组, 这时候数据插入或更新速度会比堆组织表慢一些. 如果堆组织表上有索引, 那么对堆组织表的插入也会因为要修改索引而变慢 我们可以看到堆组织表+索引的方式 与 索引表 都能够实现数据的快速查找, 那为什么不全部采用索引表呢, 这样不是很简单吗? 我能想到的是前者我们可以针对不同的查找条件建立多个索引, 而后者却不行, 后者只能对某一组查询条件有效 堆组织表 (heap organized table) Oracle中有很多类型的表,像堆组织表、索引组织表、索引聚簇表等等。首先,我将从最基本、最常用的堆组织表 (heap organized table) 介绍。 通常我们默认建的表就是堆组织表。语法 (详细语法请参见Oracle官方文档) 如下: Create table test( ...

2019-10-29 · 9 min · 1767 words · -

MySQL 默认排序

MySQL 默认排序 不加order by 的情况 下, 顺序 不能保证, 不同存储引擎, 有过增删改操作 都有可能 影响默认顺序, 默认排序只依赖于内部实现, 不同版本的MySQL也有可能 不同. 所以不能依赖默认排序. https://my.oschina.net/alarm1673/blog/1814508 https://stackoverflow.com/questions/8746519/sql-what-is-the-default-order-by-of-queries

2019-10-29 · 1 min · 18 words · -

jdbi

jdbi JDBI jdbi jdbi是我比较喜欢的一个数据库中间件,它是非 ORM 的,特别适合于数据库固定不变的场景,即不会对应多种数据库,以后也不会更换数据库的场景。 如果不是这种场景,那么使用jdbc或者最好选择hibernate等对多种数据库兼容较好的中间件。 基于上述使用场景,jdbi的优点有: 和 jdbci 比较接近,使用和掌握非常简单。 与时俱进,例如说现在最新的 jdbi3,增加了流式编程函数式等编程风格。 源代码的实现思路非常清晰,有一种美感。使用jdbi封装出的数据库代码也非常清晰。 jdbi 的两种风格 Fluent Api handle.createUpdate(“INSERT INTO user(id, name) VALUES (:id, :name)”) .bind(“id”, 2) .bind(“name”, “Clarice”) .execute(); 这里就是java8的流式风格,用连贯式表达式将一个sql实现串在一起 Declarative Api // Define your own declarative interface public interface UserDao { @SqlUpdate("CREATE TABLE user (id INTEGER PRIMARY KEY, name VARCHAR)") void createTable(); @SqlUpdate("INSERT INTO user(id, name) VALUES (?, ?)") void insertPositional(int id, String name); @SqlUpdate("INSERT INTO user(id, name) VALUES (:id, :name)") void insertNamed(@Bind("id") int id, @Bind("name") String name); @SqlUpdate("INSERT INTO user(id, name) VALUES (:id, :name)") void insertBean(@BindBean User user); @SqlQuery("SELECT * FROM user ORDER BY name") @RegisterBeanMapper(User.class) List<User> listUsers(); } 声明式的主要是使用注解来实现,在实际的面向对象风格的代码中,我个人觉得声明式的比较简洁,容易阅读和维护。所以下面都按照Declarative Api的方式。 ...

2019-10-29 · 1 min · 105 words · -

linux typeset

linux typeset https://blog.csdn.net/blackmanren/article/details/9281201 typeset 用于设置变量属性, 如大小写,宽度,左右对齐等都可以用typeset来控制, 当用typeset改变一个变量的属性时,这种改变是永久的,下面以ksh为例,演示typeset的几种典型用法 typeset的-u选项可以将一个变量的字符变成大写 /home/lee#typeset -u var=abc /home/lee#echo $var ABC 3:typeset的-l选项将一个变量的字符变成小写 /home/lee#typeset -l var=ABC /home/lee#echo $var abc typeset的-L选项把变量变成一个左对齐的4个字符串,有些像字符串截取 /home/lee#typeset -L4 var=abcdefg /home/lee#echo $var abcd typeset的-R选项把变量变成一个右对齐的4个字符串 /home/lee#typeset -R4 var=abcdefg /home/lee#echo $var defg typeset的-Z选项把串变成一个空填充,占15个字符位的串,冒号用来保护空白符 typeset -Z15 var=“abc ddd” /home/lee#echo “$var” ^^^^^^^^abc ddd #^为空白 /home/lee#typeset -LZ15 var=“abc 123” /home/lee#echo “$var$var” abc 123 abc 123 7:变量n是一个被设置成一个整数的变量,typeset命令将整数n前面补齐0,共15个字符位 /home/lee#typeset -i n=24 /home/lee#typeset -Z15 n /home/lee#echo $n 000000000000024 8:变量answer被给定一个值-Yes并变成一个小写,左对齐,一个字符的串 /home/lee#typeset -lL1 answer=Yes /home/lee#echo $answer ...

2019-10-28 · 1 min · 113 words · -

ConcurrentLinkedDeque

ConcurrentLinkedDeque 非阻塞线程安全列表——ConcurrentLinkedDeque应用举例 在java中,最常用的数据结构可能是列表。有数目不详的元素列表,你可以添加、阅读、或删除任何位置的元素。此外,并发列表允许不同的线程列表中添加或删除元素时不产生任何数据不一致。非阻塞列表提供如下操作,如果操作不能立即完成,列出抛出异常或者返回一个null值。Java 7中引入了ConcurrentLinkedDeque类,它实现了一个非阻塞并发列表,在本教程中,我们将学习使用这个类。 在这个例子中,我们将实现一个示例使用以下两个不同的任务: 一个将大量数据添加到一个列表中 一个大量地从同样的列表中删除数据 让我们为每个任务创建的线程: package com.howtodoinjava.demo.multithreading.concurrentLinkedDequeExample; import java.util.concurrent.ConcurrentLinkedDeque; public class AddTask implements Runnable { private ConcurrentLinkedDeque<String> list; public AddTask(ConcurrentLinkedDeque<String> list) { this.list = list; } @Override public void run() { String name = Thread.currentThread().getName(); for (int i = 0; i < 10000; i++) { list.add(name + ": Element " + i); } } } 和: packagecom.howtodoinjava.demo.multithreading.concurrentLinkedDequeExample; importjava.util.concurrent.ConcurrentLinkedDeque; publicclass RemoveTask implementsRunnable { privateConcurrentLinkedDeque<String> list; publicRemoveTask(ConcurrentLinkedDeque<String> list) { this.list = list; } @Override publicvoid run() { for(inti = 0; i < 5000; i++) { list.pollFirst(); list.pollLast(); } } } ...

2019-10-23 · 2 min · 288 words · -

ansible 变量

ansible 变量 ram_size: “{{ (ansible_memtotal_mb * 0.8)|int }}” --- - hosts: 'all' vars: var0: 'value0'

2019-10-21 · 1 min · 15 words · -

application start script

application start script #! /usr/bin/env bash APP_HOME=/data/server/app0 APP_NAME=app0 PID_FILE=/var/run/app0.pid startApp(){ cd ${APP_HOME} nohup java -jar ${APP_NAME}.jar > log 2>&1 & echo $! > ${PID_FILE}; } stopApp(){ kill `cat ${PID_FILE}` } case $1 in start) startApp ;; stop) stopApp ;; restart) stopApp startApp ;; *) echo "usage: wrapper {start|stop|restart}" ;; esac exit 0

2019-10-21 · 1 min · 52 words · -

Java Mission Control, jmc

Java Mission Control, jmc https://github.com/JDKMissionControl/jmc https://www.oracle.com/java/technologies/javase-overview.html download https://ci.adoptopenjdk.net/view/JMC/job/jmc-latest/

2019-10-14 · 1 min · 8 words · -

redis thread

redis thread https://www.cnblogs.com/traditional/p/13273089.html 在 Redis4.0 之前,Redis 是单线程运行的 但是单线程并不代表效率就低 因为底层采用了基于 epoll 的 IO 多路复用

2019-10-11 · 1 min · 13 words · -

架构, 架构师, architecture

架构, 架构师, architecture 架构师: architect 架构: architecture 软件架构 软件架构 (software architecture) 就是软件的基本结构。 分层架构 分层架构 (layered architecture) 是最常见的软件架构,也是事实上的标准架构。如果你不知道要用什么架构,那就用它。 这种架构将软件分成若干个水平层,每一层都有清晰的角色和分工,不需要知道其他层的细节。层与层之间通过接口通信。 虽然没有明确约定,软件一定要分成多少层,但是四层的结构最常见。 表现层 (presentation) : 用户界面,负责视觉和用户互动 业务层 (business) : 实现业务逻辑 持久层 (persistence) : 提供数据,SQL 语句就放在这一层 数据库 (database) : 保存数据 有的软件在逻辑层和持久层之间,加了一个服务层 (service) ,提供不同业务逻辑需要的一些通用接口。 用户的请求将依次通过这四层的处理,不能跳过其中任何一层。 事件驱动架构 事件 (event) 是状态发生变化时,软件发出的通知。 事件驱动架构 (event-driven architecture) 就是通过事件进行通信的软件架构。它分成四个部分。 事件队列 (event queue) : 接收事件的入口 分发器 (event mediator) : 将不同的事件分发到不同的业务逻辑单元 事件通道 (event channel) : 分发器与处理器之间的联系渠道 事件处理器 (event processor) : 实现业务逻辑,处理完成后会发出事件,触发下一步操作 微核架构 微核架构 (microkernel architecture) 又称为"插件架构" (plug-in architecture) ,指的是软件的内核相对较小,主要功能和业务逻辑都通过插件实现。 ...

2019-10-11 · 2 min · 326 words · -

获取网络时间

获取网络时间 public class GetNetworkTime { public static void main(String[] args) { String webUrl2 = "http://www.baidu.com";//百度 String webUrl3 = "http://www.taobao.com";//淘宝 String webUrl4 = "http://www.ntsc.ac.cn";//中国科学院国家授时中心 String webUrl5 = "http://www.360.cn";//360 System.out.println(getWebsiteDatetime(webUrl2) + " [百度]"); System.out.println(getWebsiteDatetime(webUrl3) + " [淘宝]"); System.out.println(getWebsiteDatetime(webUrl4) + " [中国科学院国家授时中心]"); System.out.println(getWebsiteDatetime(webUrl5) + " [360安全卫士]"); } /** * 获取指定网站的日期时间 * * @param webUrl * @return * @author SHANHY * @date 2015年11月27日 */ private static String getWebsiteDatetime(String webUrl){ try { URL url = new URL(webUrl);// 取得资源对象 URLConnection uc = url.openConnection();// 生成连接对象 uc.connect();// 发出连接 long ld = uc.getDate();// 读取网站日期时间 Date date = new Date(ld);// 转换为标准时间对象 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);// 输出北京时间 return sdf.format(date); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } } https://blog.csdn.net/catoop/article/details/50076879

2019-10-09 · 1 min · 119 words · -

netty Reactor 模式

netty Reactor模式 Reactor模式的角色构成(Reactor模式一共有5中角色构成): Handle (句柄或描述符,在Windows下称为句柄,在Linux下称为描述符):本质上表示一种资源(比如说文件描述符,或是针对网络编程中的socket描述符),是由操作系统提供的;该资源用于表示一个个的事件,事件既可以来自于外部,也可以来自于内部;外部事件比如说客户端的连接请求,客户端发送过来的数据等;内部事件比如说操作系统产生的定时事件等。它本质上就是一个文件描述符,Handle是事件产生的发源地。 Synchronous Event Demultiplexer (同步事件分离器):它本身是一个系统调用,用于等待事件的发生(事件可能是一个,也可能是多个)。调用方在调用它的时候会被阻塞,一直阻塞到同步事件分离器上有事件产生为止。对于Linux来说,同步事件分离器指的就是常用的I/O多路复用机制,比如说select、poll、epoll等。在Java NIO领域中,同步事件分离器对应的组件就是Selector;对应的阻塞方法就是select方法。 Event Handler (事件处理器):本身由多个回调方法构成,这些回调方法构成了与应用相关的对于某个事件的反馈机制。在Java NIO领域中并没有提供事件处理器机制让我们调用或去进行回调,是由我们自己编写代码完成的。Netty相比于Java NIO来说,在事件处理器这个角色上进行了一个升级,它为我们开发者提供了大量的回调方法,供我们在特定事件产生时实现相应的回调方法进行业务逻辑的处理,即,ChannelHandler。ChannelHandler中的方法对应的都是一个个事件的回调。 Concrete Event Handler (具体事件处理器):是事件处理器的实现。它本身实现了事件处理器所提供的各种回调方法,从而实现了特定于业务的逻辑。它本质上就是我们所编写的一个个的处理器实现。 Initiation Dispatcher (初始分发器):实际上就是Reactor角色。它本身定义了一些规范,这些规范用于控制事件的调度方式,同时又提供了应用进行事件处理器的注册、删除等设施。它本身是整个事件处理器的核心所在,Initiation Dispatcher会通过 Synchronous Event Demultiplexer 来等待事件的发生。一旦事件发生,Initiation Dispatcher 首先会分离出每一个事件,然后调用事件处理器,最后调用相关的回调方法来处理这些事件。Netty中ChannelHandler 里的一个个回调方法都是由 bossGroup 或 workGroup 中的某个EventLoop来调用的。 Reactor模式流程 ① 初始化Initiation Dispatcher,然后将若干个Concrete Event Handler注册到Initiation Dispatcher中。当应用向Initiation Dispatcher注册Concrete Event Handler时,会在注册的同时指定感兴趣的事件,即,应用会标识出该事件处理器希望Initiation Dispatcher在某些事件发生时向其发出通知,事件通过Handle来标识,而Concrete Event Handler又持有该Handle。这样,事件 ————> Handle ————> Concrete Event Handler 就关联起来了。 ② Initiation Dispatcher 会要求每个事件处理器向其传递内部的Handle。该Handle向操作系统标识了事件处理器。 ③ 当所有的Concrete Event Handler都注册完毕后,应用会调用handle_events方法来启动Initiation Dispatcher的事件循环。这是,Initiation Dispatcher会将每个注册的Concrete Event Handler的Handle合并起来,并使用Synchronous Event Demultiplexer(同步事件分离器)同步阻塞的等待事件的发生。比如说,TCP协议层会使用select同步事件分离器操作来等待客户端发送的数据到达连接的socket handler上。 比如,在Java中通过Selector的select()方法来实现这个同步阻塞等待事件发生的操作。在Linux操作系统下,select()的实现中 a)会将已经注册到Initiation Dispatcher的事件调用epollCtl(epfd, opcode, fd, events)注册到linux系统中,这里fd表示Handle,events表示我们所感兴趣的Handle的事件;b)通过调用epollWait方法同步阻塞的等待已经注册的事件的发生。不同事件源上的事件可能同时发生,一旦有事件被触发了,epollWait方法就会返回;c)最后通过发生的事件找到相关联的SelectorKeyImpl对象,并设置其发生的事件为就绪状态,然后将SelectorKeyImpl放入selectedSet中。这样一来我们就可以通过Selector.selectedKeys()方法得到事件就绪的SelectorKeyImpl集合了。 ④ 当与某个事件源对应的Handle变为ready状态时(比如说,TCP socket变为等待读状态时),Synchronous Event Demultiplexer就会通知Initiation Dispatcher。 ⑤ Initiation Dispatcher会触发事件处理器的回调方法,从而响应这个处于ready状态的Handle。当事件发生时,Initiation Dispatcher会将被事件源激活的Handle作为『key』来寻找并分发恰当的事件处理器回调方法。 ⑥ Initiation Dispatcher会回调事件处理器的handle_event(type)回调方法来执行特定于应用的功能(开发者自己所编写的功能),从而相应这个事件。所发生的事件类型可以作为该方法参数并被该方法内部使用来执行额外的特定于服务的分离与分发。 ...

2019-10-03 · 1 min · 186 words · -

golang MP4文件服务器

golang MP4 文件服务器 https://studygolang.com/articles/11204 package main import ( "github.com/gorilla/handlers" "log" "net/http" "os" "time" ) func ServeHTTP(w http.ResponseWriter, r *http.Request) { video, err := os.Open("/tmp/foo.mp4") if err != nil { log.Fatal(err) } defer video.Close() http.ServeContent(w, r, "foo.mp4", time.Now(), video) } func main() { http.HandleFunc("/", ServeHTTP) _ = http.ListenAndServe(":8089", handlers.LoggingHandler(os.Stdout, http.DefaultServeMux)) }

2019-09-27 · 1 min · 50 words · -

termite

termite vim ~/.config/termite/config font = Source Code Pro 10 Termite是一种基于VTE的最小终端仿真器,它是一个模态应用程序,类似于Vim,具有插入模式和选择模式,其中键绑定具有不同的功能,Termite基于VTE库,这是一个你喜欢每天与之互动的终端,特别是当它与i3窗口管理器结合时,其主要功能包括: 灵活性。 众多主题。 有许多关键绑定可供考虑用于捷径。 与其他应用程序集成,例如Oh-my-zsh。 历史搜索。 支持bash和zsh shell。 提供了AppImages。 最小的设计用户界面。 keyboard-centric VTE-based terminal https://wiki.archlinux.org/index.php/Termite https://github.com/thestinger/termite https://ywnz.com/linuxml/4305.html

2019-09-26 · 1 min · 25 words · -

go new make

go new make https://sanyuesha.com/2017/07/26/go-make-and-new/ new 和 make 都可以用来分配空间,初始化类型,但是它们确有不同。 new(T) 返回的是 T 的指针 new(T) 为一个 T 类型新值分配空间并将此空间初始化为 T 的零值,返回的是新值的地址,也就是 T 类型的指针 *T,该指针指向 T 的新分配的零值。 p1 := new(int) fmt.Printf("p1 -> %#v \n ", p1) //(*int)(0xc42000e250) fmt.Printf("p1 point to -> %#v \n ", *p1) //0 var p2 _int i := 0 p2 = &i fmt.Printf("p2 -> %#v \n ", p2) //(_int)(0xc42000e278) fmt.Printf("p2 point to -> %#v \n ", *p2) //0 上面的代码是等价的, new(int) 将分配的空间初始化为 int 的零值, 也就是 0, 并返回 int 的指针, 这和直接声明指针并初始化的效果是相同的. ...

2019-09-21 · 3 min · 582 words · -

Go stacks

Go stacks Viper: 配置管理 Bun ORM: ORM 框架 Resty: HTTP 客户端

2019-09-17 · 1 min · 11 words · -

将cmd中命令输出保存为TXT文本文件

将cmd中命令输出保存为TXT文本文件 https://www.cnblogs.com/hongten/archive/2013/03/27/hongten_windows_cms.html 将cmd中命令输出保存为TXT文本文件 在网上看到一篇名为: “[转载]如何将cmd中命令输出保存为TXT文本文件” 例如: 将Ping命令的加长包输出到D盘的ping.txt文本文件。 在D:目录下创建文本文件ping.txt (这步可以省略,偶尔提示无法创建文件时需要) 在提示符下输入ping <www.idoo.org.ru> -t > D:ping.txt 这时候发现D盘下面的ping.txt里面已经记录了所有的信息 备注: 只用">“是覆盖现有的结果,每一个命令结果会覆盖现有的txt文件,如果要保存很多命令结果的话,就需要建立不同文件名的txt文件。 那么有没有在一个更好的办法只用一个txt文件呢?答案是肯定的,要在同一个txt文件里面追加cmd命令结果,就要用”»“替换”>" 就可以了.

2019-09-17 · 1 min · 19 words · -

Making ipset,iptables persistent

Making ipset,iptables persistent ipset save > /etc/ipset.conf systemctl enable ipset.service iptables-save -f /etc/iptables/iptables.rules systemctl enable iptables.service https://wiki.archlinux.org/index.php/Ipset https://wiki.archlinux.org/index.php/Iptables

2019-09-09 · 1 min · 18 words · -

圈复杂度(Cyclomatic Complexity)

圈复杂度(Cyclomatic Complexity) 圈复杂度(Cyclomatic Complexity)是一种代码复杂度的衡量标准。它可以用来衡量一个模块判定结构的复杂程度,数量上表现为独立线性路径条数,也可理解为覆盖所有的可能情况最少使用的测试用例数。圈复杂度大说明程序代码的判断逻辑复杂,可能质量低且难于测试和维护。程序的可能错误和高的圈复杂度有着很大关系。 下面这个实例中,单元测试的覆盖率可以达到100%,但是很容易发现这其中已经漏掉了一个NPE的测试用例。case1方法的圈复杂度为2,因此至少需要2个用例才能完全覆盖到其所有的可能情况。 //程序原代码,圈复杂度为 2 public String case1(int num) { String string = null; if (num == 1) { string = “String”; } return string.substring(0); } //上面代码的单元测试代码 public void testCase1(){ String test1 = case1(1); } 圈复杂度主要与分支语句 (if、else、,switch 等) 的个数成正相关。当一段代码中含有较多的分支语句,其逻辑复杂程度就会增加。 圈复杂度的计算方法,可以参考这篇文章: http://blog.csdn.net/lg707415323/article/details/7790660 可以直接降低圈复杂度的 9 种重构技术 (针对结构化编程) Composing Methods(重新组织你的函数) Extract Method(提炼函数) Substitute Algorithm(替换你的算法) Simplifying Conditional Expressions(简化条件表达式) Decompose Conditional(分解表达式) Consolidate Conditional Expression(合并表达式) Consolidate Duplicate Conditional Fragments (合并重复的条件) Remove Control Flag(移除控制标记) Making Method Calls Simpler(简化函数调用) Separate Query from Modifier(将查询函数和修改函数分离) <2>PARAMETERIZE Method(令函数携带参数) ...

2019-09-09 · 1 min · 91 words · -

数据库事务, 锁

数据库事务, 锁 数据库锁 因为数据库要解决并发控制问题。在同一时刻,可能会有多个客户端对同一张表进行操作,比如有的在读取该行数据,其他的尝试去删除它。为了保证数据的一致性,数据库就要对这种并发操作进行控制,因此就有了锁的概念。 锁的分类 从对数据库操作的类型分 读锁(共享锁):针对同一块数据,多个读操作可以同时进行而不会互相影响。由读表操作加上的锁,加锁后其他用户只能获取该表或行的共享锁,不能获取排它锁,也就是说只能读不能写。 写锁(排它锁):当当前写操作没有完成之前,它会阻断其他写锁和读锁。由写表操作加上的锁,加锁后其他用户不能获取该表或行的任何锁。 从锁定的数据范围分 表锁:锁定某个表。 行锁 :锁定某行。 为了尽可能 提高数据库的并发度,每次锁定的数据范围越小越好。理论上每次只锁定当前操作的数据的方案会得到最大的并发度,但是管理锁是很耗费资源的事情。因此数据库系统需要在高并发响应和系统性能两方面进行平衡,这样就产生了“锁粒度”的概念。 锁粒度 表锁:管理锁的开销最小,同时允许的并发量也最小的锁机制。MyIsam存储引擎使用的锁机制。当要写入数据时,把整个表都锁上,此时其他读、写动作一律等待。在MySql中,除了MyIsam存储引擎使用这种锁策略外,MySql本身也使用表锁来执行某些特定动作,比如alter table. 行锁:可以支持最大并发的锁策略。InnoDB和Falcon两张存储引擎都采用这种策略。 MySql是一种开放的架构,你可以实现自己的存储引擎,并实现自己的锁粒度策略,不像Oracle,你没有机会改变锁策略,Oracle采用的是行锁。从大到小,mysql服务器仅支持表级锁,行锁需要存储引擎完成。粒度越精细,并发性越好。即行锁的并发性最好,但需要存储引擎的支持。 数据库事务有不同的隔离级别,不同的隔离级别对锁的使用是不同的,锁的应用最终导致不同事务的隔离级别。 事务和锁机制是什么关系? 开启事务就自动加锁了吗? 1、事务与锁是不同的。事务具有ACID(原子性、一致性、隔离性和持久性),锁是用于解决隔离性的一种机制。 2、事务的隔离级别通过锁的机制来实现。另外锁有不同的粒度,同时事务也是有不同的隔离级别的。 3、开启事务就自动加锁。 ql规范定义的事务的隔离级别: 1.READ UNCOMMITTED(读取未提交内容) 所有事务可以看到未提交事务的执行结果,本隔离级别很少用到实际应用中,读取未提交的数据,又称为“脏读”。 2.READ COMMITTED(读取提交内容) 大多数数据库的默认隔离级别是此级别,但不是MySQL默认的。一个事务在开始的时候只能看见已提交事务所做的改变。一个事务从开始到提交前所做的任何改变都是不可见的,除非提交。这种隔离级别也称为不可重复读。 3.REPEATABLE READ(可重复读) 此隔离级别是为了解决不可重复读隔离级别导致的问题即一个事务多个实例并发读取数据时会看到不同的结果。可重复读描述的是一个事务在处理数据时,多次查询此数据得到的结果是一样的。MySQL的InnoDB存储引擎通过多版本并发控制(Multi_Version Concurrency Control, MVCC)机制来解决该问题。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时, 另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。(幻读描述的是MVCC不能阻止插入新的数据,导致多次查询时数据记录不一致。) 4.SERIALIZABLE(可串行化) 可串行化是最高的隔离级别,它通过强制事务排序,使之不可重读,解决了幻读的问题。此隔离级别会在每个读的数据行上加共享锁,使用这种隔离级别会产生大量的超时现象,一般实际开发中不会用到。该类型在A客户端操作test.test1表时会锁定该数据,如果B客户端想要操作test.test1就需要等待A客户端释放。 这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如: 脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。 不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。 幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。 mysql加锁机制: 根据类型可分为共享锁(SHARED LOCK)和排他锁(EXCLUSIVE LOCK)或者叫读锁(READ LOCK)和写锁(WRITE LOCK)。 根据粒度划分又分表锁和行锁。表锁由数据库服务器实现,行锁由存储引擎实现。 mysql提供了3种事务型存储引擎,InnDB、NDB Cluster和Falcon。 一个事务执行的任何过程中都可以获得锁,但是只有事务提交或回滚的时候才释放这些锁。这些都是隐式锁定,也可以显式锁定,InnoDB支持显式锁定,例如: SELECT …. LOCK IN SHARE MODE (加共享锁) SELECT …..FOR UPDATE(加排他锁) ...

2019-09-09 · 1 min · 102 words · -