MySQL :: Download MySQL Community Server (Archived Versions)

默认安装:
./bin/mysqld --basedir=/usr/local/mysql/ --datadir=/usr/local/mysql/data --user=mysql --initialize
./support-files/mysql.server start
SET PASSWORD = PASSWORD('123456');
ALTER USER USER() IDENTIFIED BY '123456';
-----------------------------
自定义安装:
./my.cnf
[mysqld]
basedir=/www/server/mysql/mysql5.7
datadir=/www/server/mysql/mysql5.7/data
socket=/tmp/mysql5.7.sock
port=3306
user=mysql
default_storage_engine = InnoDB
performance_schema_max_table_instances = 400
table_definition_cache = 400
skip-external-locking
key_buffer_size = 128M
max_allowed_packet = 100G
table_open_cache = 512
sort_buffer_size = 2M
net_buffer_length = 4K
read_buffer_size = 2M
read_rnd_buffer_size = 256K
myisam_sort_buffer_size = 32M
thread_cache_size = 64
query_cache_size = 64M
tmp_table_size = 64M
sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
# Settings user and group are ignored when systemd is used.
# If you need to run mysqld under a different user or group,
# customize your systemd unit file for mariadb according to the
# instructions in http://fedoraproject.org/wiki/Systemd
[mysqld_safe]
log-error=/www/server/mysql/mysql5.7/mysql.log./bin/mysqld --defaults-file=./my.cnf --initialize
basedir=/www/server/mysql/mysql5.7
datadir=/www/server/mysql/mysql5.7/data
./support-files/mysql.server start
--------------------------------
源码安装:
编译器,头文件,数据文件拥有者,网络通讯sock文件(配置文件)
yum -y install gcc gcc-c++
CMake has bootstrapped. Now run gmake.
[100%] Built target foo
error:
-- Could not find (the correct version of) boost.
-- MySQL currently requires boost_1_59_0CMake Error at cmake/boost.cmake:88 (MESSAGE):
You can download it with -DDOWNLOAD_BOOST=1 -DWITH_BOOST=<directory>http://www.sourceforge.net/projects/boost/files/boost/1.59.0/boost_1_59_0.tar.gz
error:
-- Could NOT find Curses (missing: CURSES_LIBRARY CURSES_INCLUDE_PATH)
CMake Error at cmake/readline.cmake:71 (MESSAGE):
Curses library not found. Please install appropriate package,remove CMakeCache.txt and rerun cmake.On Debian/Ubuntu, package name is libncurses5-dev, on Redhat and derivates it is ncurses-devel.
yum install ncursed-devel -y[100%] Built target my_safe_process
cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ -DMYSQL_DATADIR=/usr/local/mysql/data \ -DMYSQL_UNIX_ADDR=/usr/local/mysql/tmp/mysql.sock \ -DDEFAULT_CHARSET=utf8 \ -DWITH_BOOST=/usr/local/boost \ -DDEFAULT_COLLATION=utf8_general_ci \ -DEXTRA_CHARSETS=gbk,gb2312,utf8,ascii \ -DWITH_INNOBASE_STORAGE_ENGINE=1 \ -DWITH_FEAERATED_STORAGE_ENGINE=1 \ -DWITH_BLACKHOLE_STORAGE_ENGINE=1 \ -DWITHOUT_EXAMPLE_STORAGE_ENGINE=1 \ -DWITHOUT_PARTITION_STORAGE_ENGINE=1 \ -DWITH_FAST_MUTEXES=1 \ -DWITH_ZLIB=bundled \ -DENABLED_LOCAL_INFILE=1 \ -DWITH_READLINE=1 \ -DWITH_EMBEDDED_SERVER=1 \ -DWITH_DEBUG=0
-----------------------------------------
mysql 5.7:
安全性:安装方式,密码
列计算:1 + 2 c3 ,before: 触发器,视图
json数据类型:before: text,varchar
Replication增强:支持多源复制,基于库或逻辑锁的多线程复制,在线变更复制方式

基于表的多线程复制:
mysql5.7之前,从5.6开始支持多线程复制,只不过是对于每一个库一个复制线程。
mysql5.7之后,对多线程复制功能进行了加强,加强了slave_parallel_type参数可以控制并发同步是基于database还是logical_clock(主从并行支持事务)
在线变更复制方式:
mysql5.7之前:要把基于日志点的复制方式变更为基于gtid的复制方式或是把基于gtid的复制方式变更为基于日志的复制方式必须要重启master服务器。
mysql5.7之后,允许在线变更复制方式,而不用重启master服务器;
Innodb引擎增强:支持缓冲池大小在线变更,增强innodb_buffer_pool导入导出功能(内存热数据导入磁盘,重启加载),支持为innodb表建立表空间;
mysql5.7之前,要变更innodb_buffer_pool大小必须更改my.cnf文件后重启数据库服务器;
mysql5.7之后,innodb_buffer_pool_size参数变为动态参数,可以在线调整innodb缓存池的大小;
mysql5.7之前,具有系统表空间及可以为每个表建立一个独立的表空间;
mysql5.7之后,支持create tablespace 语法为一个表或多个表建立公用的表空间;
安全及管理方面的增强:
不再支持old_password认证,增加账号默认过期时间及加强对账号的管理功能,增加了sys管理数据库;
mysql > help create user;
select * from mysql.user \G;
----------------------------------------------------
mysql> show variables like "innodb_file_per_table";
参数innodb_file_per_table=1重新启动mysql
innodb的数据结构: 共享表空间(0)以及独占表空间(1)
共享表空间: 所有的表数据,索引文件全部放在一个文件中(.frm)
独占表空间: 每一个表都将会生成以独立的文件方式来进行存储,每一个表都有一个.frm表描述文件,还有一个.ibd文件(表的数据内容以及索引内容);
MYISAM表由:表名.frm 描述表结构。表名.MYD保存表数据。表名.MYI存储表索引
引擎:
alter table tableName engine=innodb / myisam
锁:
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用;
行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统。
MySQL的表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。
锁模式的兼容性:
对MyISAM表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写请求;
对MyISAM表的写操作,则会阻塞其他用户对同一表的读和写操作;
MyISAM表的读操作与写操作之间,以及写操作之间是串行的。当一个线程获得对一个表的写锁后,只有持有锁的线程可以对表进行更新操作。其他线程的读、写操作都会等待,直到锁被释放为止。
MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此,用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁
MySQL内部有两组专门的状态变量记录系统内部锁资源争用情况;
状态值都是从系统启动后开始记录,出现一次对应的事件则数量加1:
> show status like 'table%';
Table_locks_immediate:产生表级锁定的次数;
Table_locks_waited:出现表级锁定争用而发生等待的次数;
缩短锁定时间 < Query执行时间尽可能的短
MyISAM的存储引擎有一个非常有用的特性 : ConcurrentInsert(并发插入)的特性。
concurrent_insert=2,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录;
concurrent_insert=1,如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是MySQL的默认设置;
concurrent_insert=0,不允许并发插入。
利用MyISAM存储引擎的并发插入特性,来解决应用中对同一表查询和插入的锁争用。例如,将concurrent_insert系统变量设为2,总是允许并发插入;同时,通过定期在系统空闲时段执行OPTIMIZE TABLE语句来整理空间碎片,收回因删除记录而产生的中间空洞。
MySQL的表级锁定对于读和写是有不同优先级设定的,默认情况下是写优先级要大于读优先级。
所以,如果我们可以根据各自系统环境的差异决定读与写的优先级:
通过执行命令SET LOW_PRIORITY_UPDATES=1,使该连接读比写的优先级高。
如果我们的系统是一个以读为主,可以设置此参数,如果以写为主,则不用设置;
行级锁定
InnoDB的行级锁定分为两种类型,共享锁和排他锁
而在锁定机制的实现过程中为了让行级锁定和表级锁定共存,InnoDB也同样使用了意向锁(表级锁定)的概念,也就有了意向共享锁和意向排他锁这两种。
InnoDB的锁定模式实际上分为四种:共享锁(S),排他锁(X),意向共享锁(IS)和意向排他锁(IX),共存逻辑关系?

如果一个事务请求的锁模式与当前的锁兼容,InnoDB就将请求的锁授予该事务;反之,如果两者不兼容,该事务就要等待锁释放。
意向锁是InnoDB自动加的,不需用户干预。
对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);
对于普通SELECT语句,InnoDB不会加任何锁;
事务可以通过以下语句显示给记录集加共享锁或排他锁。
共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE用SELECT ... IN SHARE MODE获得共享锁,主要用在需要数据依存关系时来确认某行记录是否存在,并确保没有人对这个记录进行UPDATE或者DELETE操作。
但是如果当前事务也需要对该记录进行更新操作,则很有可能造成死锁,对于锁定行记录后需要进行更新操作的应用,应该使用SELECT... FOR UPDATE方式获得排他锁。
InnoDB行锁是通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁
间隙锁(Next-Key锁)间隙锁锁定的是一个范围,而不是具体的索引键
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;
对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。
事务再次执行,就会发生幻读(防止幻读,以满足相关隔离级别的要求);
死锁:
MyISAM表锁总是一次获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。
但在InnoDB中,除单个SQL组成的事务外,锁是逐步获得的,当两个事务都需要获得对方持有的排他锁才能继续完成事务,这种循环锁等待就是典型的死锁。
在InnoDB的事务管理和锁定机制中,有专门检测死锁的机制,会在系统中产生死锁之后的很短时间内就检测到该死锁的存在。当InnoDB检测到系统中产生了死锁之后,InnoDB会通过相应的判断来选这产生死锁的两个事务中较小的事务来回滚,而让另外一个较大的事务成功完成。
那InnoDB是以什么来为标准判定事务的大小的呢?MySQL官方手册中也提到了这个问题,实际上在InnoDB发现死锁之后,会计算出两个事务各自插入、更新或者删除的数据量来判定两个事务的大小。也就是说哪个事务所改变的记录条数越多,在死锁中就越不会被回滚掉。
但是有一点需要注意的就是,当产生死锁的场景中涉及到不止InnoDB存储引擎的时候,InnoDB是没办法检测到该死锁的,这时候就只能通过锁定超时限制参数InnoDB_lock_wait_timeout来解决。
需要说明的是,这个参数并不是只用来解决死锁问题,在并发访问比较高的情况下,如果大量事务因无法立即获得所需的锁而挂起,会占用大量计算机资源,造成严重性能问题,甚至拖跨数据库。我们通过设置合适的锁等待超时阈值,可以避免这种情况发生。
通常来说,死锁都是应用设计的问题,通过调整业务流程、数据库对象设计、事务大小,以及访问数据库的SQL语句,绝大部分死锁都可以避免。
(1)在应用中,如果不同的程序会并发存取多个表,应尽量约定以相同的顺序来访问表,这样可以大大降低产生死锁的机会。
(2)在程序以批量方式处理数据的时候,如果事先对数据排序,保证每个线程按固定的顺序来处理记录,也可以大大降低出现死锁的可能。
(3)在事务中,如果要更新记录,应该直接申请足够级别的锁,即排他锁,而不应先申请共享锁,更新时再申请排他锁,因为当用户申请排他锁时,其他事务可能又已经获得了相同记录的共享锁,从而造成锁冲突,甚至死锁。
(4)在REPEATABLE-READ隔离级别下,如果两个线程同时对相同条件记录用SELECT...FOR UPDATE加排他锁,在没有符合该条件记录情况下,两个线程都会加锁成功。程序发现记录尚不存在,就试图插入一条新记录,如果两个线程都这么做,就会出现死锁。这种情况下,将隔离级别改成READ COMMITTED,就可避免问题。
(5)当隔离级别为READ COMMITTED时,如果两个线程都先执行SELECT...FOR UPDATE,判断是否存在符合条件的记录,如果没有,就插入记录。此时,只有一个线程能插入成功,另一个线程会出现锁等待,当第1个线程提交后,第2个线程会因主键重出错,但虽然这个线程出错了,却会获得一个排他锁。这时如果有第3个线程又来申请排他锁,也会出现死锁。对于这种情况,可以直接做插入操作,然后再捕获主键重异常,或者在遇到主键重错误时,总是执行ROLLBACK释放获得的排他锁。
(1)事务需要更新大部分或全部数据,表又比较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其他事务长时间锁等待和锁冲突,这种情况下可以考虑使用表锁来提高该事务的执行速度。
(2)事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚。这种情况也可以考虑一次性锁定事务涉及的表,从而避免死锁、减少数据库因事务回滚带来的开销。
(1)使用LOCK TABLES虽然可以给InnoDB加表级锁,但必须说明的是,表锁不是由InnoDB存储引擎层管理的,而是由其上一层──MySQL Server负责的,仅当autocommit=0、InnoDB_table_locks=1(默认设置)时,InnoDB层才能知道MySQL加的表锁,MySQL Server也才能感知InnoDB加的行锁,这种情况下,InnoDB才能自动识别涉及表级锁的死锁,否则,InnoDB将无法自动检测并处理这种死锁。
(2)在用 LOCK TABLES对InnoDB表加锁时要注意,要将AUTOCOMMIT设为0,否则MySQL不会给表加锁;事务结束前,不要用UNLOCK TABLES释放表锁,因为UNLOCK TABLES会隐含地提交事务;COMMIT或ROLLBACK并不能释放用LOCK TABLES加的表级锁,必须用UNLOCK TABLES释放表锁。
a)尽可能让所有的数据检索都通过索引来完成,从而避免InnoDB因为无法通过索引键加锁而升级为表级锁定;
b)合理设计索引,让InnoDB在索引键上面加锁的时候尽可能准确,尽可能的缩小锁定范围,避免造成不必要的锁定而影响其他Query的执行;
c)尽可能减少基于范围的数据检索过滤条件,避免因为间隙锁带来的负面影响而锁定了不该锁定的记录;
d)尽量控制事务的大小,减少锁定的资源量和锁定时间长度;
e)在业务环境允许的情况下,尽量使用较低级别的事务隔离,以减少MySQL因为实现事务隔离级别所带来的附加成本。
(2)由于InnoDB的行级锁定和事务性,所以肯定会产生死锁,下面是一些比较常用的减少死锁产生概率的小建议:
a)类似业务模块中,尽可能按照相同的访问顺序来访问,防止产生死锁;
b)在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
c)对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率。
通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况:
> show status like 'InnoDB_row_lock%';InnoDB_row_lock_current_waits:当前正在等待锁定的数量;
InnoDB_row_lock_time:从系统启动到现在锁定总时间长度;
InnoDB_row_lock_time_avg:每次等待所花平均时间;
InnoDB_row_lock_time_max:从系统启动到现在等待最常的一次所花的时间;
InnoDB_row_lock_waits:系统启动后到现在总共等待的次数;
select lock in share mode共享
select for update排他
begin;
select * from goods where id = 1 for update;
update goods set stock = stock - 1 where id = 1;
commit;
#不加锁获取 id=1 的商品对象
select * from goods where id = 1 ;
begin;
#更新 stock 值,这里需要注意 where 条件 “stock = cur_stock”,只有程序中获取到的库存量与数据库中的库存量相等才执行更新 update goods set stock = stock - 1 where id = 1 and stock = cur_stock;
commit;
-----------------------
make -j2 # 两个线程编译 , Makefile , make clean

