网站首页 包含标签 数据库 的所有文章

  • 如何快速搭建xxl-job项目详解

    文章目录 第1步:下载xxl-job源码 第2步:初始化数据库SQL 第3步:配置部署“调度中心” 3.1:修改调度中心配置文件: 3.2:部署调度中心项目 3.3 调度中心集群(可选): 3.4 其他:Docker 镜像方式搭建调度中心: 第4步: 配置部署“执行器项目” 4.1:部署执行器项目 4.2:测试执行定时任务 总结 本文重点讲解如何快速搭建xxl-job分布式任务调度框架项目,不对xxl-job做深入介绍,如果还不了解该框架的可以移步《xxl-job分布式任务调度框架详解》这篇文章,本文只讲解如何快速搭建xxl-job项目相关的实操步骤,我们一起来看以下。 搭建xxl-job项目xxl-job主要分为4个步骤: 第1步:下载xxl-job源码 首先我们去github或者gitee去下载xxl-job的项目源码,这里我下载2.4.0的版本。以下是下载地址: github:https://github.com/xuxueli/xxl-job gitee:https://gitee.com/xuxueli0323/xxl-job xxl-job官方教程文档:https://www.xuxueli.com/xxl-job/ 下载时选择自己想要的版本,建议是稳定版。 第2步:初始化数据库SQL 接下来,我们需要初始化“调度数据库”,请将下载好的项目源码解压,获取 “调度数据库初始化SQL脚本” 并执行即可,SQL脚本位置在如下: /xxl-job/doc/db/tables_xxl_job.sql 注意: 1)该SQL脚本是mysql数据库脚本,会自动创建名为xxl_job的数据库,表名也都是xxl_job开头的,如果你要修改数据库名称,记得提前改下脚本,初始化后一共8张表如下: 2)另外,调度中心支持集群部署,集群情况下各节点务必连接同一个mysql实例,如果mysql做主从,调度中心集群节点务必强制走主库。 第3步:配置部署“调度中心” 接下来我们需要配置部署“调度中心”,调度中心的作用是统一管理任务调度平台上调度任务,负责触发调度执行,并且提供任务管理平台。其实就是我们可视化的后台管理项目,即调度中心项目:xxl-job-admin。 因此,我们需要将源码中xxl-job-admin项目导入IDEA,由于是maven开发的,因此你本地需要配置好maven环境,没配置过的请参考《IntelliJ IDEA如何整合Maven图文教程详解》。 3.1:修改调度中心配置文件: 调度中心配置文件地址: /xxl-job-admin/src/main/resources/application.properties 调度中心配置内容说明: ### 调度中心JDBC链接:链接地址请保持和 2.1章节 所创建的调度数据库的地址一致 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=root_pwd spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver ### 报警邮箱 spring.mail.host=smtp.qq.com spring.mail.port=25 spring.mail.username=xxx@qq.com spring.mail.password=xxx spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true spring.mail.properties.mail.smtp.starttls.required=true spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory ### 调度中心通讯TOKEN [选填]:非空时启用; xxl.job.accessToken= ### 调度中心国际化配置 [必填]: 默认为 "zh_CN"/中文简体, 可选范围为 "zh_CN"/中文简体, "zh_TC"/中文繁体 and "en"/英文; xxl.job.i18n=zh_CN ## 调度线程池最大线程配置【必填】 xxl.job.triggerpool.fast.max=200 xxl.job.triggerpool.slow.max=100 ### 调度中心日志表数据保存天数 [必填]:过期日志自动清理;限制大于等于7时生效,否则, 如-1,关闭自动清理功能; xxl.job.logretentiondays=30 以上配置重点关注jdbc数据库连接相关的内容,比如修改数据库用户名密码,以及报警邮箱相关配置,这里就不再详细展开,大家根据自己的需求配置修改即可。 3.2:部署调度中心项目 在idea中可以直接启动运行该项目,如果已经正确进行上述配置,运行成功会打印如下日志: 10:13:54.594 logback [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '/xxl-job-admin' 10:13:54.606 logback [main] INFO c.x.job.admin.XxlJobAdminApplication - Started XxlJobAdminApplication in 2.167 seconds (JVM running for 3.881) 10:13:59.003 logback [xxl-job, admin JobScheduleHelper#scheduleThread] INFO c.x.j.a.c.thread.JobScheduleHelper - >>>>>>>>> init xxl-job admin scheduler success. 然后浏览器访问调度中心访问地址:http://localhost:8080/xxl-job-admin(该地址执行器将会使用到,作为回调地址) 默认登录账号 “admin/123456”, 登录后运行界面如下图所示。 如果要上线部署,可将项目编译打包部署即可。以上,我们就将任务调度中心集成好了。 另外补充说明以下两点: 3.3 调度中心集群(可选): 调度中心支持集群部署,提升调度系统容灾和可用性。 调度中心集群部署时,几点要求和建议: DB配置保持一致; 集群机器时钟保持一致(单机集群忽视); 建议:推荐通过nginx为调度中心集群做负载均衡,分配域名。调度中心访问、执行器回调配置、调用API服务等操作均通过该域名进行。 3.4 其他:Docker 镜像方式搭建调度中心: 参考文章《docker如何部署xxl-job调度中心》 第4步: 配置部署“执行器项目” “执行器”项目其实就是我们下载源码中的:xxl-job-executor-samples项目,这里面有两个“执行器”项目,分别为xxl-job-executor-sample-frameless和xxl-job-executor-sample-springboot。 xxl-job提供2种版本执行器供选择,现以 springboot 版本为例,可直接使用,也可以参考其并将现有项目改造成执行器。 顺便说下执行器项目作用:负责接收“调度中心”的调度并执行;可直接部署执行器,也可以将执行器集成到现有业务项目中。 4.1:部署执行器项目 我们使用idea打开xxl-job-executor-samples项目,注意application.properties中xxl.job.admin.addresses配置,调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行”执行器心跳注册”和”任务结果回调”;为空则关闭自动注册;我们这里默认和之前调度中心地址一致即可。 xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin 然后直接运行xxl-job-executor-springboot项目,发现启动成功。 4.2:测试执行定时任务 接下来,我们测试执行系统默认定时任务,打开调度中心页面,在任务管理中,执行一次,如下图: 我们发现在xxl-job-executor-springboot项目中,打印了如下信息: 10:43:54.772 logback [Thread-8] INFO com.xxl.job.core.server.EmbedServer - >>>>>>>>>>> xxl-job remoting server start success, nettype = class com.xxl.job.core.server.EmbedServer, port = 9999 10:47:23.505 logback [xxl-job, EmbedServer bizThreadPool-303137862] INFO c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job regist JobThread success, jobId:1, handler:com.xxl.job.core.handler.impl.MethodJobHandler@344426bf[class com.xxl.job.executor.service.jobhandler.SampleXxlJob#demoJobHandler] 10:49:06.782 logback [xxl-job, JobThread-1-1700189243505] INFO com.xxl.job.core.thread.JobThread - >>>>>>>>>>> xxl-job JobThread stoped, hashCode:Thread[xxl-job, JobThread-1-1700189243505,10,main] 查看调度日志查看发现调度成功: 总结 当然你也可以将下载的整个项目源码导入idea,分别修改配置,然后运行以上的两个子项目,就可以进行搭建测试了。 如果你想将调度执行项目集成到自己的springboot项目中该如何去实现呢?具体的请参考文章《SpringBoot如何集成整合xxl-job任务调度框架》。 以上就是快速搭建搭建xxl-job项目详解的全部内容,希望对你有帮助。 ...

    2023-11-20 233
  • 如何优化mysql like %xxx%模糊查询?

    本文主要讲解关于如何优化mysql like %xxx%模糊查询相关内容,让我们来一起学习下吧! 今天给大家分享一个小知识,实际项目中,like %xxx%的情况其实挺多的,比如某个表单如果支持根据公司名进行搜索,用户一般都是输入湖南xxx有限公司中的xxx进行搜索,所以对于接口而言,就必须使用like %xxx%来支持,从而不符合最左前缀原则导致索引失效,那么该如何优化这种情况呢? 第一种可以尝试的方案就是利用索引条件下推,我先演示再讲原理,比如我有下面一张订单表: 就算给company_name创建一个索引,执行where company_name like '%腾讯%'也不会走索引。 但是如果给created_at, company_name创建一个联合索引,那么执行where created_at=CURDATE() and company_name like '%腾讯%'就会走联合索引,并且company_name like '%腾讯%'就会利用到索引条件下推机制,比如下图中Extra里的Using index condition就表示利用了索引条件下推。 所以,并不是like %xxx%就一定会导致索引失效,原理也可以配合其他字段一起来建联合索引,从而使用到索引条件下推机制。 再来简单分析一下索引条件下推的原理,在执行查询时先利用SQL中所提供的created_at条件在联合索引B+树中进行快速查找,匹配到所有符合created_at条件的B+树叶子节点后,再根据company_name条件进行过滤,然后再根据过滤之后的结果中的主键ID进行回表找到其他字段(回表),最终才返回结果,这样处理的好处是能够减少回表的次数,从而提高查询效率。 当然,如果实在不能建立或不方便建立联合索引,导致不能利用索引条件下推机制,那么其实可以先试试Mysql中的全文索引,最后才考虑引入ES等中间件,当然Mysql其他一些常规优化机制也是可以先考虑的,比如分页、索引覆盖(不select *)等。 以上就是关于如何优化mysql like %xxx%模糊查询相关的全部内容,希望对你有帮助。欢迎持续关注潘子夜个人博客,学习愉快哦! ...

    2023-11-20 227
  • 索引失效场景有哪些

    使用函数或运算符处理列 当在查询条件中对列进行函数调用或进行运算时,索引通常会失效。 例如,WHERE DATE_FORMAT(column, '%Y-%m-%d') = '2023-11-10',这种情况下,无法使用列上的索引。 使用通配符前缀 当在查询条件中使用通配符前缀(如LIKE 'prefix%')时,通常无法使用索引。 使用OR条件 在WHERE子句中使用多个OR条件时,如果每个条件都没有适用的索引,那么索引可能会失效。 不等于条件 当使用不等于条件(!=或<>)时,索引通常会失效。 数据分布不均匀 如果索引列上的数据分布极不均匀,即某些值出现非常频繁,而其他值出现很少,索引可能会失效。这会导致查询优化器认为扫描整个表更快。 大数据表 当表非常大时,即使索引存在,查询优化器可能会选择执行全表扫描,因为扫描整个表可能比使用索引更快。 列数据类型不匹配 当查询条件中的列数据类型与索引列数据类型不匹配时,索引可能会失效。例如,对字符串列应用数值函数。 连接操作(JOIN) 在连接操作中,如果没有适用的索引来支持连接条件,索引可能会失效。 类型转换 当查询条件中的列需要进行类型转换以与索引列匹配时,索引通常会失效。 子查询 子查询可能会导致索引失效,尤其是当子查询结果集非常大时。 ...

    2023-11-10 157
  • 数据库查询慢怎么优化

    定位慢查询 数据库监控工具:使用数据库监控工具,如MySQL的Slow Query Log或PostgreSQL的pg_stat_statements,来识别慢查询。这些工具可以记录执行时间较长的查询。 查询执行计划:对于关系型数据库,查看查询执行计划是一种重要的方式来定位性能问题。通过EXPLAIN或EXPLAIN ANALYZE命令,可以查看数据库是如何执行查询的,以及是否有性能问题。 应用层监控:使用应用层性能监控工具来识别慢查询的来源。这些工具可以告诉你哪些查询正在导致性能下降。 监控索引:确保表上使用了适当的索引。缺少索引或者使用不当的索引可能导致查询变慢。 检查服务器负载:如果服务器负载过高,可能导致查询变慢。检查服务器的CPU、内存和磁盘使用情况。 优化慢查询 索引优化:确保数据库表上的列有适当的索引,这有助于加速检索。但不要过度索引,因为索引也会增加写操作的开销。 重写查询:有时,可以通过重写查询语句来优化查询性能。使用合适的WHERE子句、JOIN条件和ORDER BY子句等。 缓存:使用缓存来减少数据库查询的频率。可以使用缓存中间件(如Redis或Memcached)或应用程序级别的缓存。 升级硬件:如果服务器性能不足,可以考虑升级硬件,包括CPU、内存和存储。 分区:对于大型表,可以考虑分区,以减小查询的范围。 定期维护:定期执行数据库维护操作,如索引重建、表优化和统计信息更新,以确保数据库性能不下降。 限制结果集大小:通过限制查询返回的结果集大小,可以减轻数据库负担。 异步处理:将某些查询从同步操作改为异步操作,以提高应用程序的响应速度。 数据库分片:对于大型数据库,可以考虑数据库分片,将数据分散到多个服务器上以提高查询性能。 使用合适的数据库引擎:不同的数据库引擎具有不同的性能特点。根据应用程序需求选择合适的数据库引擎。 ...

    2023-11-10 165
  • MySQL常见的三种存储引擎是什么

    MyISAM MyISAM表是独立于操作系统的,这说明可以轻松地将其从Windows服务器移植到Linux服务器; 每当我们建立一个MyISAM引擎的表时,就会在本地磁盘上建立三个文件,文件名就是表明。 例如,我建立了一个MyISAM引擎的tb_Demo表,那么就会生成以下三个文件: tb_demo.frm,存储表定义; tb_demo.MYD,存储数据; tb_demo.MYI,存储索引。 MyISAM表无法处理事务,这就意味着有事务处理需求的表,不能使用MyISAM存储引擎。 MyISAM存储引擎特别适合在以下几种情况下使用: 选择密集型的表。MyISAM存储引擎在筛选大量数据时非常迅速,这是它最突出的优点。 插入密集型的表。MyISAM的并发插入特性允许同时选择和插入数据。例如:MyISAM存储引擎很适合管理邮件或Web服务器日志数据。 InnoDB InnoDB是一个健壮的事务型存储引擎,这种存储引擎已经被很多互联网公司使用,为用户操作非常大的数据存储提供了一个强大的解决方案。 我的电脑上安装的MySQL 5.6.13版,InnoDB就是作为默认的存储引擎。 InnoDB还引入了行级锁定和外键约束,在以下场合下,使用InnoDB是最理想的选择: 更新密集的表。InnoDB存储引擎特别适合处理多重并发的更新请求。 事务。InnoDB存储引擎是支持事务的标准MySQL存储引擎。 自动灾难恢复。与其它存储引擎不同,InnoDB表能够自动从灾难中恢复。 外键约束。MySQL支持外键的存储引擎只有InnoDB。 支持自动增加列AUTO_INCREMENT属性。 一般来说,如果需要事务支持,并且有较高的并发读取频率,InnoDB是不错的选择。 MEMORY 使用MySQL Memory存储引擎的出发点是速度。 为得到最快的响应时间,采用的逻辑存储介质是系统内存。 虽然在内存中存储表数据确实会提供很高的性能,但当mysqld守护进程崩溃时,所有的Memory数据都会丢失。 获得速度的同时也带来了一些缺陷。它要求存储在Memory数据表里的数据使用的是长度不变的格式,这意味着不能使用BLOB和TEXT这样的长度可变的数据类型,VARCHAR是一种长度可变的类型,但因为它在MySQL内部当做长度固定不变的CHAR类型,所以可以使用。 一般在以下几种情况下使用Memory存储引擎: 目标数据较小,而且被非常频繁地访问。在内存中存放数据,所以会造成内存的使用,可以通过参数max_heap_table_size控制Memory表的大小,设置此参数,就可以限制Memory表的最大大小。 如果数据是临时的,而且要求必须立即可用,那么就可以存放在内存表中。 存储在Memory表中的数据如果突然丢失,不会对应用服务产生实质的负面影响。 Memory同时支持散列索引和B树索引。 B树索引的优于散列索引的是,可以使用部分查询和通配查询,也可以使用<、>和>=等操作符方便数据挖掘。 散列索引进行“相等比较”非常快,但是对“范围比较”的速度就慢多了,因此散列索引值适合使用在=和<>的操作符中,不适合在<或>操作符中,也同样不适合用在order by子句中。 ...

    2023-11-07 168
  • InnoDB引擎与MyISAM引擎的区别

    1.数据存储的方式不同,MyISAM 中的数据和索引是分开存储的,而 InnoDB 是把索引和数据存储在同一个文件里面。 2.对于事务的支持不同,MyISAM 不支持事务,而 InnoDB 支持 ACID 特性的事务处理 3.对于锁的支持不同,MyISAM 只支持表锁,而 InnoDB 可以根据不同的情况,支持行锁,表锁,间隙锁,临键锁 4.MyISAM 不支持外键,InnoDB 支持外键 当然也可以从索引结构、存储限制等方面,更加深入的回答。 具体参考如下官方文档:https://dev.mysql.com/doc/refman/8.0/en/innodb-introduction.htm ...

    2023-11-06 172
  • 存储引擎区别及特点有哪些

    特点 InnoDB MyISAM Memory 存储限制 64TB 有 有 事务安全 支持 – – 锁机制 行锁 表锁 表锁 B+tree索引 支持 支持 支持 Hash索引 – – 支持 全文索引 支持(5.6版本之后) 支持 – 空间使用 高 低 n/a 内存使用 高 低 中等 批量插入速度 低 高 高 支持外键 支持 – – ...

    2023-11-06 173
  • Memory存储引擎的特点

    Memory介绍 Memory引擎的表数据时存储在内存中的,由于受到硬件问题、或断电问题的影响,只能将这些表作为 临时表或缓存使用。 Memory特点 数据存储在内存中,读取速度非常快。 不支持事务和持久性,数据在数据库重启时丢失。 适合用作缓存或临时存储。 表级锁定 Memory文件 xxx.sdi:存储表结构信息创建表 my_memory , 指定Memory存储引擎 create table my_memory( id int, name varchar(10) ) engine = Memory ; ...

    2023-11-06 181
  • MyISAM存储引擎的特点

    MyISAM介绍 MyISAM是MySQL早期的默认存储引擎。 MyISAM特点 不支持事务,不提供ACID特性。 支持表级锁定,性能较差于InnoDB在高并发环境中。 较快的读取性能,适用于只读或读写很少的应用。 没有外键约束。 MyISAM文件 xxx.sdi:存储表结构信息 xxx.MYD: 存储数据 xxx.MYI: 存储索引创建表 my_myisam , 并指定MyISAM存储引擎 create table my_myisam( id int, name varchar(10) ) engine = MyISAM ; ...

    2023-11-06 161
  • innodb存储引擎特点

    InnoDB介绍 InnoDB是一种兼顾高可靠性和高性能的通用存储引擎,在 MySQL 5.5 之后,InnoDB是默认的 MySQL 存储引擎。 InnoDB特点 支持事务,提供ACID(原子性、一致性、隔离性、持久性)特性。 支持行级锁定,适用于高并发环境。 支持外键约束,确保数据一致性。 具有自动崩溃恢复和日志文件,以确保数据的持久性。 InnoDB文件 xxx.ibd:xxx代表的是表名,innoDB引擎的每张表都会对应这样一个表空间文件,存储该表的表结 构(frm-早期的 、sdi-新版的)、数据和索引。参数:innodb_file_per_table show variables like 'innodb_file_per_table' 如果该参数开启,代表对于InnoDB引擎的表,每一张表都对应一个ibd文件。我们直接打开MySQL的 数据存放目录, 这个目录下有很多文件 夹,不同的文件夹代表不同的数据库. 注意:idb是二进制文件,不可以使用记事本直接打开,可以使用mysql提供指令打开 以从ibd文件中提取sdi信息,而sdi数据字典信息中就包含该表的表结构。 注意:使用cmd名称窗口查看 ibd2sdi tb_account.ibd ...

    2023-11-06 169
  • MySQL体系结构详解

    客户端应用程序:客户端应用程序是与MySQL数据库交互的用户或应用程序。这些应用程序使用MySQL客户端库来建立连接、发送SQL查询和接收查询结果。 SQL解释器:SQL解释器负责解析客户端应用程序发送的SQL查询语句,将其转换为内部数据结构,然后将其传递给查询优化器。 查询优化器:查询优化器是MySQL的核心组件之一。它分析SQL查询,确定最佳执行计划,并生成一组执行操作,以便从数据库中检索所需的数据。查询优化器考虑了表的索引、表之间的关系以及其他因素来提高查询性能。 存储引擎:MySQL支持多个存储引擎,每个存储引擎负责数据的物理存储和检索。常见的存储引擎包括: InnoDB:支持事务、行级锁定、外键和高并发性。 MyISAM:不支持事务,但具有快速读取性能。 Memory:将数据存储在内存中,用于快速读取和临时存储。 连接池:连接池是用于管理数据库连接的组件。它负责创建、维护和分配数据库连接,以降低连接建立和断开的开销,提高性能。 查询缓存:查询缓存用于存储已执行查询的结果集,以便在将来相同查询的情况下能够快速检索结果。不过,在高并发写入环境中,查询缓存可能会降低性能,因此有时会被禁用。 MySQL服务器:MySQL服务器是数据库管理系统的核心。它接收来自客户端应用程序的SQL查询,通过SQL解释器和查询优化器处理查询,然后将查询委托给适当的存储引擎执行。MySQL服务器还负责安全性、权限管理、事务控制、并发控制、崩溃恢复和日志记录等任务。 日志文件:MySQL使用多种日志文件来记录数据库活动,包括: 二进制日志(Binary Logs):记录所有更改数据的SQL语句,用于复制和恢复。 错误日志(Error Log):记录数据库错误和警告信息。 查询日志(Query Log):记录所有SQL查询,通常用于调试目的。 数据文件和表空间:数据文件是用于存储表数据和索引的物理文件。这些文件通常被组织成表空间,不同的存储引擎可以在不同的表空间中存储数据。 表和索引:表是MySQL数据库中的主要数据存储单元,它们包含了数据行。索引用于加速数据检索操作,提高查询性能。 系统变量和参数文件:MySQL具有一组系统变量,允许管理员配置数据库的行为。这些变量的配置信息通常存储在参数文件中,以便进行高级配置。 ...

    2023-11-06 179
  • MySQL有哪些锁

    大家好,我是不念,这次,来说说 MySQL 的锁,主要是 Q&A 的形式,看起来会比较轻松。 在 MySQL 里,根据加锁的范围,可以分为全局锁、表级锁和行锁三类。 全局锁 全局锁是怎么用的? 要使用全局锁,则要执行这条命令: flush tables with read lock 执行后,整个数据库就处于只读状态了,这时其他线程执行以下操作,都会被阻塞: 对数据的增删改操作,比如 insert、delete、update等语句; 对表结构的更改操作,比如 alter table、drop table 等语句。 如果要释放全局锁,则要执行这条命令: unlock tables 当然,当会话断开了,全局锁会被自动释放。 全局锁应用场景是什么? 全局锁主要应用于做全库逻辑备份,这样在备份数据库期间,不会因为数据或表结构的更新,而出现备份文件的数据与预期的不一样。 举个例子大家就知道了。 在全库逻辑备份期间,假设不加全局锁的场景,看看会出现什么意外的情况。 如果在全库逻辑备份期间,有用户购买了一件商品,一般购买商品的业务逻辑是会涉及到多张数据库表的更新,比如在用户表更新该用户的余额,然后在商品表更新被购买的商品的库存。 那么,有可能出现这样的顺序: 先备份了用户表的数据; 然后有用户发起了购买商品的操作; 接着再备份商品表的数据。 也就是在备份用户表和商品表之间,有用户购买了商品。 这种情况下,备份的结果是用户表中该用户的余额并没有扣除,反而商品表中该商品的库存被减少了,如果后面用这个备份文件恢复数据库数据的话,用户钱没少,而库存少了,等于用户白嫖了一件商品。 所以,在全库逻辑备份期间,加上全局锁,就不会出现上面这种情况了。 加全局锁又会带来什么缺点呢? 加上全局锁,意味着整个数据库都是只读状态。 那么如果数据库里有很多数据,备份就会花费很多的时间,关键是备份期间,业务只能读数据,而不能更新数据,这样会造成业务停滞。 既然备份数据库数据的时候,使用全局锁会影响业务,那有什么其他方式可以避免? 有的,如果数据库的引擎支持的事务支持可重复读的隔离级别,那么在备份数据库之前先开启事务,会先创建 Read View,然后整个事务执行期间都在用这个 Read View,而且由于 MVCC 的支持,备份期间业务依然可以对数据进行更新操作。 因为在可重复读的隔离级别下,即使其他事务更新了表的数据,也不会影响备份数据库时的 Read View,这就是事务四大特性中的隔离性,这样备份期间备份的数据一直是在开启事务时的数据。 备份数据库的工具是 mysqldump,在使用 mysqldump 时加上 –single-transaction 参数的时候,就会在备份数据库之前先开启事务。这种方法只适用于支持「可重复读隔离级别的事务」的存储引擎。 InnoDB 存储引擎默认的事务隔离级别正是可重复读,因此可以采用这种方式来备份数据库。 但是,对于 MyISAM 这种不支持事务的引擎,在备份数据库时就要使用全局锁的方法。 表级锁 MySQL 表级锁有哪些?具体怎么用的。 MySQL 里面表级别的锁有这几种: 表锁; 元数据锁(MDL); 意向锁; AUTO-INC 锁; 表锁 先来说说表锁。 如果我们想对学生表(t_student)加表锁,可以使用下面的命令: //表级别的共享锁,也就是读锁; lock tables t_student read; //表级别的独占锁,也就是写锁; lock tables t_stuent write; 需要注意的是,表锁除了会限制别的线程的读写外,也会限制本线程接下来的读写操作。 也就是说如果本线程对学生表加了「共享表锁」,那么本线程接下来如果要对学生表执行写操作的语句,是会被阻塞的,当然其他线程对学生表进行写操作时也会被阻塞,直到锁被释放。 要释放表锁,可以使用下面这条命令,会释放当前会话的所有表锁: unlock tables 另外,当会话退出后,也会释放所有表锁。 不过尽量避免在使用 InnoDB 引擎的表使用表锁,因为表锁的颗粒度太大,会影响并发性能,InnoDB 牛逼的地方在于实现了颗粒度更细的行级锁。 元数据锁 再来说说元数据锁(MDL)。 我们不需要显示的使用 MDL,因为当我们对数据库表进行操作时,会自动给这个表加上 MDL: 对一张表进行 CRUD 操作时,加的是 MDL 读锁; 对一张表做结构变更操作的时候,加的是 MDL 写锁; MDL 是为了保证当用户对表执行 CRUD 操作时,防止其他线程对这个表结构做了变更。 当有线程在执行 select 语句( 加 MDL 读锁)的期间,如果有其他线程要更改该表的结构( 申请 MDL 写锁),那么将会被阻塞,直到执行完 select 语句( 释放 MDL 读锁)。 反之,当有线程对表结构进行变更( 加 MDL 写锁)的期间,如果有其他线程执行了 CRUD 操作( 申请 MDL 读锁),那么就会被阻塞,直到表结构变更完成( 释放 MDL 写锁)。 MDL 不需要显示调用,那它是在什么时候释放的? MDL 是在事务提交后才会释放,这意味着事务执行期间,MDL 是一直持有的。 那如果数据库有一个长事务(所谓的长事务,就是开启了事务,但是一直还没提交),那在对表结构做变更操作的时候,可能会发生意想不到的事情,比如下面这个顺序的场景: 首先,线程 A 先启用了事务(但是一直不提交),然后执行一条 select 语句,此时就先对该表加上 MDL 读锁; 然后,线程 B 也执行了同样的 select 语句,此时并不会阻塞,因为「读读」并不冲突; 接着,线程 C 修改了表字段,此时由于线程 A 的事务并没有提交,也就是 MDL 读锁还在占用着,这时线程 C 就无法申请到 MDL 写锁,就会被阻塞, 那么在线程 C 阻塞后,后续有对该表的 select 语句,就都会被阻塞,如果此时有大量该表的 select 语句的请求到来,就会有大量的线程被阻塞住,这时数据库的线程很快就会爆满了。 为什么线程 C 因为申请不到 MDL 写锁,而导致后续的申请读锁的查询操作也会被阻塞? 这是因为申请 MDL 锁的操作会形成一个队列,队列中写锁获取优先级高于读锁,一旦出现 MDL 写锁等待,会阻塞后续该表的所有 CRUD 操作。 所以为了能安全的对表结构进行变更,在对表结构变更前,先要看看数据库中的长事务,是否有事务已经对表加上了 MDL 读锁,如果可以考虑 kill 掉这个长事务,然后再做表结构的变更。 意向锁 接着,说说意向锁。 在使用 InnoDB 引擎的表里对某些记录加上「共享锁」之前,需要先在表级别加上一个「意向共享锁」; 在使用 InnoDB 引擎的表里对某些纪录加上「独占锁」之前,需要先在表级别加上一个「意向独占锁」; 也就是,当执行插入、更新、删除操作,需要先对表加上「意向独占锁」,然后对该记录加独占锁。 而普通的 select 是不会加行级锁的,普通的 select 语句是利用 MVCC 实现一致性读,是无锁的。 不过,select 也是可以对记录加共享锁和独占锁的,具体方式如下: //先在表上加上意向共享锁,然后对读取的记录加共享锁 select ... lock in share mode; //先表上加上意向独占锁,然后对读取的记录加独占锁 select ... for update; 意向共享锁和意向独占锁是表级锁,不会和行级的共享锁和独占锁发生冲突,而且意向锁之间也不会发生冲突,只会和共享表锁(lock tables … read)和独占表锁(lock tables … write)发生冲突。 表锁和行锁是满足读读共享、读写互斥、写写互斥的。 如果没有「意向锁」,那么加「独占表锁」时,就需要遍历表里所有记录,查看是否有记录存在独占锁,这样效率会很慢。 那么有了「意向锁」,由于在对记录加独占锁前,先会加上表级别的意向独占锁,那么在加「独占表锁」时,直接查该表是否有意向独占锁,如果有就意味着表里已经有记录被加了独占锁,这样就不用去遍历表里的记录。 所以,意向锁的目的是为了快速判断表里是否有记录被加锁。 AUTO-INC 锁 表里的主键通常都会设置成自增的,这是通过对主键字段声明 AUTO_INCREMENT 属性实现的。 之后可以在插入数据时,可以不指定主键的值,数据库会自动给主键赋值递增的值,这主要是通过 AUTO-INC 锁实现的。 AUTO-INC 锁是特殊的表锁机制,锁不是再一个事务提交后才释放,而是再执行完插入语句后就会立即释放。 在插入数据时,会加一个表级别的 AUTO-INC 锁,然后为被 AUTO_INCREMENT 修饰的字段赋值递增的值,等插入语句执行完成后,才会把 AUTO-INC 锁释放掉。 那么,一个事务在持有 AUTO-INC 锁的过程中,其他事务的如果要向该表插入语句都会被阻塞,从而保证插入数据时,被 AUTO_INCREMENT 修饰的字段的值是连续递增的。 但是, AUTO-INC 锁再对大量数据进行插入的时候,会影响插入性能,因为另一个事务中的插入会被阻塞。 因此, 在 MySQL 5.1.22 版本开始,InnoDB 存储引擎提供了一种轻量级的锁来实现自增。 一样也是在插入数据的时候,会为被 AUTO_INCREMENT 修饰的字段加上轻量级锁,然后给该字段赋值一个自增的值,就把这个轻量级锁释放了,而不需要等待整个插入语句执行完后才释放锁。 InnoDB 存储引擎提供了个 innodb_autoinc_lock_mode 的系统变量,是用来控制选择用 AUTO-INC 锁,还是轻量级的锁。 当 innodb_autoinc_lock_mode = 0,就采用 AUTO-INC 锁,语句执行结束后才释放锁; 当 innodb_autoinc_lock_mode = 2,就采用轻量级锁,申请自增主键后就释放锁,并不需要等语句执行后才释放。 当 innodb_autoinc_lock_mode = 1: 普通 insert 语句,自增锁在申请之后就马上释放; 类似 insert … select 这样的批量插入数据的语句,自增锁还是要等语句结束后才被释放; 当 innodb_autoinc_lock_mode = 2 是性能最高的方式,但是当搭配 binlog 的日志格式是 statement 一起使用的时候,在「主从复制的场景」中会发生数据不一致的问题。 举个例子,考虑下面场景: session A 往表 t 中插入了 4 行数据,然后创建了一个相同结构的表 t2,然后两个 session 同时执行向表 t2 中插入数据。 如果 innodb_autoinc_lock_mode = 2,意味着「申请自增主键后就释放锁,不必等插入语句执行完」。那么就可能出现这样的情况: session B 先插入了两个记录,(1,1,1)、(2,2,2); 然后,session A 来申请自增 id 得到 id=3,插入了(3,5,5); 之后,session B 继续执行,插入两条记录 (4,3,3)、 (5,4,4)。 可以看到,session B 的 insert 语句,生成的 id 不连续。 当「主库」发生了这种情况,binlog 面对 t2 表的更新只会记录这两个 session 的 insert 语句,如果 binlog_format=statement,记录的语句就是原始语句。记录的顺序要么先记 session A 的 insert 语句,要么先记 session B 的 insert 语句。 但不论是哪一种,这个 binlog 拿去「从库」执行,这时从库是按「顺序」执行语句的,只有当执行完一条 SQL 语句后,才会执行下一条 SQL。因此,在从库上「不会」发生像主库那样两个 session 「同时」执行向表 t2 中插入数据的场景。所以,在备库上执行了 session B 的 insert 语句,生成的结果里面,id 都是连续的。这时,主从库就发生了数据不一致。 要解决这问题,binlog 日志格式要设置为 row,这样在 binlog 里面记录的是主库分配的自增值,到备库执行的时候,主库的自增值是什么,从库的自增值就是什么。 所以,当 innodb_autoinc_lock_mode = 2 时,并且 binlog_format = row,既能提升并发性,又不会出现数据一致性问题。 行级锁 InnoDB 引擎是支持行级锁的,而 MyISAM 引擎并不支持行级锁。 前面也提到,普通的 select 语句是不会对记录加锁的,因为它属于快照读。如果要在查询时对记录加行锁,可以使用下面这两个方式,这种查询会加锁的语句称为锁定读。 //对读取的记录加共享锁 select ... lock in share mode; //对读取的记录加独占锁 select ... for update; 上面这两条语句必须在一个事务中,因为当事务提交了,锁就会被释放,所以在使用这两条语句的时候,要加上 begin、start transaction 或者 set autocommit = 0。 共享锁(S锁)满足读读共享,读写互斥。独占锁(X锁)满足写写互斥、读写互斥。 行级锁的类型主要有三类: Record Lock,记录锁,也就是仅仅把一条记录锁上; Gap Lock,间隙锁,锁定一个范围,但是不包含记录本身; Next-Key Lock:Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。 Record Lock Record Lock 称为记录锁,锁住的是一条记录。而且记录锁是有 S 锁和 X 锁之分的: 当一个事务对一条记录加了 S 型记录锁后,其他事务也可以继续对该记录加 S 型记录锁(S 型与 S 锁兼容),但是不可以对该记录加 X 型记录锁(S 型与 X 锁不兼容); 当一个事务对一条记录加了 X 型记录锁后,其他事务既不可以对该记录加 S 型记录锁(S 型与 X 锁不兼容),也不可以对该记录加 X 型记录锁(X 型与 X 锁不兼容)。 举个例子,当一个事务执行了下面这条语句: mysql > begin; mysql > select * from t_test where id = 1 for update; 就是对 t_test 表中主键 id 为 1 的这条记录加上 X 型的记录锁,这样其他事务就无法对这条记录进行修改了。 当事务执行 commit 后,事务过程中生成的锁都会被释放。 Gap Lock Gap Lock 称为间隙锁,只存在于可重复读隔离级别,目的是为了解决可重复读隔离级别下幻读的现象。 假设,表中有一个范围 id 为(3,5)间隙锁,那么其他事务就无法插入 id = 4 这条记录了,这样就有效的防止幻读现象的发生。 间隙锁虽然存在 X 型间隙锁和 S 型间隙锁,但是并没有什么区别,间隙锁之间是兼容的,即两个事务可以同时持有包含共同间隙范围的间隙锁,并不存在互斥关系,因为间隙锁的目的是防止插入幻影记录而提出的。 Next-Key Lock Next-Key Lock 称为临键锁,是 Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。 假设,表中有一个范围 id 为(3,5] 的 next-key lock,那么其他事务即不能插入 id = 4 记录,也不能修改 id = 5 这条记录。 所以,next-key lock 即能保护该记录,又能阻止其他事务将新纪录插入到被保护记录前面的间隙中。 next-key lock 是包含间隙锁+记录锁的,如果一个事务获取了 X 型的 next-key lock,那么另外一个事务在获取相同范围的 X 型的 next-key lock 时,是会被阻塞的。 比如,一个事务持有了范围为 (1, 10] 的 X 型的 next-key lock,那么另外一个事务在获取相同范围的 X 型的 next-key lock 时,就会被阻塞。 虽然相同范围的间隙锁是多个事务相互兼容的,但对于记录锁,我们是要考虑 X 型与 S 型关系,X 型的记录锁与 X 型的记录锁是冲突的。 插入意向锁 一个事务在插入一条记录的时候,需要判断插入位置是否已被其他事务加了间隙锁(next-key lock 也包含间隙锁)。 如果有的话,插入操作就会发生阻塞,直到拥有间隙锁的那个事务提交为止(释放间隙锁的时刻),在此期间会生成一个插入意向锁,表明有事务想在某个区间插入新记录,但是现在处于等待状态。 举个例子,假设事务 A 已经对表加了一个范围 id 为(3,5)间隙锁。 当事务 A 还没提交的时候,事务 B 向该表插入一条 id = 4 的新记录,这时会判断到插入的位置已经被事务 A 加了间隙锁,于是事物 B 会生成一个插入意向锁,然后将锁的状态设置为等待状态(PS:MySQL 加锁时,是先生成锁结构,然后设置锁的状态,如果锁状态是等待状态,并不是意味着事务成功获取到了锁,只有当锁状态为正常状态时,才代表事务成功获取到了锁),此时事务 B 就会发生阻塞,直到事务 A 提交了事务。 插入意向锁名字虽然有意向锁,但是它并不是意向锁,它是一种特殊的间隙锁,属于行级别锁。 如果说间隙锁锁住的是一个区间,那么「插入意向锁」锁住的就是一个点。因而从这个角度来说,插入意向锁确实是一种特殊的间隙锁。 插入意向锁与间隙锁的另一个非常重要的差别是:尽管「插入意向锁」也属于间隙锁,但两个事务却不能在同一时间内,一个拥有间隙锁,另一个拥有该间隙区间内的插入意向锁(当然,插入意向锁如果不在间隙锁区间内则是可以的)。 ...

    2023-11-05 189
  • 主从延时的原因及解决方案

    主从延迟情况 我们先看看,哪些情况会导致主从延时: 从库机器性能:从库机器比主库的机器性能差,只需选择主从库一样规格的机器就好。 从库压力大:可以搞了一主多从的架构,还可以把 binlog 接入到 Hadoop 这类系统,让它们提供查询的能力。 从库过多:要避免复制的从节点数量过多,从库数据一般以3-5个为宜。 大事务:如果一个事务执行就要 10 分钟,那么主库执行完后,给到从库执行,最后这个事务可能就会导致从库延迟 10 分钟啦。日常开发中,不要一次性 delete 太多 SQL,需要分批进行,另外大表的 DDL 语句,也会导致大事务。 网络延迟:优化网络,比如带宽 20M 升级到 100M。 MySQL 版本低:低版本的 MySQL 只支持单线程复制,如果主库并发高,来不及传送到从库,就会导致延迟,可以换用更高版本的 MySQL,支持多线程复制。 主从延时解决方案 面试时,有些同学能回答出使用缓存、查询主库、提升机器配置等,仅仅这些么? 最容易想到的方法,缩短主从同步时间: 提升从库机器配置,可以和主库一样,甚至更好; 避免大事务; 搞多个从库,即一主多从,分担从库查询压力; 优化网络宽带; 选择高版本 MySQL,支持主库 binlog 多线程复制。 也可以从业务场景考虑: 使用缓存:我们在同步写数据库的同时,也把数据写到缓存,查询数据时,会先查询缓存,不过这种情况会带来 MySQL 和 Redis 数据一致性问题。 查询主库:直接查询主库,这种情况会给主库太大压力,核心场景可以使用,比如订单支付。 如果能把上面基本回答出来,就已经非常厉害了,还有么? 其实还可以在 MySQL 架构上来考虑。 主库对数据安全性较高,设置配置如下: sync_binlog = 1 innodb_flush_log_at_trx_commit = 1 而 slave 不需要这么高的数据安全,完全可以将 sync_binlog 设置为 0,或者关闭 binlog,innodb_flushlog 也可以设置为 0,来提高 sql 的执行效率。 架构方案:使用多台 slave 来分摊读请求,再从这些 slave 中取一台专用的服务器,只作为备份用,不进行其他任何操作,比如设置 sync_binlog 为0,或者关闭 binglog 等,提升从库查询性能。 ...

    2023-11-03 169
  • 主从延迟的原因

    探讨这个问题前,我们需要知道主从复制的原理。 主从复制原理 MySQL 的主从复制是依赖于 binlog,也就是记录 MySQL 上的所有变化并以二进制形式保存在磁盘上二进制日志文件。 主从复制就是将 binlog 中的数据从主库传输到从库上,一般这个过程是异步的,即主库上的操作不会等待 binlog 同步地完成。 详细流程如下: 主库写 binlog:主库的更新 SQL(update、insert、delete) 被写到 binlog; 主库发送 binlog:主库创建一个 log dump 线程来发送 binlog 给从库; 从库写 relay log:从库在连接到主节点时会创建一个 IO 线程,以请求主库更新的 binlog,并且把接收到的 binlog 信息写入一个叫做 relay log 的日志文件; 从库回放:从库还会创建一个 SQL 线程读取 relay log 中的内容,并且在从库中做回放,最终实现主从的一致性。 主从延时原因 我们分析一下主从复制的过程。 MySQL 的主从复制都是单线程的操作,主库对所有 DDL 和 DML 产生 binlog,binlog 是顺序写,所以效率很高。 Slave 的 Slave_IO_Running 线程会到主库取日志,放入 relay log,效率会比较高。 Slave 的 Slave_SQL_Running 线程将主库的 DDL 和 DML 操作都在 Slave 实施,DML 和 DDL 的 IO 操作是随机的,不是顺序的,因此成本会很高。 还可能是 Slave 上的其他查询产生 lock 争用,由于 Slave_SQL_Running 也是单线程的,所以一个 DDL 卡住了,需要执行 10 分钟,那么所有之后的 DDL 会等待这个 DDL 执行完才会继续执行,这就导致了延时。 总结一下主从延迟的主要原因:主从延迟主要是出现在 “relay log 回放” 这一步,当主库的 TPS 并发较高,产生的 DDL 数量超过从库一个 SQL 线程所能承受的范围,那么延时就产生了,当然还有就是可能与从库的大型 query 语句产生了锁等待。 ...

    2023-11-03 157
  • 什么是主从延时?

    有时候我们遇到从数据库中获取不到信息的诡异问题时,会纠结于代码中是否有一些逻辑会把之前写入的内容删除,但是你又会发现,过了一段时间再去查询时又可以读到数据了,这基本上就是主从延迟在作怪。 主从延迟,其实就是“从库回放” 完成的时间,与 “主库写 binlog” 完成时间的差值,会导致从库查询的数据,和主库的不一致。 ...

    2023-11-03 167
  • MySQL数据库事务是什么

    什么是事务 数据库的事务是一种机制,一个操作序列,包含了一组操作命令 事务把所有的命令作为一个整体一起向系统提交或撤销操作请求,即这一组数据库命令,要么同时成功,要么同时失败 事务是一个不可分割的工作逻辑单元 为什么需要事务 事务的主要目的是确保数据库操作的一致性和完整性。下面是一个简单的例子来解释为什么需要事务。 假设有一个银行系统,其中有两个账户 A 和 B,当前账户 A 的余额为 1000 元,账户 B 的余额为 2000 元。现在有两个用户同时进行转账操作,一个用户从账户 A 向账户 B 转账 500 元,另一个用户从账户 B 向账户 A 转账 700 元。 如果没有事务的支持,那么这两个转账操作可以并发执行,可能会导致以下问题: 并发问题:在没有事务的情况下,两个用户同时进行转账操作时,可能会出现竞争条件。例如,如果用户 A 首先读取账户 A 的余额为 1000 元,在用户 B 读取账户 B 的余额为 2000 元之前执行转账操作,那么用户 A 的转账操作会以账户 A 余额为 1000 元进行计算,导致账户 A 的余额不正确。 数据不一致:如果两个转账操作不在同一个事务中,当第一个转账操作成功并提交后,而第二个转账操作失败并中止,会导致账户 A 和账户 B 的余额不一致。 数据丢失:如果没有事务支持,当一个转账操作成功时,另一个转账操作发生错误并中止,导致其中一个用户的转账款项丢失。 通过使用事务,可以解决上述问题。事务可以确保这两个转账操作要么全部成功,要么全部失败。 如果其中一个转账操作失败,事务可以回滚到事务开始之前的状态,保证数据的一致性。 同时,事务还可以提供隔离性,使得并发执行的转账操作相互不影响。 事务的四大特性 ...

    2023-11-02 144
  • 什么是数据复制,有哪些架构

    数据复制是指将数据复制到一个或多个数据容器以确保可用性的过程。 复制的数据通常存储在不同的数据库实例中,即使一个实例发生故障,我们也可以从其他实例获取数据。 一种流行数据复制的实现架构是主从架构。 主从架构 为了理解这个架构,我们举一个例子。 我们有四个客户端,每个客户端都连接到一个负载均衡器。 然后负载均衡器将请求分发到三个应用程序服务器。 每台服务器连接到一个数据库实例。 你能注意到这里有什么问题吗? 我们的数据库存在单点故障。如果它崩溃了,我们的整个系统就会停止工作。 为了避免这种单点故障,我们可以使用另一个数据库(最好是不同的数据库实例)来存储原始数据的副本(一般我们成为从库)。现在如果原始数据库(主库)崩溃,我们可以将请求转到从库。 但是我们如何保持从库与主库同步呢?这有两种方法。 同步复制数据 在这种方法中,数据同时写入主库和从库 数据始终一致。即数据如果写入主库,它也会写入从库 数据库负载较高 异步复制数据 在这种方法中,首先将数据写入主库,并定期将更新写入从库 由于复制以固定间隔进行,因此存在数据丢失和不一致的可能性 数据库负载相对较低 这里我们的一般定义是收到写请求的主库数据库是 master,从库被称为 slaves。 如上图我们的主站也就是 Server2 维护事务日志。他会更新从站中(Server1)的数据,它发送命令,然后从站以相同的顺序执行这些命令。 如果服务器向从站发送写入请求会发生什么? 有两种方法可以处理这种情况 不允许对从站的写请求,从站无法写入数据库,它只能去读从库数据。 允许从站写入数据。我们将允许从站写入数据。然后从站将更改复制到主站。在这种情况下,从站就接替了主站的角色。所以不再是主从架构而是主主架构 主主架构的问题 网络故障可能会导致主主架构中的数据不一致。 让我们用一个例子来理解这一点,假设我们有两个数据库实例 A 和 B。 两人都是 master。 它们之间的路由器出现故障。所以 A 认为 B 离线,B 认为 A 离线。 他们有一个数据项 X,其值最初为 100。 现在用户发送以下请求, X 减去 20,该请求被路由到 A,此时 A 中 X 的值为 80。 X 减去 80,这个请求被路由到 B(因为都是 master,所以写请求可以路由到任何数据库)。现在 B 中 X 的值为 20。“由于存在通信故障,A 和 B 无法同步,它们具有不同的数据值,因此不一致。” 现在,如果用户发出读请求,他/她将获得不同的值,具体取决于他/她将连接到的数据库。 这个问题被称为裂脑问题。 解决裂脑问题 我们可以通过添加第三个节点(数据库实例)来解决裂脑问题。 这里我们假设一个节点崩溃以及其他两个节点之间的路由器崩溃的可能性极小。 让我们考虑三个数据库实例 A、B 和 C。 如果 C 崩溃,A 和 B 是主库并且它们是同步的。所以他们处于一致的状态。当 C 在线时,他们可以读取 A 或 B 的内容。 如果 A 和 B 之间出现通信故障 当 A 收到写入请求时,它将其状态传播到 C。最初状态为 S0,然后转移到 Sx。所以现在 A 和 C 都有 Sx。 当 B 收到写入请求时,它将其状态从 S0 移至 Sy。它尝试将其状态传播到 C,但失败,因为 B 的先前状态不等于 C。现在 B 中止写入请求并将其状态更新为 Sx。现在 B 可以接受写入请求并将更改传播到 C。 这称为分布式共识。多个节点就特定值达成一致。在这种情况下,A、B 和 C 在最终状态上达成一致。 最后 感谢您的阅读,希望本文能对你理解分布式架构中的数据复制有所帮助。 ...

    2023-11-02 170
  • MySQL: Binlog复制如何安全地跳过错误事务

    MySQL是一个功能强大的开源关系数据库管理系统,它提供了二进制日志(Binlog)复制功能,帮助数据库管理员在主从架构中同步数据。 然而,在实际运营过程中,可能会遇到由于某些错误事务而导致复制过程中断的情况。 在确认是单独的错误事务导致问题后,我们可以在从服务器(Slave)上采取措施来跳过该错误事务,然后继续复制过程。 首先,我们需要停止从服务器上的复制过程,以确保不会有新的数据被复制过来。 可以通过执行以下命令来停止复制: STOP REPLICA; 接下来,我们需要设置全局变量sql_slave_skip_counter,以指定要跳过的错误事务数量。 通常情况下,如果只有一个错误事务,我们可以将该变量设置为1: SET GLOBAL sql_slave_skip_counter = 1; 然后,我们可以重新启动复制过程,以继续复制后续的事务: START REPLICA; 为了验证我们的操作是否成功,可以通过以下命令检查复制的状态和sql_slave_skip_counter的值: SHOW REPLICA STATUS\G show variables like 'sql_slave_skip_counter'; 一旦复制应用启动,GLOBAL sql_slave_skip_counter变量会被重置为0。这意味着,如果在将来再次遇到需要跳过的错误事务,我们需要再次设置这个变量。 虽然我们可以将sql_slave_skip_counter设置为一个非常大的值,以确保启动后所有错误都会被忽略,但这并不是一个推荐的做法。这样做可能会忽略掉所有的错误事务,包括那些可能会影响数据完整性或系统稳定性的重要错误,甚至会错过正常的事务导致数据丢失。 因此,通常建议仅在清楚知道错误事务的性质和影响时,才使用sql_slave_skip_counter来跳过错误事务。 总结来说,通过理解和应用sql_slave_skip_counter变量,我们可以在遇到错误事务时,有选择地跳过它们,以保持复制过程的连续性。 但同时,我们也应该注意不要滥用这个功能,以避免产生不可预见的问题。 在处理复制错误时,应该先尝试找出并解决错误的根本原因,而不是简单地跳过错误事务。 通过这样的实践,我们可以确保我们的MySQL复制环境更加健壮和可靠。 ...

    2023-10-22 185
  • Windows安装MySQL数据库步骤

    浏览器输入网址:https://www.mysql.com/downloads下载MySQL软件包 根据图片安装MySQL软件 勾选同意,点击Next 选择只安装服务,然后点击Next 点击Execute 选择服务后点击Next 如图所示设置,点击Next 设置登录密码后,点击Next MySQL57是服务名称,可以根据爱好设置,点击Next 默认,点击Next 默认,点击Execute 点击finish,表示软件安装完成 找到软件目录下的bin目录 开始->计算机->属性->高级系统设置->环境变量 ,把mysql的bin目录加入到path 开始->cmd->输入登录账户和密码,看到如图界面,表示MySQL服务安装完成 注意:不同MySQL版本安装略有不同,但是总体大同小异,大家一起开始MySQL数据库的学习之旅吧! ...

    2023-10-14 171
  • Java 字符串常量池

    文章目录 1.Java中的不可变字符串 2.Java中的String常量池是什么? 3.字符串文字和字符串对象的区别 4.String.intern() API 5.优点 5.1. 增强的安全性 5.2. 线程安全性 6.缺点 6.1. 无法扩展String类 6.2. 长时间内存中的敏感数据 6.3. 可能的OutOfMemoryError 了解Java中的String类,创建它的不可变性背后的动机,以及String常量池的概念。我们将看到当我们通过String文字或String构造函数创建String实例时,内存是如何被操作的。最后,我们将讨论String类的不可变性引起的主要优点和缺点。 1.Java中的不可变字符串 字符串是字符序列。在Java中,与其他编程语言类似,字符串是预定义类型的一部分。Java有java.lang.String类,其实例表示字符串。 String类是一个不可变类。不可变意味着一旦创建了String实例,就无法更改它。 通常,许多敏感信息(用户名、密码、URL、端口、数据库、套接字连接)被表示并传递为字符串。通过使这些信息不可变,代码就能够免受各种安全威胁的影响。 字符串的不可变性还允许缓存字符串文字,这允许应用程序在堆内存和垃圾收集器上产生最小的影响的情况下使用大量的字符串文字。 在可变的上下文中,修改字符串文字可能导致变量损坏。 2.Java中的String常量池是什么? 在Java中,内存被分为三个部分,即堆、栈和字符串池。字符串常量池是用于存储字符串文字的特殊区域。 请注意,在Java 7之前,字符串池是永久代内存区的一部分。 从Java 7开始,字符串与应用程序创建的其他对象一起分配在Java堆区域中。 随后,在Java 8中,永久代已完全删除。 因此,在最新的JVM中,字符串池是堆内存中的一个特殊区域,用于存储字符串文字。 尽管字符串池已从永久代空间移动到堆内存区域,但围绕字符串的创建、文字、对象和内部化的所有概念都没有改变。   3.字符串文字和字符串对象的区别 在Java中,字符串文字是使用双引号创建的字符串,而字符串对象是使用new()运算符创建的字符串。 需要注意的是,字符串文字是在字符串池区域创建的,而字符串对象是在堆内存区域创建的。 String strLiteral = "Hello World"; String strObj = new String("Hello World"); 假设我们想创建两个具有相同内容“panziye.com”的字符串。如果已经存在一个内容为“panziye.com”的字符串,那么新的文字将指向已经存在的文字。而对于字符串对象,每次都会在堆内存中创建一个新的字符串对象。 让我们看一个示例: String a = "panziye.com"; String b = "panziye.com"; System.out.println(a == b); //true 在上面的程序中,我们创建了两个具有相同内容的字符串文字。在字符串池中创建了’a’之后,下一个字符串文字’b’指向了内存中的同一个对象,所以’a == b’是true。这是因为Java中的字符串文字会被重用,以节省内存空间。 String a = "panziye.com"; String b = "panziye.com"; System.out.println(a == b); String c = new String("panziye.com"); System.out.println(a == b); //true System.out.println(b == c); //false 在上面的程序中,我们创建了一个具有类似内容的新字符串对象。当我们检查对象引用是否相等时,我们看到’b’和’c’指向不同的对象。这意味着当我们创建字符串对象’c’时,在内存中创建了一个新的对象。这是因为每次使用new关键字创建字符串对象时,都会在堆内存中分配一个新的对象。这与字符串文字不同,字符串文字在字符串池中被重用。 4.String.intern() API 我们知道字符串文字是在字符串池中创建的,而字符串对象是在堆内存区域中创建的。 我们可以使用String.intern()方法为字符串对象创建字符串文字。当在字符串对象上调用intern()方法时,它会在堆内存中创建一个String对象的精确副本,并将其存储在字符串常量池中。 String a = "panziye"; String b = "panziye"; String c = new String("panziye"); String d = c.intern(); 在上面的例子中,字符串a、b和d将引用SCP中相同的字符串文字。而字符串c将继续指向堆内的对象。 5.优点 5.1. 增强的安全性 正如前面所述,字符串池允许字符串不可变。不可变对象有助于使应用程序更安全,因为它们可能存储敏感信息。 由于我们无法更改不可变对象,这有助于提高安全性。 5.2. 线程安全性 字符串可能是Java应用程序中最常用的对象。想象一下,如果字符串是可变的。在这种情况下,在应用程序中管理线程安全将会成为一场噩梦。 任何不可变对象都具有天生的线程安全性。这意味着多个线程可以共享和操作字符串,而无需担心损坏和不一致性。 6.缺点 6.1. 无法扩展String类 如果我们想扩展String类以添加更多功能,那是不可能的。不可变类被声明为final以防止扩展。 但幸运的是,我们有许多第三方库(如Apache Commons Lang、Spring Framework、Guava),它们为几乎所有种类的用途提供了出色的实用程序类。 6.2. 长时间内存中的敏感数据 字符串中的敏感数据(例如密码)可能会在内存中(在字符串常量池中)驻留更长时间,因为字符串常量池受到垃圾收集器的特殊处理。垃圾收集器不会像访问其他内存区域那样频繁(周期性)访问字符串常量池。 由于这种特殊处理,敏感数据会在字符串常量池中保存很长时间,可能会容易受到不希望的使用。 为了避免这种潜在的缺点,建议将敏感数据(例如密码)存储在char[]中,而不是String中。 6.3. 可能的OutOfMemoryError 字符串常量池与其他内存区域相比是一个小内存区域,可能会很快填满。将太多字符串文字存储在字符串常量池中会导致OutOfMemoryError。 ...

    2023-09-16 171

联系我们

在线咨询:点击这里给我发消息

QQ交流群:KirinBlog

工作日:8:00-23:00,节假日休息

扫码关注