当前位置: 首页 > news >正文

Mr. Cappuccino的第53杯咖啡——Mybatis源码分析

Mybatis源码分析

    • Mybatis源码分析入口
    • 1. 读取配置文件
      • 总结
    • 2. 解析配置文件
      • 核心代码(一)
      • 核心代码(二)
        • 分析parse()方法
        • 分析build()方法
      • 总结
    • 3. 获取SqlSession
      • 总结
    • 4. 获取mapper代理对象
      • 总结
    • 5. 使用mapper代理对象执行Sql语句
      • 二级缓存
      • 一级缓存
      • 总结

Mybatis源码分析入口

本文将根据下面这段代码进行源码分析

InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<UserEntity> list = mapper.listUser();
System.out.println(list);
sqlSession.close();

1. 读取配置文件

InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");

ClassLoaderWrapper.java

在这里插入图片描述


总结

从入口一路点击进去可以发现底层是通过调用java.lang.ClassLoader#getResourceAsStream方法来读取resources目录下的mybatis-config.xml文件,并得到InputStream对象

2. 解析配置文件

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSessionFactoryBuilder.java

在这里插入图片描述

在这里插入图片描述


核心代码(一)

XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);

XMLConfigBuilder.java

在这里插入图片描述

XPathParser.java

在这里插入图片描述

可以发现底层是将InputStream对象转换成Document对象,并将Document对象保存至当前类(XPathParser)的document属性中

继续回到上一层,点击进入this()方法

XMLConfigBuilder.java

在这里插入图片描述

可以发现this()方法主要是在进行部分属性的初始化,并将XPathParser对象保存至当前类(XMLConfigBuilder)的parser属性中。
关键点:初始化了父类的configuration属性。


核心代码(二)

return build(parser.parse());

分析parse()方法


XMLConfigBuilder.java

在这里插入图片描述

  1. 根据Document对象获取节点为configuration的配置信息,并转换成XNode对象

XPathParser.java

在这里插入图片描述

  1. 将XNode对象解析成Configuration对象

XMLConfigBuilder.java

在这里插入图片描述

XMLConfigBuilder.java

在这里插入图片描述


点击进入addMappers(mapperPackage)方法


Configuration.java

在这里插入图片描述

MapperRegistry.java

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


在这里插入图片描述

从这里可以发现parser.parse()主要是在解析配置文件(mybatis-config.xml),具体过程是根据Document对象获取节点为configuration的配置信息,并转换成XNode对象再解析各个节点,重点部分是mappers节点的解析。
在解析mappers节点的代码中可以发现如果是使用package或class注册mapper可以直接注册mapper接口对象,如果是使用url或者resource注册mapper则需要先解析mapper.xml映射文件后并通过namespace找到所绑定的接口对象再进行注册。
mapper的注册是通过MapperRegistry对象完成的,而MapperRegistry则是Configuration对象里面的一个属性,也就是说所有的配置解析完成后都存放在Configuration对象中。
parser.parse()最终返回Configuration对象。

分析build()方法


SqlSessionFactoryBuilder.java

在这里插入图片描述

DefaultSqlSessionFactory.java

在这里插入图片描述

从这里可以发现SqlSessionFactoryBuilder将得到的Configuration对象建造成DefaultSqlSessionFactory对象,也就是SqlSessionFactory对象。


总结

SqlSessionFactoryBuilder先是通过XMLConfigBuilder解析配置文件并将解析得到的配置装载到Configuration对象中,再将Configuration建造成DefaultSqlSessionFactory对象。

这里采用了建造者设计模式
BaseBuilder:所有解析器的父类,包含配置文件实例,为解析文件提供一些通用的方法;
XMLConfigBuilder:主要负责解析mybatis-config.xml文件;
XMLMapperBuilder:主要负责解析mapper.xml文件;
XMLStatementBuilder:主要负责解析映射文件中的SQL节点;

Configuration对象核心属性释义:

  1. MapperRegistry:mapper接口动态代理工厂类的注册中心;
  2. ResultMap:用于解析mapper.xml文件中的resultMap节点,使用ResultMapping来封装id、result等子元素;
  3. MappedStatement:用于存储mapper.xml文件中的select、insert、update和delete节点,同时还包含了这些节点的很多重要属性;
  4. SqlSource:用于创建BoundSql,mapper.xml文件中的sql语句会被解析成BoundSql对象,经过解析BoundSql包含的语句最终仅仅包含?占位符,可以直接提交给数据库执行;

3. 获取SqlSession

SqlSession sqlSession = sqlSessionFactory.openSession();

DefaultSqlSessionFactory.java

在这里插入图片描述

Configuration.java

在这里插入图片描述
在这里插入图片描述

从这里可以看到如果没有设置执行器类型,则会默认使用简单执行器类型

ExecutorType.java

在这里插入图片描述

上面枚举类中的三种执行器类型均可通过openSession()传参设置


点击进入openSessionFromDataSource()方法


DefaultSqlSessionFactory.java

在这里插入图片描述

openSessionFromDataSource()方法有三个入参:ExecutorType execType(执行器类型)、TransactionIsolationLevel level(事务隔离级别)、boolean autoCommit(是否自动提交)

  1. 获取TransactionFactory

DefaultSqlSessionFactory.java

在这里插入图片描述

TransactionFactory有两种:JdbcTransactionFactory,ManagedTransactionFactory
通过mybatis-config.xml文件进行配置

在这里插入图片描述

<transactionManager type="JDBC"/>

这里配置的是JdbcTransactionFactory

  1. 获取Transaction

JdbcTransactionFactory.java

在这里插入图片描述

JdbcTransaction.java

在这里插入图片描述

  1. 根据Transaction和执行器类型获取执行器(核心代码)

Configuration.java

在这里插入图片描述

CachingExecutor.java

在这里插入图片描述

Mybatis默认使用的执行器是SimpleExecutor,SimpleExecutor的父类是BaseExecutor,BaseExecutor下一共有三个子类也就是三种执行器:BatchExecutor、SimpleExecutor、ReuseExecutor,这三种执行器均可通过传值设置。

cacheEnabled默认值为true,说明Mybatis默认会使用CachingExecutor。进入CachingExecutor类可以发现,CachingExecutor是在上面三种执行器(BaseExecutor)的基础上做了一层包装(装饰器设计模式),先调用CachingExecutor再调用BaseExecutor,是对BaseExecutor类的增强。

cacheEnabled可以通过mybatis-config.xml文件进行配置

<settings><!-- 是否开启二级缓存 --><setting name="cacheEnabled" value="false"/>
</settings>

BaseExecutor是一级缓存(默认开启),默认使用SimpleExecutor,CachingExecutor是二级缓存(默认开启,但还需要做一些额外的配置才能生效)

  1. 生成DefaultSqlSession

在这里插入图片描述

将Configuration、Executor、autoCommit等信息包装成DefaultSqlSession对象,并且返回该对象


总结

openSession()是SqlSessionFactory接口中的一个重载方法,可以配置执行器类型、事务隔离级别、是否自动提交等参数,Configuration负责判断当前使用的执行器(Executor),DefaultSqlSessionFactory最后将Configuration、Executor、autoCommit等信息包装成DefaultSqlSession对象并返回。

这里采用了装饰器设计模式

BaseExecutor是一级缓存(默认开启),BaseExecutor是BatchExecutor、SimpleExecutor、ReuseExecutor三种执行器的父类。

  1. SimpleExecutor:默认的Executor,每个SQL执行的时候都会创建新的Statement;
  2. ReuseExecutor:相同的SQL会重复使用Statement;
  3. BatchExecutor:用于批处理的Executor;

CachingExecutor是二级缓存(默认开启,但还需要做一些额外的配置才能生效)
CachingExecutor:可缓存数据的Executor,用装饰器模式包装了其它的执行器(如BaseExecutor下的三种执行器)

4. 获取mapper代理对象

UserMapper mapper = sqlSession.getMapper(UserMapper.class);

DefaultSqlSession.java

在这里插入图片描述

Configuration.java

在这里插入图片描述

MapperRegistry.java

在这里插入图片描述

之前已经对mapper接口进行了注册,这里通过mapper接口类型获取对应的动态代理工厂类(MapperProxyFactory),动态代理工厂类使用JDK动态代理技术生成mapper代理对象并返回该对象。

MapperProxyFactory.java

在这里插入图片描述

MapperProxy.java

在这里插入图片描述

JDK动态代理技术主要用于拦截和修改方法的调用,在使用mapper代理对象调用mapper接口中的方法时MapperProxy中的invoke方法也会被执行。

总结

根据mapper接口类型从MapperRegistry中获取对应的动态代理工厂类(MapperProxyFactory),动态代理工厂类使用JDK动态代理技术生成mapper代理对象并返回该对象。在使用mapper代理对象调用方法时底层会走MapperProxy中的invoke方法。

这里采用了JDK动态代理设计模式

MapperRegistry:mapper接口动态代理工厂类的注册中心;
MapperProxyFactory:用于生成动态代理的实例对象;
MapperProxy:动态代理回调类;

5. 使用mapper代理对象执行Sql语句

List<UserEntity> list = mapper.listUser();

在这里插入图片描述

在这里插入图片描述


MapperProxy.java

在这里插入图片描述

在这里插入图片描述

核心代码

mapperMethod.execute(sqlSession, args);

MapperMethod.java

在这里插入图片描述

因为执行的SQL为select,返回值类型为List集合,所以会走executeForMany()方法

在这里插入图片描述

DefaultSqlSession.java

在这里插入图片描述

这个方法是不是很熟悉,没错,这就是在基于XML方式-原生方式开发用到的方法

List<UserEntity> list = sqlSession.selectList("com.mybatis.mapper.UserMapper.listUser", UserEntity.class);

DefaultSqlSession.java

在这里插入图片描述

在这里插入图片描述

二级缓存

如果开启了二级缓存则会使用CachingExecutor

CachingExecutor.java

在这里插入图片描述

  1. 获取SQL语句

在这里插入图片描述

  1. 创建缓存key

在这里插入图片描述

  1. 执行查询逻辑

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

SimpleExecutor中没有query方法,默认走父类(BaseExecutor)


一级缓存

BaseExecutor.java

在这里插入图片描述
在这里插入图片描述

SimpleExecutor.java

在这里插入图片描述

  1. 初始化RoutingStatementHandler对象

Configuration.java

在这里插入图片描述

RoutingStatementHandler.java

在这里插入图片描述

  1. 生成Statement对象

SimpleExecutor.java

在这里插入图片描述

2.1. 获取Connection

BaseExecutor.java

在这里插入图片描述

JdbcTransaction.java

在这里插入图片描述

2.2. 根据不同的StatementHandler创建Statement对象

RoutingStatementHandler.java

在这里插入图片描述

BaseStatementHandler.java

在这里插入图片描述

Mybatis默认采用PreparedStatementHandler处理器

PreparedStatementHandler.java

在这里插入图片描述

2.3. 使用ParameterHandler处理占位符参数

RoutingStatementHandler.java

在这里插入图片描述

PreparedStatementHandler.java

在这里插入图片描述

DefaultParameterHandler.java

在这里插入图片描述

  1. 执行查询逻辑

RoutingStatementHandler.java

在这里插入图片描述

PreparedStatementHandler.java

在这里插入图片描述

DefaultResultSetHandler.java

在这里插入图片描述


总结

在使用代理对象调用方法时,底层会走MapperProxy中的invoke方法,在执行查询语句时,默认会先从二级缓存(CachingExecutor)中读取数据,如果存在则直接返回,不存在则继续查询一级缓存,如果一级缓存(BaseExecutor)中存在则直接返回,不存在则继续查询数据库,在查询数据库时,总体上使用StatementHandler对象和JDBC进行交互,整个查询流程先是使用ParameterHandler对SQL语句的入参进行处理,待SQL语句被执行完后得到结果集,再使用ResultSetHandler对结果集进行处理并返回。

四大核心接口对象

  1. Executor(执行器):负责整个SQL执行过程的总体控制;
  2. StatementHandler(语句处理器):负责和JDBC层的具体交互;
  3. ParameterHandler(参数处理器):负责PreparedStatement入参的具体设置;
  4. ResultSetHandler(结果集处理器):负责将JDBC查询的结果映射为Java对象;

StatementHandler

  1. RoutingStatementHandler:根据StatementType路由到不同的StatementHandler对象;
  2. SimpleStatementHandler:管理Statement对象并向数据库中推送不需要预编译的SQL语句;
  3. PreparedStatementHandler:管理Statement对象并向数据库中推送需要预编译的SQL语句;
  4. CallableStatementHandler:管理Statement对象并调用数据库中的存储过程;

相关文章:

Mr. Cappuccino的第53杯咖啡——Mybatis源码分析

Mybatis源码分析 Mybatis源码分析入口1. 读取配置文件总结 2. 解析配置文件核心代码&#xff08;一&#xff09;核心代码&#xff08;二&#xff09;分析parse()方法分析build()方法 总结 3. 获取SqlSession总结 4. 获取mapper代理对象总结 5. 使用mapper代理对象执行Sql语句二…...

修改文件格式(查看文件拓展名)

很多时候我们直接把txt文件重命名为xxx.c或者别的文件格式&#xff0c;文件类型依然会是txt&#xff0c;文件名并不会变成我们想要的xxx.c&#xff0c;而是xxx.c.txt&#xff0c;也就是下面这个样子 给大家介绍2种方法去解决这个问题 目录 1.另存为新格式 2.显示文件拓展名 1…...

利用鸿鹄可观测性监控Istio Ingress网关

一、需求描述 在上一篇《利用Vector和鸿鹄搭建微服务应用的可观测性平台》中&#xff0c;阐述了微服务的基本概念、优点及如何利用鸿鹄来处理分布式应用的日志。本文将进一步讨论微服务架构面临的问题、服务网格及鸿鹄处理Istio Gateway的独特优势。 1.1 微服务架构面临的挑战 …...

vscode 前端开发插件 2023

自己记录 安装vscode后必装插件 chinesegit 必装没啥可说 随时更新 1.CSS Navigation CTRL点击类名可跳转到对应样式位置。 如果是scss less的话。css peak插件无法生效 2.GitLens — Git supercharged 可以看到每一行的git提交记录。 3.Auto Rename Tag 可以同步更新…...

使用docker部署Wordpress

文章目录 1.创建网络2.创建volume存储3.拉取镜像4.创建mysql容器mysql修改密码 5.创建wordpress容器6.访问localhost:80就可以直接使用啦 1.创建网络 docker network create --subnet172.18.0.0/24 pro-net2.创建volume存储 # mysql 存储 docker volume create volume_mysql…...

7.31黄金最新行情走势分析及多空交易策略

近期有哪些消息面影响黄金走势&#xff1f;黄金多空该如何研判&#xff1f; ​黄金消息面解析&#xff1a;上周有重磅数据美联储加息的消息&#xff0c;黄金受其影响波动比较频繁&#xff0c;总体空间40美金。但这个过程跌宕起伏。收线来看黄金在连续上涨三周后迎来一根小阴十…...

Spring框架——AOP注解方式

目录 Spring框架的AOP技术&#xff08;注解方式&#xff09; 通知类型 Spring框架的AOP技术&#xff08;注解方式&#xff09; 1. 步骤一&#xff1a;创建JavaWEB项目&#xff0c;引入具体的开发的jar包* 先引入Spring框架开发的基本开发包com.springsource.org.apache.commo…...

Java 日志(Logging)如何创建和捕获日志消息和文件

Java允许我们通过日志记录过程来创建和捕获日志消息和文件。 在Java中&#xff0c;日志记录需要框架和API。Java在java.util.logging程序包中具有内置的日志记录框架。 Java 日志组件 下图显示了Java Logging API&#xff08;java.util.logging&#xff09;的核心组件和指定…...

em3288 linux_4.19 lvds+tp调试

一、显示配置\rk3288_linux4.19\kernel\arch\arm\boot\dts\rk3288-evb-act8846.dtspanel {compatible "simple-panel";backlight <&backlight>;bus-format <MEDIA_BUS_FMT_RGB666_1X18>;enable-gpios <&gpio1 24 GPIO_ACTIVE_HIGH>;ena…...

Linux 之 systemctl

systemctl 可以控制软件&#xff08;一般指服务&#xff09;的启动、关闭、开机自启动 能被systemctl 管理的软件&#xff0c;一般也称 服务 系统内置服务均可被 systemctl 控制第三方软件&#xff0c;如果 自动注册了 可被systemctl 控制第三方软件&#xff0c;如果没有自动…...

【技巧】通过 CMD 走代理下载 Vue

通过 CMD 走代理下载 Vue 在学习或者工作中&#xff0c;有时上网走的是代理模式&#xff0c;就是在浏览器里面配置代理服务的那种。后来在下载 Vue 组件的时候显示请求超时。此时才发先&#xff0c;浏览器代理只能在浏览器里生效&#xff0c;cmd 中不生效&#xff0c;那该怎么办…...

VSCode C/C++多文件编译配置

多文件编译备忘&#xff0c;带注释的地方都需要注意&#xff01;&#xff01;&#xff01; launch.json文件 {// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息&#xff0c;请访问: https://go.microsoft.com/fwlink/?linkid830387&quo…...

Autosar通信入门系列05-聊聊一帧Can/CanFD报文发送时间?

本文框架 1. 概述2. 一帧CAN报文发送时间计算3. 一帧CanFD报文的传输时间计算3.1 标准CAN与CANFD两者间的区别3.2 CANFD报文传输时间计算 1. 概述 本篇我们一起看下一帧Can报文发送需要多长时间&#xff0c;下述文章里我们会首先计算下Can分别对应的字节数&#xff0c;再根据传…...

【phaser微信抖音小游戏开发002】hello world!

执行效果&#xff1a; 将以下代码文本内容&#xff0c;放入到game.js中即可。目录结构如下图 import ./js/libs/weapp-adapter import ./js/libs/symbolGameGlobal.window.scrollTo () > { };//防止真机出错 import Phaser from ./js/phaser//引入Phaservar {windowWidth, …...

2023.07.29 驱动开发DAY6

通过epoll实现一个并发服务器 服务器 #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/epoll.h…...

网工必须掌握的5种组网技术,你会了吗?

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 目录 一、VLAN技术 1、VLAN是什么&#xff1f; 2、VLAN的作用 ①提高网络安全性 ②提高了网络的灵活性性 ③增强了网络的健壮性 二、D…...

webpack中文文档

基本安装 首先我们创建一个目录&#xff0c;初始化 npm&#xff0c;然后 在本地安装 webpack&#xff0c;接着安装 webpack-cli&#xff08;此工具用于在命令行中运行 webpack&#xff09;&#xff1a; mkdir webpack-demo cd webpack-demo npm init -y npm install webpack …...

【Linux指令篇】--- Linux常用指令汇总(克服指令繁杂问题)

文章目录 前言&#x1f31f;一、Linux基本指令&#x1f31f;二、ls指令&#x1f30f;2.1.语法&#xff1a;&#x1f30f;2.2.功能&#xff1a;&#x1f30f;2.3.常用选项&#xff1a; &#x1f31f;三、pwd指令&#x1f30f;3.1.语法&#xff1a;&#x1f30f;3.2.功能&#xf…...

硬盘的分类

目前常见的硬盘种类主要有以下2种&#xff1a; 机械硬盘&#xff08;HDD&#xff09; 机械硬盘&#xff08;HDD&#xff09;是一种利用旋转磁盘和读写头来存储和访问数据的存储设备。它由磁盘、读写头、电机和控制电路等组成&#xff0c;磁盘通常是一种铝合金或玻璃材质的圆盘&…...

el-upload批量手动上传,并用form表单校验上传文件

手动上传设置:auto-upload"false" <el-formref"formData"class"formWidth":model"formData"label-width"120px":rules"rules"><el-form-itemlabel"数据"class"uploadClass"required…...

牛客网Verilog刷题——VL52

牛客网Verilog刷题——VL52 题目答案 题目 请编写一个十进制计数器模块&#xff0c;当mode信号为1&#xff0c;计数器输出信号递增&#xff0c;当mode信号为0&#xff0c;计数器输出信号递减。每次到达0&#xff0c;给出指示信号zero。模块的接口信号图如下&#xff1a; 模块的…...

4-7月预测价差方向准确率统计

月度 预测价差方向准确率 4月 33.6% 5月 28.4% 6月 25.7% 7月 34.2% 4-7月合计 30.6% 准确率计算公式&#xff1a; 其中&#xff0c; D&#xff1a;价差方向预测值&#xff08;1:实时>日前&#xff0c;0:实时日前&#xff0c;-1&#xff1a;实时<日前&#x…...

《Vue3+Typescript》一个简单的日历组件实现

这是一个没有套路的前端博主&#xff0c;热衷各种前端向的骚操作&#xff0c;经常想到哪就写到哪&#xff0c;如果有感兴趣的技术和前端效果可以留言&#xff5e;博主看到后会去代替大家踩坑的&#xff5e; 主页: oliver尹的主页 格言: 跌倒了爬起来就好&#xff5e; 目录 一、…...

第一章 修学旅行

前言 翻了翻文章回收站&#xff0c;好怀念靖和阳的故事啊&#xff08;航和颜&#xff1a;还有我们别忘啦&#xff09; 不知道还有没有人记得以前的故事呢…… 那么&#xff0c;我就开始写啦。这是关于密码学的一篇文章&#xff0c;一共2696字&#xff1a;D&#xff08;累死我…...

如果你也能认识并使用这个低代码平台,那真的是泰酷辣——iVX低代码平台

低代码技术起源是比较悠久的了&#xff0c;尤其是在近些年&#xff0c;随着技术的演进&#xff0c;低代码平台逐渐成为热门趋势。这些平台通过简化应用程序开发流程&#xff0c;减少手动编码&#xff0c;使非专业开发人员也能快速构建复杂应用。为我们的敏捷开发和高效生产贡献…...

uC-OS2 V2.93 STM32L476 移植:系统移植篇

前言 上一篇已经 通过 STM32CubeMX 搭建了 NUCLEO-L476RG STM32L476RG 的 裸机工程&#xff0c;并且下载了 uC-OS2 V2.93 的源码&#xff0c;接下来&#xff0c;开始系统移植 开发环境 win10 64位 Keil uVision5&#xff0c;MDK V5.36 uC-OS2 V2.93 开发板&#xff1a;NUC…...

gitee修改代码提交操作步骤说明

一&#xff0c;简介 本文主要介绍如何从gitee仓库下载文件&#xff0c;本地修改&#xff0c;本地提交&#xff0c;然后再push到远程服务器的操作步骤。供参考&#xff0c;欢迎一起讨论交流~ 二&#xff0c;操作步骤 总的操作步骤分为以下几步 1&#xff0c;远程服务器下载文…...

物联网|可变参数的使用技巧|不一样的点灯实验|访问外设的寄存器|操作寄存器实现点灯|硬件编程的基本流程-学习笔记(11)

文章目录 可变参数的使用技巧第三阶段-初级实验Lesson5:不一样的点灯实验---学习I/O的输出 ☆点灯的电路图分析1 一起看看点灯的电路图Tip1:另一种点灯的电路Tip1:如何访问外设的寄存器2 STM32F407中操作GPIO的方法 通过直接操作寄存器实现点灯实验Tip1:硬件编程的基本流程 2代…...

30. 利用linprog 解决 生产决策问题(matlab程序)

1.简述 线线规划的几个基本性质&#xff1a;【文献[1]第46页】 (1)线性规划问题的可行域如果非空&#xff0c;则是一个凸集-凸多面体&#xff1b; (2)如果线性规划问题有最优解&#xff0c;那么最优解可在可行域的顶点中确定&#xff1b; (3)如果可行域有界&#xff0c;且可行域…...

一百三十九、Kettle——Linux安装Kettle8.2

一、目的 为了方便海豚调度kettle任务&#xff0c;在Linux上安装kettle 二、kettle版本与前提 版本&#xff1a;kettle8.2 pdi-ce-8.2.0.0-342 前提&#xff1a;Linux已经安装好jdk 三、安装步骤 &#xff08;一&#xff09;打开安装包所在地 [roothurys22 ~]# cd …...