十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
1、情况一:MySQL的错误日志文件(安装目录\MYOA\data5\机器名.err)会记录如下内容:
浦北网站建设公司成都创新互联公司,浦北网站设计制作,有大型网站制作公司丰富经验。已为浦北数千家提供企业网站建设服务。企业网站搭建\成都外贸网站建设公司要多少钱,请找那个售后服务好的浦北做网站的公司定做!
InnoDB: Reading tablespace information from the .ibd files...
InnoDB: Error: trying to add tablespace 460 of name '.\td_oa\flow_data_35.ibd'
InnoDB: to the tablespace memory cache, but tablespace
InnoDB: 460 of name '.\td_oa\exam_data.ibd' already exists in the tablespace
解决方法:
1)剪切出安装目录\MYOA\data5\TD_OA的flow_data_35.ibd和flow_data_35.frm两个文件;
2)启动MySQL5_OA服务,使用备份的flow_data_35.sql导入到TD_OA库中。如果提示flow_data_35表已经存在不能导入,则继续按后续步骤执行;
3)在data5下手动建立tmp目录;
4)使用MySQL管理工具或MySQL命令行程序在tmp下建立名称为flow_data_35的表(包含一个字段即可);
5)将tmp下的flow_data_35.frm和flow_data_35.ibd拷贝到安装目录\MYOA\data5\TD_OA目录下;
6)在MySQL管理工具或MySQL命令行程序中,进入TD_OA库,使用“drop table flow_data_35;”命令清除公共表空间中残留的flow_data_35表的相关信息;
7)进入tmp库,删掉flow_data_35表;
8)使用备份的flow_data_35.sql导入到TD_OA库中;
9)如果还有其他表存在该问题,可重复执行4至8步骤。
2、情况二:MySQL的错误日志文件(安装目录\MYOA\data5\机器名.err)会记录如下内容:
130409 15:54:31 [Note] Plugin 'FEDERATED' is disabled.
130409 15:54:31 InnoDB: The InnoDB memory heap is disabled
130409 15:54:31 InnoDB: Mutexes and rw_locks use Windows interlocked functions
130409 15:54:31 InnoDB: Compressed tables use zlib 1.2.3
130409 15:54:32 InnoDB: Initializing buffer pool, size = 1023.0M
InnoDB: VirtualAlloc(1086849024 bytes) failed; Windows error 8
130409 15:54:32 InnoDB: Completed initialization of buffer pool
130409 15:54:32 InnoDB: Fatal error: cannot allocate memory for the buffer pool
130409 15:54:32 [ERROR] Plugin 'InnoDB' init function returned error.
130409 15:54:32 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
130409 15:54:32 [ERROR] Unknown/unsupported storage engine: Innodb
130409 15:54:32 [ERROR] Aborting
解决方法:
此情况出现的原因是myoa\mysql5\my.ini中innodb_buffer_pool_size的值太大,OA服务器操作系统不支持所致。改小后再启动mysql5_OA服务即可,一般保持和数据库大小一致。数据库大小即是myoa/data5的大小。
3、情况三:mysql服务启动不了,事件查看器中显示:The syntax
'--log-slow-queries' is deprecated and will be removed in a future
release. Please use '--slow-query-log'/'--slow-query-log-file' instead.
解决方法:安装目录\MYOA\data5下的ibdata1、ib_logfile0、ib_logfile1文件属性被设置为只读导致,取消只读控制,重启mysql5_OA服务即可。
4、情况四:MySQL的错误日志文件(data5\机器名.err)会记录如下内容:InnoDB: No valid checkpoint found.
解决方法:此问题找不到检查点,数据库是无效的,此种情况,只能用热备份数据恢复。
5、以上四种情况,是2013版OA系统目前比较常见的mysql服务启动不了的现象和解决办法,大家可作参考,其他情况的话,再具体分析处理。
6、分析思路总结:遇到mysql5_OA服务启动不了的情况,首先查看myoa\data5下的错误日志文件,根据日志中的具体内容进行具体分析。
7、2013版MYSQL服务启动不了(可以尝试强制启动mysql服务)方法如下:
1)打开\MYOA\mysql5\my.ini,去掉innodb_force_recovery=1前边的注释。
2)启动MySQL5_OA服务,此时MySQL处于只读状态,可以导出,不可写入。如果仍不能启动,可以尝试将innodb_force_recovery修改为2、3、4、5、6等,直到可以启动为止。
3)使用MySQL管理工具,将TD_OA等相关的数据库导出为SQL文件。
4)停止MySQL5_OA服务,删除TD_OA下的所有文件、ibdata1、ib_logfile0、ib_logfile1等文件。
5)打开\MYOA\mysql5\my.ini,在innodb_force_recovery=1前边加上#号,将该项注释掉。
6)启动MySQL5_OA服务,然后导入此前备份的SQL文件。
7)检查数据库,将无法通过该方法恢复的数据表,通过之前自动备份的SQL文件进行恢复。
MySQL 的 Binlog 记录着 MySQL 数据库的所有变更信息,了解 Binlog 的结构可以帮助我们解析Binlog,甚至对 Binlog 进行一些修改,或者说是“篡改”,例如实现类似于 Oracle 的 flashback 的功能,恢复误删除的记录,把 update 的记录再还原回去等。本文将带您探讨一下这些神奇功能的实现,您会发现比您想象地要简单得多。本文指的 Binlog 是 ROW 模式的 Binlog,这也是 MySQL 8 里的默认模式,STATEMENT 模式因为使用中有很多限制,现在用得越来越少了。
Binlog 由事件(event)组成,请注意是事件(event)不是事务(transaction),一个事务可以包含多个事件。事件描述对数据库的修改内容。
现在我们已经了解了 Binlog 的结构,我们可以试着修改 Binlog 里的数据。例如前面举例的 Binlog 删除了一条记录,我们可以试着把这条记录恢复,Binlog 里面有个删除行(DELETE_ROWS_EVENT)的事件,就是这个事件删除了记录,这个事件和写行(WRITE_ROWS_EVENT)的事件的数据结构是完全一样的,只是删除行事件的类型是 32,写行事件的类型是 30,我们把对应的 Binlog 位置的 32 改成 30 即可把已经删除的记录再插入回去。从前面的 “show binlog events” 里面可看到这个 DELETE_ROWS_EVENT 是从位置 378 开始的,这里的位置就是 Binlog 文件的实际位置(以字节为单位)。从事件(event)的结构里面可以看到 type_code 是在 event 的第 5 个字节,我们写个 Python 小程序把把第383(378+5=383)字节改成 30 即可。当然您也可以用二进制编辑工具来改。
找出 Binlog 中的大事务
由于 ROW 模式的 Binlog 是每一个变更都记录一条日志,因此一个简单的 SQL,在 Binlog 里可能会产生一个巨无霸的事务,例如一个不带 where 的 update 或 delete 语句,修改了全表里面的所有记录,每条记录都在 Binlog 里面记录一次,结果是一个巨大的事务记录。这样的大事务经常是产生麻烦的根源。我的一个客户有一次向我抱怨,一个 Binlog 前滚,滚了两天也没有动静,我把那个 Binlog 解析了一下,发现里面有个事务产生了 1.4G 的记录,修改了 66 万条记录!下面是一个简单的找出 Binlog 中大事务的 Python 小程序,我们知道用 mysqlbinlog 解析的 Binlog,每个事务都是以 BEGIN 开头,以 COMMIT 结束。我们找出 BENGIN 前面的 “# at” 的位置,检查 COMMIT 后面的 “# at” 位置,这两个位置相减即可计算出这个事务的大小,下面是这个 Python 程序的例子。
切割 Binlog 中的大事务
对于大的事务,MySQL 会把它分解成多个事件(注意一个是事务 TRANSACTION,另一个是事件 EVENT),事件的大小由参数 binlog-row-event-max-size 决定,这个参数默认是 8K。因此我们可以把若干个事件切割成一个单独的略小的事务
ROW 模式下,即使我们只更新了一条记录的其中某个字段,也会记录每个字段变更前后的值,这个行为是 binlog_row_image 参数控制的,这个参数有 3 个值,默认为 FULL,也就是记录列的所有修改,即使字段没有发生变更也会记录。这样我们就可以实现类似 Oracle 的 flashback 的功能,我个人估计 MySQL 未来的版本从可能会基于 Binlog 推出这样的功能。
了解了 Binlog 的结构,再加上 Python 这把瑞士军刀,我们还可以实现很多功能,例如我们可以统计哪个表被修改地最多?我们还可以把 Binlog 切割成一段一段的,然后再重组,可以灵活地进行 MySQL 数据库的修改和迁移等工作。
怎么样对MySQL中的事件进行调度
一、概述
事件调度器是在 MySQL 5.1 中新增的另一个特色功能,可以作为定时任务调度器,取代部分原先只能用操作系统任务调度器才能完成的定时功能。例如,Linux 中的 crontabe 只能精确到每分钟执行一次,而 MySQL 的事件调度器则可以实现每秒钟执行一个任务,这在一些对实时性要求较高的环境下就非常实用了。
事件调度器是定时触发执行的,在这个角度上也可以称作是"临时的触发器"。触发器只是针对某个表产生的事件执行一些语句,而事件调度器则是在某一个(间隔)时间执行一些语句。事件是由一个特定的线程来管理的,也就是所谓的"事件调度器"。启用事件调度器后,拥有 SUPER 权限的账户执行 SHOW PROCESSLIST 就可以看到这个线程了。通过设定全局变量event_scheduler 的值即可动态的控制事件调度器是否启用。
复制代码 代码如下:
(root:localhost:)test SET GLOBAL event_scheduler = ON;
(root:localhost:)test show processlist\G
*************************** 4. row ***************************
Id: 46147
User: event_scheduler
Host: localhost
db: NULL
Command: Daemon
Time: 1
State: Waiting on empty queue
Info: NULL
如上,该线程的所有者是 event_scheduler。
二、应用案例
本案例是利用 event scheduler 的特性,每秒钟调用一次存储过程,用于判断 SLAVE 是否正常运行,如果发现 SLAVE 关闭了,忽略 0 次错误,然后重新启动 SLAVE。
首先创建存储过程
delimiter //
复制代码 代码如下:
create procedure `Slave_Monitor`()
begin
SELECT VARIABLE_VALUE INTO @SLAVE_STATUS
FROM information_schema.GLOBAL_STATUS
WHERE VARIABLE_NAME='SLAVE_RUNNING';
IF ('ON' != @SLAVE_STATUS) THEN
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=0;
SLAVE START;
END IF;
end; //
delimiter ;
由于存储过程中无法调用类似 SHOW SLAVE STATUS 这样的语句,因此无法得到确切的复制错误信息和错误代码,不能进一步的处理 SLAVE 停止的各种情况。
接着,创建任务
复制代码 代码如下:
CREATE EVENT IF NOT EXISTS `Slave_Monitor`
ON SCHEDULE EVERY 5 SECOND
ON COMPLETION PRESERVE
DO
CALL Slave_Monitor();
创建了一个任务,每 5秒钟 执行一次,任务结束后依旧保留该任务,而不是删除。当然了,在本例中的任务不会结束,除非将它手动禁止了。
如果在运行中想要临时关闭一下某个任务,执行 ALTER EVENT 语句即可:
复制代码 代码如下:
(root:localhost:)test alter event `Slave_Monitor` ON
COMPLETION PRESERVE DISABLE;
(root:localhost:)test alter event `Slave_Monitor` ON
COMPLETION PRESERVE ENABLE;
通常情况下在PHP中MySQL查询是串行的,如果能实现MySQL查询的异步化,就能实现多条SQL语句同时执行,这样就能大大地缩短MySQL查询的耗时,提高数据库查询的效率。目前MySQL的异步查询只在MySQLi扩展提供,查询方法分别是:
1、使用MYSQLI_ASYNC模式执行mysqli::query
2、获取异步查询结果:mysqli::reap_async_query
使用mysql异步查询,需要使用mysqlnd作为PHP的MySQL数据库驱动。
使用MySQL异步查询,因为需要给所有查询都创建一个新的连接,而MySQL服务端会为每个连接创建一个单独的线程进行处理,如果创建的线程过多,则会造成线程切换引起系统负载过高。Swoole中的异步MySQL其原理是通过MYSQLI_ASYNC模式查询,然后获取mysql连接的socket,加入到epoll事件循环中,当数据库返回结果时会回调指定函数,这个过程是完全异步非阻塞的。
只要字段值还可以继续拆分,就不满足第一范式。
范式设计得越详细,对某些实际操作可能会更好,但并非都有好处,需要对项目的实际情况进行设定。
在满足第一范式的前提下,其他列都必须完全依赖于主键列。 如果出现不完全依赖,只可能发生在联合主键的情况下:
实际上,在这张订单表中,product_name 只依赖于 product_id ,customer_name 只依赖于 customer_id。也就是说,product_name 和 customer_id 是没用关系的,customer_name 和 product_id 也是没有关系的。
这就不满足第二范式:其他列都必须完全依赖于主键列!
拆分之后,myorder 表中的 product_id 和 customer_id 完全依赖于 order_id 主键,而 product 和 customer 表中的其他字段又完全依赖于主键。满足了第二范式的设计!
在满足第二范式的前提下,除了主键列之外,其他列之间不能有传递依赖关系。
表中的 customer_phone 有可能依赖于 order_id 、 customer_id 两列,也就不满足了第三范式的设计:其他列之间不能有传递依赖关系。
修改后就不存在其他列之间的传递依赖关系,其他列都只依赖于主键列,满足了第三范式的设计!
查询每门课的平均成绩。
查询 score 表中至少有 2 名学生选修,并以 3 开头的课程的平均分数。
分析表发现,至少有 2 名学生选修的课程是 3-105 、3-245 、6-166 ,以 3 开头的课程是 3-105 、3-245。也就是说,我们要查询所有 3-105 和 3-245 的 degree 平均分。
查询所有学生的 name,以及该学生在 score 表中对应的 c_no 和 degree 。
通过分析可以发现,只要把 score 表中的 s_no 字段值替换成 student 表中对应的 name 字段值就可以了,如何做呢?
查询所有学生的 no 、课程名称 ( course 表中的 name ) 和成绩 ( score 表中的 degree ) 列。
只有 score 关联学生的 no ,因此只要查询 score 表,就能找出所有和学生相关的 no 和 degree :
然后查询 course 表:
只要把 score 表中的 c_no 替换成 course 表中对应的 name 字段值就可以了。
查询所有学生的 name 、课程名 ( course 表中的 name ) 和 degree 。
只有 score 表中关联学生的学号和课堂号,我们只要围绕着 score 这张表查询就好了。
只要把 s_no 和 c_no 替换成 student 和 srouse 表中对应的 name 字段值就好了。
首先把 s_no 替换成 student 表中的 name 字段:
再把 c_no 替换成 course 表中的 name 字段:
查询 95031 班学生每门课程的平均成绩。
在 score 表中根据 student 表的学生编号筛选出学生的课堂号和成绩:
这时只要将 c_no 分组一下就能得出 95031 班学生每门课的平均成绩:
查询在 3-105 课程中,所有成绩高于 109 号同学的记录。
首先筛选出课堂号为 3-105 ,在找出所有成绩高于 109 号同学的的行。
查询所有成绩高于 109 号同学的 3-105 课程成绩记录。
查询所有和 101 、108 号学生同年出生的 no 、name 、birthday 列。
查询 '张旭' 教师任课的学生成绩表。
首先找到教师编号:
通过 sourse 表找到该教师课程号:
通过筛选出的课程号查询成绩表:
查询某选修课程多于5个同学的教师姓名。
首先在 teacher 表中,根据 no 字段来判断该教师的同一门课程是否有至少5名学员选修:
查看和教师编号有有关的表的信息:
我们已经找到和教师编号有关的字段就在 course 表中,但是还无法知道哪门课程至少有5名学生选修,所以还需要根据 score 表来查询:
根据筛选出来的课程号,找出在某课程中,拥有至少5名学员的教师编号:
在 teacher 表中,根据筛选出来的教师编号找到教师姓名:
查询 “计算机系” 课程的成绩表。
思路是,先找出 course 表中所有 计算机系 课程的编号,然后根据这个编号查询 score 表。
查询 计算机系 与 电子工程系 中的不同职称的教师。
查询课程 3-105 且成绩 至少 高于 3-245 的 score 表。
查询课程 3-105 且成绩高于 3-245 的 score 表。
查询某课程成绩比该课程平均成绩低的 score 表。
查询所有任课 ( 在 course 表里有课程 ) 教师的 name 和 department 。
查询 student 表中至少有 2 名男生的 class 。
查询 student 表中不姓 "王" 的同学记录。
查询 student 表中每个学生的姓名和年龄。
查询 student 表中最大和最小的 birthday 值。
以 class 和 birthday 从大到小的顺序查询 student 表。
查询 "男" 教师及其所上的课程。
查询最高分同学的 score 表。
查询和 "李军" 同性别的所有同学 name 。
查询和 "李军" 同性别且同班的同学 name 。
查询所有选修 "计算机导论" 课程的 "男" 同学成绩表。
需要的 "计算机导论" 和性别为 "男" 的编号可以在 course 和 student 表中找到。
建立一个 grade 表代表学生的成绩等级,并插入数据:
查询所有学生的 s_no 、c_no 和 grade 列。
思路是,使用区间 ( BETWEEN ) 查询,判断学生的成绩 ( degree ) 在 grade 表的 low 和 upp 之间。
准备用于测试连接查询的数据:
分析两张表发现,person 表并没有为 cardId 字段设置一个在 card 表中对应的 id 外键。如果设置了的话,person 中 cardId 字段值为 6 的行就插不进去,因为该 cardId 值在 card 表中并没有。
要查询这两张表中有关系的数据,可以使用 INNER JOIN ( 内连接 ) 将它们连接在一起。
完整显示左边的表 ( person ) ,右边的表如果符合条件就显示,不符合则补 NULL 。
完整显示右边的表 ( card ) ,左边的表如果符合条件就显示,不符合则补 NULL 。
完整显示两张表的全部数据。
在 MySQL 中,事务其实是一个最小的不可分割的工作单元。事务能够 保证一个业务的完整性 。
比如我们的银行转账:
在实际项目中,假设只有一条 SQL 语句执行成功,而另外一条执行失败了,就会出现数据前后不一致。
因此,在执行多条有关联 SQL 语句时, 事务 可能会要求这些 SQL 语句要么同时执行成功,要么就都执行失败。
在 MySQL 中,事务的 自动提交 状态默认是开启的。
自动提交的作用 :当我们执行一条 SQL 语句的时候,其产生的效果就会立即体现出来,且不能 回滚 。
什么是回滚?举个例子:
可以看到,在执行插入语句后数据立刻生效,原因是 MySQL 中的事务自动将它 提交 到了数据库中。那么所谓 回滚 的意思就是,撤销执行过的所有 SQL 语句,使其回滚到 最后一次提交 数据时的状态。
在 MySQL 中使用 ROLLBACK 执行回滚:
由于所有执行过的 SQL 语句都已经被提交过了,所以数据并没有发生回滚。那如何让数据可以发生回滚?
将自动提交关闭后,测试数据回滚:
那如何将虚拟的数据真正提交到数据库中?使用 COMMIT :
事务的实际应用 ,让我们再回到银行转账项目:
这时假设在转账时发生了意外,就可以使用 ROLLBACK 回滚到最后一次提交的状态:
这时我们又回到了发生意外之前的状态,也就是说,事务给我们提供了一个可以反悔的机会。假设数据没有发生意外,这时可以手动将数据真正提交到数据表中:COMMIT 。
事务的默认提交被开启 ( @@AUTOCOMMIT = 1 ) 后,此时就不能使用事务回滚了。但是我们还可以手动开启一个事务处理事件,使其可以发生回滚:
仍然使用 COMMIT 提交数据,提交后无法再发生本次事务的回滚。
事务的四大特征:
事务的隔离性可分为四种 ( 性能从低到高 ) :
查看当前数据库的默认隔离级别:
修改隔离级别:
测试 READ UNCOMMITTED ( 读取未提交 ) 的隔离性:
由于小明的转账是在新开启的事务上进行操作的,而该操作的结果是可以被其他事务(另一方的淘宝店)看见的,因此淘宝店的查询结果是正确的,淘宝店确认到账。但就在这时,如果小明在它所处的事务上又执行了 ROLLBACK 命令,会发生什么?
这就是所谓的 脏读 ,一个事务读取到另外一个事务还未提交的数据。这在实际开发中是不允许出现的。
把隔离级别设置为 READ COMMITTED :
这样,再有新的事务连接进来时,它们就只能查询到已经提交过的事务数据了。但是对于当前事务来说,它们看到的还是未提交的数据,例如:
但是这样还有问题,那就是假设一个事务在操作数据时,其他事务干扰了这个事务的数据。例如:
虽然 READ COMMITTED 让我们只能读取到其他事务已经提交的数据,但还是会出现问题,就是 在读取同一个表的数据时,可能会发生前后不一致的情况。* 这被称为* 不可重复读现象 ( READ COMMITTED ) 。
将隔离级别设置为 REPEATABLE READ ( 可被重复读取 ) :
测试 REPEATABLE READ ,假设在两个不同的连接上分别执行 START TRANSACTION :
当前事务开启后,没提交之前,查询不到,提交后可以被查询到。但是,在提交之前其他事务被开启了,那么在这条事务线上,就不会查询到当前有操作事务的连接。相当于开辟出一条单独的线程。
无论小张是否执行过 COMMIT ,在小王这边,都不会查询到小张的事务记录,而是只会查询到自己所处事务的记录:
这是 因为小王在此之前开启了一个新的事务 ( START TRANSACTION ) * ,那么* 在他的这条新事务的线上,跟其他事务是没有联系的 ,也就是说,此时如果其他事务正在操作数据,它是不知道的。
然而事实是,在真实的数据表中,小张已经插入了一条数据。但是小王此时并不知道,也插入了同一条数据,会发生什么呢?
报错了,操作被告知已存在主键为 6 的字段。这种现象也被称为 幻读,一个事务提交的数据,不能被其他事务读取到 。
顾名思义,就是所有事务的 写入操作 全都是串行化的。什么意思?把隔离级别修改成 SERIALIZABLE :
还是拿小张和小王来举例:
此时会发生什么呢?由于现在的隔离级别是 SERIALIZABLE ( 串行化 ) ,串行化的意思就是:假设把所有的事务都放在一个串行的队列中,那么所有的事务都会按照 固定顺序执行 ,执行完一个事务后再继续执行下一个事务的 写入操作 ( 这意味着队列中同时只能执行一个事务的写入操作 ) 。
根据这个解释,小王在插入数据时,会出现等待状态,直到小张执行 COMMIT 结束它所处的事务,或者出现等待超时。
转载:
1、命令查看是否开启event_scheduleSHOWVARIABLESLIKE'event_scheduler'。
2、使用命令开启临时开启,重启mysql又还原回去。
3、修改配置永久修改配置文件的[mysqld]部分加上event_scheduler=ON。