JTA分布式事务管理器

XA协议:是一种标准协议,允许事务管理器协调多个资源管理器,确保在分布式事务中的一致性和原子性。

JTA:是JavaEE规范中的一种,用于管理分布式事务的 API,提供了事务的控制和协调机制

Atomikos理解成JTA的实现

XA是JTA的基础(JTA实现了XA协议)  Atomikos实现了JTA

Atomikos这种方式限定与单应用多数据源使用场景.

关于理论的一些:

当业务操作需要涉及到多个数据库时,这就可称为分布式事务处理.实现分布式事务处理的关键是采用一种手段保证事务涉及的所有数据库所做的全部动作要么全部生效,要买么全部回滚.

目前处理分布式事务的规范就是XA规范.

X/Open组织为分布式事务制定了的事务中间件与数据库之间的接口规范.这种规范就是XA规范.事务中间件用它来通知数据库事务开始,提交,回滚等

X/Open组织仅仅制定了分布式事务处理的XA规范,但具体的实现则由不同的数据库厂商自行提供.

对于大部分主流商业及开源数据库都提供了XA规范的驱动

分布式事务处理方法很多

XA 方案

2PC   两阶段提交:

2PC 的传统方案是在数据库层面实现的,如 Oracle MySQL 都支持 2PC 协议,为了统一标准减少行业内不必要的对
接成本,需要制定标准化的处理模型及接口标准,国际开放标准组织 Open Group 定义了分布式事务处理模型
DTP Distributed Transaction Processing Reference Model )。

成功示例:

失败示例:

执行流程如下:
1 、应用程序( AP )持有用户库和积分库两个数据源。
2 、应用程序( AP )通过 TM 通知用户库 RM 新增用户,同时通知积分库 RM 为该用户新增积分, RM 此时并未提交事
务,此时用户和积分资源锁定。
3 TM 收到执行回复,只要有一方失败则分别向其他 RM 发起回滚事务,回滚完毕,资源锁释放。
4 TM 收到执行回复,全部成功,此时向所有 RM 发起提交事务,提交完毕,资源锁释放。
DTP 模型定义如下角色:
AP (Application Program) :即应用程序,可以理解为使用 DTP 分布式事务的程序。
RM (Resource Manager) :即资源管理器,可以理解为事务的参与者,一般情况下是指一个数据库实例,通过
资源管理器对该数据库进行控制,资源管理器控制着分支事务。
TM (Transaction Manager) :事务管理器,负责协调和管理事务,事务管理器控制着全局事务,管理事务生命
周期,并协调各个 RM 全局事务 是指分布式事务处理环境中,需要操作多个数据库共同完成一个工作,这个
工作即是一个全局事务。
DTP 模型定义 TM RM 之间通讯的接口规范叫 XA ,简单理解为数据库提供的 2PC 接口协议, 基于数据库的 XA
协议来实现 2PC 又称为 XA 方案
以上三个角色之间的交互方式如下:
1 TM AP 提供 应用程序编程接口, AP 通过 TM 提交及回滚事务。
2 TM 交易中间件通过 XA 接口来通知 RM 数据库事务的开始、结束以及提交、回滚等。
总结:
整个 2PC 的事务流程涉及到三个角色 AP RM TM AP 指的是使用 2PC 分布式事务的应用程序; RM 指的是资
源管理器,它控制着分支事务; TM 指的是事务管理器,它控制着整个全局事务。
1 )在 准备阶段 RM 执行实际的业务操作,但不提交事务,资源锁定;
2 )在 提交阶段 TM 会接受 RM 在准备阶段的执行回复,只要有任一个 RM 执行失败, TM 会通知所有 RM 执行回滚操
作,否则, TM 将会通知所有 RM 提交该事务。提交阶段结束资源锁释放。
XA 方案的问题:
1 、需要本地数据库支持 XA 协议。
2 、资源锁需要等到两个阶段结束才释放,性能较差。(这句话掠过哈,这句话是讲seata的人说的   当然  也许   可能没有阿里的 seata好用)

下面是SpringBoot+Mybatis多数据源配置
项目结构

这边随意建了两张表测试   分别在不同数据库
CREATE TABLE `news` (
  `id` int NOT NULL AUTO_INCREMENT,
  `title` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `content` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE `user_inf` (
  `user_id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
application.properties
两个数据源配置文件
@Configuration
@MapperScan(basePackages = {"com.example.demo5.mapper"},sqlSessionFactoryRef = "primarySqlSessionFactory")
public class DataSourceConfig1 {

    @Primary
    @Bean(name="primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource(){
        //return DataSourceBuilder.create().build();
        //return new HikariDataSource();
        return new DruidDataSource();
    }

    @Primary
    @Bean(name="primarySqlSessionFactory")
    public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean=new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setTypeAliasesPackage("com.example.demo5.pojo");
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/*Mapper.xml"));
        SqlSessionFactory sqlSessionFactory = bean.getObject();
        sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
        //sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
        return sqlSessionFactory;
    }

    @Primary
    @Bean(name="primarySqlSessionTemplate")
    public SqlSessionTemplate primarySqlSessionTemplate(@Qualifier("primarySqlSessionFactory")SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Primary
    @Bean(name="primaryJdbcTemplate")
    public JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource")DataSource dataSource){
        return  new JdbcTemplate(dataSource);
    }

    @Primary
    @Bean(name="primaryTransactionManager")
    public DataSourceTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource")DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }

}

@Configuration
@MapperScan(basePackages = {"com.example.demo5.mapper2"},sqlSessionFactoryRef = "secondSqlSessionFactory")
public class DataSourceConfig2 {


    @Bean(name="secondDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.second")
    public DataSource secondDataSource(){
        return DataSourceBuilder.create().build();
    }


    @Bean(name="secondSqlSessionFactory")
    public SqlSessionFactory secondSqlSessionFactory(@Qualifier("secondDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean=new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setTypeAliasesPackage("com.example.demo5.pojo2");
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers2/*Mapper.xml"));
        SqlSessionFactory sqlSessionFactory = bean.getObject();
        sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
        //sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
        return sqlSessionFactory;
    }


    @Bean(name="secondSqlSessionTemplate")
    public SqlSessionTemplate secondSqlSessionTemplate(@Qualifier("secondSqlSessionFactory")SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }


    @Bean(name="secondJdbcTemplate")
    public JdbcTemplate secondJdbcTemplate(@Qualifier("secondDataSource")DataSource dataSource){
        return  new JdbcTemplate(dataSource);
    }


    @Bean(name="secondTransactionManager")
    public DataSourceTransactionManager secondTransactionManager(@Qualifier("secondDataSource")DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }
}

实体类

service

serviceImpl

事务测试

但是这两个事务管理器无法满足分布式事务

就是说我要将A数据库和B数据库的操作放在一个事务中,无法满足

Atomikos的使用

添加SpringBoot整合Atomikos的starter的jar包

 Atomikos的数据源必须是AtomikosDataSourceBean,因此配置的数据源必须是XADatasource

然后再使用AtomikosDataSourceBean包装它们

使用Atomikos

Atomikos的数据源必须是AtomikosDataSourceBean,因此配置数据源必须先使用XADatasource,

然后再使用AtomikosDataSourceBean包装他们.

将不同数据源对应的AtomikosDataSourceBean注入对应sqlSessionFactory

application.properties

两个配置文件

@Configuration
@MapperScan(basePackages = {"com.example.demo5.mapper"},sqlSessionFactoryRef = "primarySqlSessionFactory")
public class DataSourceConfig1 {

//    @Primary
    @Bean(name="primary")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public XADataSource primary(){
        //MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();//application.properties中的要与他里面的属性对应
        //return mysqlXADataSource;
        DruidXADataSource druidXADataSource=new DruidXADataSource();
        return druidXADataSource;
    }

    @Bean(name="primaryDataSource")
    @Primary
    public DataSource primaryDataSource(){
        AtomikosDataSourceBean atomikosDataSourceBean=new AtomikosDataSourceBean();
        atomikosDataSourceBean.setXaDataSource(primary());
        atomikosDataSourceBean.setMaxPoolSize(20);
        atomikosDataSourceBean.setUniqueResourceName("mysqlDs1");//取个唯一名字
        return atomikosDataSourceBean;
    }

    @Primary
    @Bean(name="primarySqlSessionFactory")
    public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean=new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setTypeAliasesPackage("com.example.demo5.pojo");
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/*Mapper.xml"));
        SqlSessionFactory sqlSessionFactory = bean.getObject();
        sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
        //sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
        return sqlSessionFactory;
    }

    @Primary
    @Bean(name="primarySqlSessionTemplate")
    public SqlSessionTemplate primarySqlSessionTemplate(@Qualifier("primarySqlSessionFactory")SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Primary
    @Bean(name="primaryJdbcTemplate")
    public JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource")DataSource dataSource){
        return  new JdbcTemplate(dataSource);
    }

    //使用JTA全局事务管理器后,不要再自定义事务管理器
//    @Primary
//    @Bean(name="primaryTransactionManager")
//    public DataSourceTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource")DataSource dataSource){
//        return new DataSourceTransactionManager(dataSource);
//    }

}

@Configuration
@MapperScan(basePackages = {"com.example.demo5.mapper2"},sqlSessionFactoryRef = "secondSqlSessionFactory")
public class DataSourceConfig2 {


    //    @Primary
    @Bean(name="second")
    @ConfigurationProperties(prefix = "spring.datasource.second")
    public XADataSource second(){
//        MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();//application.properties中的要与他里面的属性对应
//
//        return mysqlXADataSource;
        DruidXADataSource druidXADataSource=new DruidXADataSource();
        return druidXADataSource;

    }

    @Bean(name="secondDataSource")
    public DataSource secondDataSource(){
        AtomikosDataSourceBean atomikosDataSourceBean=new AtomikosDataSourceBean();
        atomikosDataSourceBean.setXaDataSource(second());
        atomikosDataSourceBean.setMaxPoolSize(20);
        atomikosDataSourceBean.setUniqueResourceName("mysqlDs2");//取个唯一名字
        return atomikosDataSourceBean;
    }


    @Bean(name="secondSqlSessionFactory")
    public SqlSessionFactory secondSqlSessionFactory(@Qualifier("secondDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean=new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setTypeAliasesPackage("com.example.demo5.pojo2");
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers2/*Mapper.xml"));
        SqlSessionFactory sqlSessionFactory = bean.getObject();
        sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
        //sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
        return sqlSessionFactory;
    }


    @Bean(name="secondSqlSessionTemplate")
    public SqlSessionTemplate secondSqlSessionTemplate(@Qualifier("secondSqlSessionFactory")SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }


    @Bean(name="secondJdbcTemplate")
    public JdbcTemplate secondJdbcTemplate(@Qualifier("secondDataSource")DataSource dataSource){
        return  new JdbcTemplate(dataSource);
    }


//    @Bean(name="secondTransactionManager")
//    public DataSourceTransactionManager secondTransactionManager(@Qualifier("secondDataSource")DataSource dataSource){
//        return new DataSourceTransactionManager(dataSource);
//    }
}

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.3.0</version>
        </dependency>

        <!--stomikos-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jta-atomikos</artifactId>
        </dependency>
        <!--德鲁伊-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.15</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
<!--            <scope>runtime</scope>使用MysqlXADataSource的话把运行时去掉,不然找不到  不用可以恢复运行时-->
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter-test</artifactId>
            <version>3.0.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/114120.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springboot+mybatis查询两次数据库结果不一致

最近遇到个bug记录一下。情景再现&#xff1a;在一个方法里有多次查询数据库的操作&#xff0c;但查询出的数据字段会被自动翻译。&#xff08;比如1翻译成是&#xff0c;2翻译成否&#xff09;。原因&#xff1a;mybatis缓存会被代码修改。在同一个sqlsession下&#xff0c;第…

遥遥领先,免费开源的django4-vue3前后端分离项目

星域后台管理系统前端介绍 &#x1f33f;项目简介 本项目前端基于当下流行且常用的vue3作为主要技术栈进行开发&#xff0c;融合了typescript和element-plus-ui&#xff0c;提供暗黑模式和白昼模式两种主题以及全屏切换&#xff0c;开发bug少&#xff0c;简单易学&#xff0c…

学习笔记|两组率卡方检验和Fisher确切法|适用条件|规范表达|《小白爱上SPSS》课程:SPSS第十五讲 | 两组率卡方检验和Fisher确切法怎么做?

目录 学习目的软件版本原始文档两组率卡方检验和Fisher确切法适用条件简述一、实战案例读数据&#xff1a; 二、统计策略三、SPSS操作四、结果解读第一&#xff0c;分组统计描述结果第二&#xff0c;卡方检验。 五、规范报告1、规范表格2、规范文字 学习目的 SPSS第十五讲 | 两…

Windows、程序员必装的工具

一、Typora 啥也不说了直接上图 Markdown语法 Typora免费版 提取码&#xff1a;av01 二维码&#xff1a; 1&#xff09;页面展示 2&#xff09;主题 3&#xff09;偏好设置 4&#xff09;Markdown语法设置偏好 5&#xff09;编辑器 6&#xff09;系统 二、Snipaste Snipaste…

腾讯云双11活动时间、活动入口、优惠政策详细解读

2023年腾讯云双11大促活动已开启&#xff0c;作为年终最大的一次优惠促销活动&#xff0c;腾讯云的优惠力度还是不错的&#xff0c;爆款云服务器首年88元&#xff0c;还有9999元大额代金券免费领取&#xff01; 一、腾讯云双11活动时间 即日起至2023-11-30 23:59:59&#xff0…

Modelsim 使用教程(4)—— Working With Multiple Libraries

一、概述 在文中&#xff0c;我们将练习使用多个库。在实际的项目开发过程中&#xff0c;我们可能有多个库来组织设计&#xff0c;从第三方源代码访问IP&#xff0c;或者在仿真之间共享公共部分。我们将通过创建一个包含计数器设计单元的资源库来开始本文。接下来&#xff0c;我…

怎样提取视频提取的人声或伴奏?

有些小伙伴们进行音视频创作时&#xff0c;可能会需要提取音频的人声或者是伴奏。这里给大家推荐一个音分轨人声分离软件&#xff0c;支持一键提取音频人声和一键提取伴奏功能&#xff0c;可批量导入文件同步提取&#xff0c;简单高效&#xff0c;是音视频创作者的不二选择&…

HarmonyOS开发:开源一个刷新加载组件

前言 系统Api中提供了下拉刷新组件Refresh&#xff0c;使用起来也是非常的好用&#xff0c;但是风格和日常的开发&#xff0c;有着巨大的出入&#xff0c;效果如下&#xff1a; 显然上面的效果是很难满足我们实际的需求的&#xff0c;奈何也没有提供的属性可以更改&#xff0c;…

linux远程桌面管理工具xrdp

一、概述 我们知道&#xff0c;我们日常通过vnc来远程管理linux图形界面&#xff0c;今天分享一工具Xrdp&#xff0c;它是一个开源工具&#xff0c;允许用户通过Windows RDP访问Linux远程桌面。 除了Windows RDP之外&#xff0c;xrdp工具还接受来自其他RDP客户端的连接&#xf…

量子计算与量子密码(入门级-少图版)

量子计算与量子密码 写在最前面一些可能带来的有趣的知识和潜在的收获 1、Introduction导言四个特性不确定性&#xff08;自由意志论&#xff09;Indeterminism不确定性Uncertainty叠加原理(线性)superposition (linearity)纠缠entanglement 虚数的常见基本运算欧拉公式&#x…

Linux下使用vscode编写Python项目

我此处是使用VScode远程连接的服务器&#xff0c;具体方法可看如下&#xff1a; 1、vscode中安装Python插件 按上面步骤安装好Python插件后&#xff0c;重启vscode&#xff1b; 2、选择Python解释器 创建Python项目结构&#xff1a; 按下F1&#xff0c;打开vscode命令栏&am…

自动驾驶算法(一):Dijkstra算法讲解与代码实现

目录 0 本节关键词&#xff1a;栅格地图、算法、路径规划 1 Dijkstra算法详解 2 Dijkstra代码详解 0 本节关键词&#xff1a;栅格地图、算法、路径规划 1 Dijkstra算法详解 用于图中寻找最短路径。节点是地点&#xff0c;边是权重。 从起点开始逐步扩展&#xff0c;每一步为一…

Plist编辑软件 PlistEdit Pro mac中文版功能介绍

PlistEdit Pro mac是一款功能强大的Plist文件编辑软件。Plist文件是苹果公司开发的一种XML文件格式&#xff0c;用于存储应用程序的配置信息和数据。PlistEdit Pro可以帮助用户轻松地编辑和管理Plist文件。 PlistEdit Pro具有直观的用户界面和丰富的功能。用户可以使用该软件打…

计算机网络第4章-网络层(1)

引子 网络层能够被分解为两个相互作用的部分&#xff1a; 数据平面和控制平面。 网络层概述 路由器具有截断的协议栈&#xff0c;即没有网络层以上的部分。 如下图所示&#xff0c;是一个简单网络&#xff1a; 转发和路由选择&#xff1a;数据平面和控制平面 网络层的作用…

C语言--分段函数

要求&#xff1a;写一个程序&#xff0c;输入x的值&#xff0c;输出y的值 思路&#xff1a;定义两个变量&#xff0c;一个y&#xff0c;一个x&#xff0c;当x<1时&#xff0c;yx&#xff0c;当x>1&&x<10&#xff0c;y2x-1&#xff0c;当x>10,y3x-11.用一个…

【基于卷积和Transformer:多光谱图像光谱重建】

Spectral Reconstruction From Satellite Multispectral Imagery Using Convolution and Transformer Joint Network &#xff08;基于卷积和Transformer联合网络的卫星多光谱图像光谱重建&#xff09; 基于卫星多光谱&#xff08;MS&#xff09;图像的光谱重建&#xff08;S…

用于 GaN-HEMT 功率器件仿真的 TCAD 方法论

目录 标题&#xff1a;TCAD Methodology for Simulation of GaN-HEMT Power Devices来源&#xff1a;Proceedings of the 26th International Symposium on Power Semiconductor Devices & ICs(14年 ISPSD)GaN-HEMT仿真面临的挑战文章研究了什么文章的创新点文章的研究方法…

【JVM经典面试题(五十二道)】

文章目录 JVM经典面试题&#xff08;五十二道&#xff09;引言1.什么是JVM 内存管理2.能说一下JVM的内存区域吗&#xff1f;3.说一下JDK1.6、1.7、1.8内存区域的变化&#xff1f;4.为什么使用元空间替代永久代作为方法区的实现&#xff1f;5.对象创建的过程了解吗&#xff1f;6…

配置OpenCV

Open CV中包含很多图像处理的算法&#xff0c;因此学会正确使用Open CV也是人脸识别研究的一项重要工作。在 VS2017中应用Open CV&#xff0c;需要进行手动配置&#xff0c;下面给出在VS2017中配置Open CV的详细步骤。 1.下载并安装OpenCV3.4.1与VS2017的软件。 2.配置Open CV环…

opencv第一个例子

目的 这是用用QTopencv实现的一个完整的展示图片的例子&#xff0c;包括了项目的配置文件&#xff0c;完整的代码&#xff0c;以用做初次学习opencv用。 代码 工程文件&#xff1a; QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsTARGET openCv1 TEMPL…