分类 技术教程 下的文章

逆向剖析偏向第二篇

Flowable与springBoot项目整合及泛起的问题

单纯地将Flowable和springBoot整合,使用mysql作为数据库,整合中踩了两个坑,见文末。
在pom中添加依赖



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.2.0.RELEASE
         
    
    com.happen
    flowable1
    0.0.1-SNAPSHOT
    flowable1
    Demo project for Spring Boot
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        

        
        
            org.flowable
            flowable-spring-boot-starter
            6.6.0
        


        
            mysql
            mysql-connector-java
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


application.yml文件
database-schema-update: true的作用是自动更新数据库中需要的表,在第一次运行时需要

server:
  port: 8000

web:
  domain: http://localhost

spring:
  datasource:
    driverClassName: com.mysql.cj.jdbc.Driver
    username: root
    password: WHP199617whp
    url: jdbc:mysql://localhost:3306/flowable1?useUnicode=true&characterEncoding=utf8&autoReconnect=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true

flowable:
  async-executor-activate: false
  database-schema-update: true

Flowable1Application
对数据库中的流程数目举行查询

MySQL提升条记(3)日志文件详解

package com.happen.flowable1;

import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication(proxyBeanMethods = false)
public class Flowable1Application {

    public static void main(String[] args) {
        SpringApplication.run(Flowable1Application.class, args);
    }

    @Bean
    public CommandLineRunner init(final RepositoryService repositoryService,
                                  final RuntimeService runtimeService,
                                  final TaskService taskService) {

        return new CommandLineRunner() {
            @Override
            public void run(String... strings) throws Exception {
                System.out.println("Number of process definitions : "
                        + repositoryService.createProcessDefinitionQuery().count());
                System.out.println("Number of tasks : " + taskService.createTaskQuery().count());
                runtimeService.startProcessInstanceByKey("oneTaskProcess");
                System.out.println("Number of tasks after process start: "
                        + taskService.createTaskQuery().count());
            }
        };
    }
}

xml文件,这是一个 BPMN 2.0的尺度文件




    
        
        
        
        
        
    


完整的项目目录如下:

运行效果

会在数据库中天生对应的表

控制台中:

遇到的坑

  1. 建表的时刻泛起 table 'flowable1.act_id_user' doesn't exist
    这是由于之前本机上建过相同的表,现在不许重复建表了?在数据库设置时后面追加&nullCatalogMeansCurrent=true即可
  2. nested exception is org.flowable.common.engine.api.FlowableException: Error initialising eventregistry data model
    将springboot版本设置为2.2.0.RELEASE即可(我试了2.4.5就是不行,真坑,不行就删了数据库中的所有表再试试)。

python基础(弥补):lambda匿名函数,用了的,都说好!

Flowable与springBoot项目整合及出现的问题

Windows平台上的EXE(可执行程序)遵从的PE结构部门学习总结

下面给出PE结构图(来自bing搜索):

上述PE结构的WORD代表单字操作符,DWORD代表双字操作符

 首先用二进制/十六进制编辑器查看sample.exe的代码(如图):

   

————————————————————————————————————————————————————————————— 

MySQL提升条记(3)日志文件详解

一个字节(Byte)即是8位(bit);

16进制数转换为二进制数时的对应关系是:四位对应一个16进制数;

以是一个字节就示意为2个十六进制数;

这里又指出:WORD是单字节操作符,DWORD是双字节操作符;

则:WORD所代表的单字节操作符则用2个十六进制数示意;

  DWORD所代表的双字节操作符则用四个十六进制数示意。

——————————————————————————————————————————————————————————————

 

python基础(弥补):lambda匿名函数,用了的,都说好!

逆向分析方向第二篇

在MySQL数据库和InnoDB存储引擎中,有许多种文件,如:参数文件、日志文件、socket文件、pid文件、MySQL表结构文件、存储引擎文件。

本节重点关注日志文件,MySQL的复制、事务等主要功效都和日志文件相关。日志文件主要包罗错误日志文件二进制日志文件慢查询日志文件查询日志文件重做日志文件等。其中重做日志文件是InnoDB引擎文件。

1、日志文件先容

1.1、错误日志(error log)

错误日志文件对MySQL的启动、运行、关闭历程举行了纪录,是定位MySQL问题的第一把钥匙。

1.2、慢查询日志(slow query log)

慢查询日志是用来纪录执行时间跨越 long_query_time 这个变量界说的时长的查询语句。通过慢查询日志,可以查找出哪些查询语句的执行效率很低,以便举行优化。

1.3、一样平常查询日志(general log)

一样平常查询日志纪录了所有对MySQL数据库请求的信息,无论请求是否准确执行。

默认情形下,general log 是关闭的,开启通用查询日志会增添许多磁盘 I/O, 以是如非出于调试排错目的,不建议开启通用查询日志。

1.4、二进制日志(bin log)

关于二进制日志,它纪录了数据库所有执行的DDL和DML语句(除了数据查询语句select、show等),以事宜形式纪录并保留在二进制文件中。

  • log_bin:指定binlog是否开启及文件名称。
  • server_id:指定服务器唯一ID,开启binlog 必须设置此参数。
  • binlog_format:指定binlog模式,建议设置为ROW。
  • max_binlog_size:控制单个二进制日志巨细,当前日志文件巨细跨越此变量时,执行切换动作。
  • expire_logs_days:控制二进制日志文件保留天数,默认值为0,示意不自动删除,可设置为0~99。

二进制日志文件是异常主要的日志文件,建议开启,二进制日志主要有这么几个作用:

  • 恢复:行使二进制文件恢复数据,原理是取出日志的操作纪录,重新执行

  • 复制:和恢回复理类似,一样平常分为主库和从库。
  • 审计: 通过考察二进制文件,可以判断是否存在对数据库有危险性的操作。

1.5、重做日志(redo log)

对于InnoDB,重做日志至关主要,由于它们纪录了对于InnoDB存储引擎的事务日志。

当实例或介质失败时,如数据库由于所在主机断电导致实例失败,InnoDB存储引擎就会恢复到断电前的时刻,以此来保证数据的完整性。

InnoDB引擎对数据的更新,是先将更新纪录写入redo log日志,然后会在系统空闲的时刻或者是根据设定的更新计谋再将日志中的内容更新到磁盘之中。这就是所谓的预写式手艺(Write Ahead logging)。这种手艺可以大大削减IO操作的频率,提升数据刷新的效率。

写入重做日志文件也不是直接写,而是先写入一个重做日志缓冲,然后根据一定的条件顺序写入日志文件。

redo log日志的巨细是牢固的,为了能够延续不停的对更新纪录举行写入,在redo log日志中设置了两个标志位置,checkpoint和write_pos,划分示意纪录擦除的位置和纪录写入的位置。redo log日志的数据写入示意图可见下图。

write_pos标志到了日志末端时,会从末端跳至日志头部举行重新循环写入。以是redo log的逻辑结构并不是线性的,而是可看作一个圆周运动。write_poscheckpoint中央的空间可用于写入新数据,写入和擦除都是往后推移,循环往复的。

write_pos追上checkpoint时,示意redo log日志已经写满。这时不能继续执行新的数据库更新语句,需要停下来先删除一些纪录,执行checkpoint规则腾出可写空间。

checkpoint规则:checkpoint触发后,将buffer中脏数据页和脏日志页都刷到磁盘。

同样是纪录事务日志,和bin log有什么差异呢?

  • bin log会纪录所有与数据库有关的日志纪录,包罗InnoDB、MyISAM等存储引擎的日志,而redo log只记InnoDB存储引擎的日志。

  • 纪录的内容差异,bin log纪录的是关于一个事务的详细操作内容,即该日志是逻辑日志。而redo log纪录的是关于每个页(Page)的更改的物理情形。

  • 写入的时间差异,bin log仅在事务提交前举行提交,也就是只写磁盘一次。而在事务举行的历程中,却不停有redo ertry被写入redo log中。

  • 写入的方式也不相同,redo log是循环写入和擦除,bin log是追加写入,不会笼罩已经写的文件。

1.6、回滚日志(undo log)

提到了redo log,这里在简朴领会一下回滚日志(undo log)。

回滚日志同样也是InnoDB引擎提供的日志,顾名思义,回滚日志的作用就是对数据举行回滚。当事务对数据库举行修改,InnoDB引擎不仅会纪录redo log,还会天生对应的undo log日志;若是事务执行失败或挪用了rollback,导致事务需要回滚,就可以行使undo log中的信息将数据回滚到修改之前的样子。

然则undo log不redo log纷歧样,它属于逻辑日志。它对SQL语句执行相关的信息举行纪录。当发生回滚时,InnoDB引擎会凭证undo log日志中的纪录做与之前相反的事情。好比对于每个数据插入操作(insert),回滚时会执行数据删除操作(delete);对于每个数据删除操作(delete),回滚时会执行数据插入操作(insert);对于每个数据更新操作(update),回滚时会执行一个相反的数据更新操作(update),把数据改回去。undo log由两个作用,一是提供回滚,二是实现MVCC。

2、更新语句执行

接下来连系一条更新语句的执行,来进一步明晰bin log和redo log这两种主要日志。

 update t set c=c+1 where ID=2;

2.1、更新语句执行流程

我们来看执行器和InnoDB引擎在执行这个简朴的update语句时的内部流程。

  1. 执行器先找引擎取ID=2这一行。ID是主键,引擎直接用树搜索找到这一行。若是ID=2这一行所在的数据页原本就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。

    Flowable与springBoot项目整合及出现的问题

  2. 执行器拿到引擎给的行数据,把这个值加上1,好比原来是N,现在就是N+1,获得新的一行数据,再挪用引擎接口写入这行新数据。

  3. 引擎将这行新数据更新到内存中,同时将这个更新操作纪录到redo log内里,此时redo log处于prepare状态。然后见告执行器执行完成了,随时可以提交事务。

  4. 执行器天生这个操作的binlog,并把binlog写入磁盘。

  5. 执行器挪用引擎的提交事务接口,引擎把刚刚写入的redo log改成提交(commit)状态,更新完成。

update语句的执行流程图如下:

2.2、两阶段提交

这条语句的执行历程中,redo log的写入分成了两个步骤分成了prepare和commit两个阶段举行提交,这就是所谓的两阶段提交。为什么要用两阶段提交呢?

先用通俗的说法:

好比小明去超市里买一瓶可乐:

  1. 小明:老板给我来瓶可乐!透心凉心飞扬的谁人。
  2. 老板:机械扫一下可乐,告诉小明这瓶可乐2块5,给钱(纪录 redo log,事务处于prepare状态)
  3. 收钱放入钱箱(纪录 binlog,事务现实是否完成的基本依据,处于待符号commit阶段)
  4. 然后让小明把可乐拿走(redo log 状态标为 commit,示意该事务逻辑闭环)。到这里,代表一笔生意竣事。
  5. 等算账前再把这一天卖器械的生意信息一起同步到数据库。

可见,若是收钱之前(prepare阶段,步骤3)生意被打断,回过头来处置此次生意,发现只有记了小黑板但没有收钱,则生意失败,删掉小黑板上的纪录(回滚);

若是收了钱后(commit阶段 或 待commit阶段,步骤4 || 5)生意被打断,然后回过头发现系统上有纪录(prepare)而且钱箱有本次收入(bin log),则说明本次生意有用,弥补修改commit状态,更新到库存中。

用正式一点的语言来形貌。

若是不用两阶段提交,要么就是先写完redo log再写binlog,或者接纳反过来的顺序。我们看看这两种方式会有什么问题。

仍然用前面的update语句来做例子。假设当前ID=2的行,字段c的值是0,再假设执行update语句历程中在写完第一个日志后,第二个日志还没有写完时代发生了crash,会泛起什么情形呢?

  1. 先写redo log后写binlog。假设在redo log写完,binlog还没有写完的时刻,MySQL历程异常重启。由于我们前面说过的,redo log写完之后,系统纵然溃逃,仍然能够把数据恢复回来,以是恢复后这一行c的值是1。
    然则由于binlog没写完就crash了,这时刻binlog内里就没有纪录这个语句。因此,之后备份日志的时刻,存起来的binlog内里就没有这条语句。
    然后你会发现,若是需要用这个binlog来恢复暂且库的话,由于这个语句的binlog丢失,这个暂且库就会少了这一次更新,恢复出来的这一行c的值就是0,与原库的值差异。

  1. 先写binlog后写redo log。若是在binlog写完之后crash,由于redo log还没写,溃逃恢复以后这个事务无效,以是这一行c的值是0。然则binlog内里已经纪录了“把c从0改成1”这个日志。以是,在之后用binlog来恢复的时刻就多了一个事务出来,恢复出来的这一行c的值就是1,与原库的值差异。

可以看到,若是不使用“两阶段提交”,那么数据库的状态就有可能和用它的日志恢复出来的库的状态纷歧致。

你可能会说,这个概率是不是很低,平时也没有什么动不动就需要恢复暂且库的场景呀?

着实不是的,不只是误操作后需要用这个历程来恢复数据。当你需要扩容的时刻,也就是需要再多搭建一些备库来增添系统的读能力的时刻,现在常见的做法也是用全量备份加上应用binlog来实现的,这个“纷歧致”就会导致你的线上泛起主从数据库纷歧致的情形。

简朴说,redo log和binlog都可以用于示意事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。

2.3、日志落盘

保证事务乐成,日志必须落盘,这样,数据库crash后,就不会丢失某个事务的数据了

  • innodb_flush_log_at_trx_commit 这个参数设置成 1 的时刻,示意每次事务的 redo log 都直接持久化到磁盘。这样可以保证 MySQL 异常重启之后数据不丢失。

  • sync_binlog 这个参数设置成 1 的时刻,示意每次事务的 binlog 都持久化到磁盘。这样可以保证 MySQL 异常重启之后 binlog 不丢失。



参考:

【1】:《高性能MySQL》

【2】:极客时间 《MySQL实战45讲》

【3】:《MySQL手艺内幕 InnoDB存储引擎》

【4】:听我讲完redo log、binlog原理,面试官老脸一红

【5】:为了让你彻底弄懂 MySQL 事务日志,我通宵肝出了这份图解!

【6】:MySQL中几种常见的日志

【7】:Mysql学习条记——重做日志与归档日志

【8】:浅析MySQL事务中的redo与undo

python基础(弥补):lambda匿名函数,用了的,都说好!