0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

SpringBoot分布式事务的解决方案(JTA+Atomic+多数据源)

Android编程精选 来源:blog.csdn.net/jaryle/article/d 作者:blog.csdn.net/jaryle/ 2022-04-11 11:05 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

首先,到底啥是分布式事务呢,比如我们在执行一个业务逻辑的时候有两步分别操作A数据源和B数据源,当我们在A数据源执行数据更改后,在B数据源执行时出现运行时异常,那么我们必须要让B数据源的操作回滚,并回滚对A数据源的操作;这种情况在支付业务时常常出现;比如买票业务在最后支付失败,那之前的操作必须全部回滚,如果之前的操作分布在多个数据源中,那么这就是典型的分布式事务回滚;

了解了什么是分布式事务,那分布式事务在java的解决方案就是JTA(即Java Transaction API);springboot官方提供了 Atomikos or Bitronix的解决思路;

其实,大多数情况下很多公司是使用消息队列的方式实现分布式事务。

本篇文章重点讲解springboot环境下,整合 Atomikos +mysql+mybatis+tomcat/jetty;

一、项目依赖

pom.xml中添加atomikos的springboot相关依赖:


<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jta-atomikosartifactId>
dependency>

点进去会发现里面整合好了:transactions-jmstransactions-jtatransactions-jdbcjavax.transaction-api

二、把数据源的相关配置项单独提炼到一个application.yml中:

注意:

  1. 这回我们的spring.datasource.typecom.alibaba.druid.pool.xa.DruidXADataSource;

  2. spring.jta.transaction-manager-id的值在你的电脑中是唯一的,这个详细请阅读官方文档;

ca6a91f8-b943-11ec-aa7f-dac502259ad0.png

完整的yml文件如下:

spring:
datasource:
type:com.alibaba.druid.pool.xa.DruidXADataSource
druid:

systemDB:
name:systemDB
url:jdbc//localhost:3306/springboot-mybatis?useUnicode=true&characterEncoding=utf-8
username:root
password:root
#下面为连接池的补充设置,应用到上面所有数据源中
#初始化大小,最小,最大
initialSize:5
minIdle:5
maxActive:20
#配置获取连接等待超时的时间
maxWait:60000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis:60000
#配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis:30
validationQuery:SELECT1
validationQueryTimeout:10000
testWhileIdle:true
testOnBorrow:false
testOnReturn:false
#打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements:true
maxPoolPreparedStatementPerConnectionSize:20
filters:stat,wall
#通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties:druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
#合并多个DruidDataSource的监控数据
useGlobalDataSourceStat:true

businessDB:
name:businessDB

url:jdbc//localhost:3306/springboot-mybatis2?useUnicode=true&characterEncoding=utf-8
username:root
password:root
#下面为连接池的补充设置,应用到上面所有数据源中
#初始化大小,最小,最大
initialSize:5
minIdle:5
maxActive:20
#配置获取连接等待超时的时间
maxWait:60000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis:60000
#配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis:30
validationQuery:SELECT1
validationQueryTimeout:10000
testWhileIdle:true
testOnBorrow:false
testOnReturn:false
#打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements:true
maxPoolPreparedStatementPerConnectionSize:20
filters:stat,wall
#通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties:druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
#合并多个DruidDataSource的监控数据
useGlobalDataSourceStat:true

#jta相关参数配置
jta:
log-dir:classpath:tx-logs
transaction-manager-id:txManager
三、在DruidConfig.java中实现多个数据源的注册;分布式事务管理器的注册;druid的注册;
packagecom.zjt.config;

importcom.alibaba.druid.filter.stat.StatFilter;
importcom.alibaba.druid.support.http.StatViewServlet;
importcom.alibaba.druid.support.http.WebStatFilter;
importcom.alibaba.druid.wall.WallConfig;
importcom.alibaba.druid.wall.WallFilter;
importcom.atomikos.icatch.jta.UserTransactionImp;
importcom.atomikos.icatch.jta.UserTransactionManager;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
importorg.springframework.boot.web.servlet.FilterRegistrationBean;
importorg.springframework.boot.web.servlet.ServletRegistrationBean;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.context.annotation.Primary;
importorg.springframework.core.env.Environment;
importorg.springframework.transaction.jta.JtaTransactionManager;

importjavax.sql.DataSource;
importjavax.transaction.UserTransaction;
importjava.util.Properties;

/**
*Druid配置
*
*
*/
@Configuration
publicclassDruidConfig{
@Bean(name="systemDataSource")
@Primary
@Autowired
publicDataSourcesystemDataSource(Environmentenv){
AtomikosDataSourceBeands=newAtomikosDataSourceBean();
Propertiesprop=build(env,"spring.datasource.druid.systemDB.");
ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
ds.setUniqueResourceName("systemDB");
ds.setPoolSize(5);
ds.setXaProperties(prop);
returnds;

}

@Autowired
@Bean(name="businessDataSource")
publicAtomikosDataSourceBeanbusinessDataSource(Environmentenv){

AtomikosDataSourceBeands=newAtomikosDataSourceBean();
Propertiesprop=build(env,"spring.datasource.druid.businessDB.");
ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
ds.setUniqueResourceName("businessDB");
ds.setPoolSize(5);
ds.setXaProperties(prop);

returnds;
}


/**
*注入事物管理器
*@return
*/
@Bean(name="xatx")
publicJtaTransactionManagerregTransactionManager(){
UserTransactionManageruserTransactionManager=newUserTransactionManager();
UserTransactionuserTransaction=newUserTransactionImp();
returnnewJtaTransactionManager(userTransaction,userTransactionManager);
}


privatePropertiesbuild(Environmentenv,Stringprefix){

Propertiesprop=newProperties();
prop.put("url",env.getProperty(prefix+"url"));
prop.put("username",env.getProperty(prefix+"username"));
prop.put("password",env.getProperty(prefix+"password"));
prop.put("driverClassName",env.getProperty(prefix+"driverClassName",""));
prop.put("initialSize",env.getProperty(prefix+"initialSize",Integer.class));
prop.put("maxActive",env.getProperty(prefix+"maxActive",Integer.class));
prop.put("minIdle",env.getProperty(prefix+"minIdle",Integer.class));
prop.put("maxWait",env.getProperty(prefix+"maxWait",Integer.class));
prop.put("poolPreparedStatements",env.getProperty(prefix+"poolPreparedStatements",Boolean.class));

prop.put("maxPoolPreparedStatementPerConnectionSize",
env.getProperty(prefix+"maxPoolPreparedStatementPerConnectionSize",Integer.class));

prop.put("maxPoolPreparedStatementPerConnectionSize",
env.getProperty(prefix+"maxPoolPreparedStatementPerConnectionSize",Integer.class));
prop.put("validationQuery",env.getProperty(prefix+"validationQuery"));
prop.put("validationQueryTimeout",env.getProperty(prefix+"validationQueryTimeout",Integer.class));
prop.put("testOnBorrow",env.getProperty(prefix+"testOnBorrow",Boolean.class));
prop.put("testOnReturn",env.getProperty(prefix+"testOnReturn",Boolean.class));
prop.put("testWhileIdle",env.getProperty(prefix+"testWhileIdle",Boolean.class));
prop.put("timeBetweenEvictionRunsMillis",
env.getProperty(prefix+"timeBetweenEvictionRunsMillis",Integer.class));
prop.put("minEvictableIdleTimeMillis",env.getProperty(prefix+"minEvictableIdleTimeMillis",Integer.class));
prop.put("filters",env.getProperty(prefix+"filters"));

returnprop;
}

@Bean
publicServletRegistrationBeandruidServlet(){
ServletRegistrationBeanservletRegistrationBean=newServletRegistrationBean(newStatViewServlet(),"/druid/*");

//控制台管理用户,加入下面2行进入druid后台就需要登录
//servletRegistrationBean.addInitParameter("loginUsername","admin");
//servletRegistrationBean.addInitParameter("loginPassword","admin");
returnservletRegistrationBean;
}

@Bean
publicFilterRegistrationBeanfilterRegistrationBean(){
FilterRegistrationBeanfilterRegistrationBean=newFilterRegistrationBean();
filterRegistrationBean.setFilter(newWebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
filterRegistrationBean.addInitParameter("profileEnable","true");
returnfilterRegistrationBean;
}

@Bean
publicStatFilterstatFilter(){
StatFilterstatFilter=newStatFilter();
statFilter.setLogSlowSql(true);//slowSqlMillis用来配置SQL慢的标准,执行时间超过slowSqlMillis的就是慢。
statFilter.setMergeSql(true);//SQL合并配置
statFilter.setSlowSqlMillis(1000);//slowSqlMillis的缺省值为3000,也就是3秒。
returnstatFilter;
}

@Bean
publicWallFilterwallFilter(){
WallFilterwallFilter=newWallFilter();
//允许执行多条SQL
WallConfigconfig=newWallConfig();
config.setMultiStatementAllow(true);
wallFilter.setConfig(config);
returnwallFilter;
}

}
四、分别配置每个数据源对应的sqlSessionFactory,以及MapperScan扫描的包:

MybatisDatasourceConfig.java

packagecom.zjt.config;

importcom.zjt.util.MyMapper;
importorg.apache.ibatis.session.SqlSessionFactory;
importorg.mybatis.spring.SqlSessionFactoryBean;
importorg.mybatis.spring.SqlSessionTemplate;
importorg.mybatis.spring.annotation.MapperScan;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Qualifier;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.core.io.support.PathMatchingResourcePatternResolver;
importorg.springframework.core.io.support.ResourcePatternResolver;

importjavax.sql.DataSource;

/**
*
*@description
*/
@Configuration
//精确到mapper目录,以便跟其他数据源隔离
@MapperScan(basePackages="com.zjt.mapper",markerInterface=MyMapper.class,sqlSessionFactoryRef="sqlSessionFactory")
publicclassMybatisDatasourceConfig{

@Autowired
@Qualifier("systemDataSource")
privateDataSourceds;

@Bean
publicSqlSessionFactorysqlSessionFactory()throwsException{
SqlSessionFactoryBeanfactoryBean=newSqlSessionFactoryBean();
factoryBean.setDataSource(ds);
//指定mapperxml目录
ResourcePatternResolverresolver=newPathMatchingResourcePatternResolver();
factoryBean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
returnfactoryBean.getObject();

}

@Bean
publicSqlSessionTemplatesqlSessionTemplate()throwsException{
SqlSessionTemplatetemplate=newSqlSessionTemplate(sqlSessionFactory());//使用上面配置的Factory
returntemplate;
}

//关于事务管理器,不管是JPA还是JDBC等都实现自接口PlatformTransactionManager
//如果你添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入 DataSourceTransactionManager 实例。
//在Spring容器中,我们手工注解@Bean 将被优先加载,框架不会重新实例化其他的 PlatformTransactionManager 实现类。
/*@Bean(name="transactionManager")
@Primary
publicDataSourceTransactionManagermasterTransactionManager(){
//MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源
//与DataSourceTransactionManager引用的数据源一致即可,否则事务管理会不起作用。
returnnewDataSourceTransactionManager(ds);
}*/

}

MybatisDatasource2Config.java

packagecom.zjt.config;

importcom.zjt.util.MyMapper;
importorg.apache.ibatis.session.SqlSessionFactory;
importorg.mybatis.spring.SqlSessionFactoryBean;
importorg.mybatis.spring.SqlSessionTemplate;
importorg.mybatis.spring.annotation.MapperScan;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Qualifier;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.core.io.support.PathMatchingResourcePatternResolver;
importorg.springframework.core.io.support.ResourcePatternResolver;

importjavax.sql.DataSource;

/**
*
*@description
*/
@Configuration
//精确到mapper目录,以便跟其他数据源隔离
@MapperScan(basePackages="com.zjt.mapper2",markerInterface=MyMapper.class,sqlSessionFactoryRef="sqlSessionFactory2")
publicclassMybatisDatasource2Config{

@Autowired
@Qualifier("businessDataSource")
privateDataSourceds;

@Bean
publicSqlSessionFactorysqlSessionFactory2()throwsException{
SqlSessionFactoryBeanfactoryBean=newSqlSessionFactoryBean();
factoryBean.setDataSource(ds);
//指定mapperxml目录
ResourcePatternResolverresolver=newPathMatchingResourcePatternResolver();
factoryBean.setMapperLocations(resolver.getResources("classpath:mapper2/*.xml"));
returnfactoryBean.getObject();

}

@Bean
publicSqlSessionTemplatesqlSessionTemplate2()throwsException{
SqlSessionTemplatetemplate=newSqlSessionTemplate(sqlSessionFactory2());//使用上面配置的Factory
returntemplate;
}

//关于事务管理器,不管是JPA还是JDBC等都实现自接口PlatformTransactionManager
//如果你添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入 DataSourceTransactionManager 实例。
//在Spring容器中,我们手工注解@Bean 将被优先加载,框架不会重新实例化其他的 PlatformTransactionManager 实现类。
/*@Bean(name="transactionManager2")
@Primary
publicDataSourceTransactionManagermasterTransactionManager(){
//MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源
//与DataSourceTransactionManager引用的数据源一致即可,否则事务管理会不起作用。
returnnewDataSourceTransactionManager(ds);
}*/

}

由于我们本例中只使用一个事务管理器:xatx,故就不在使用TxAdviceInterceptor.javaTxAdvice2Interceptor.java中配置的事务管理器了;有需求的童鞋可以自己配置其他的事务管理器;(见DruidConfig.java中查看)

五、新建分布式业务测试接口JtaTestService.java和实现类JtaTestServiceImpl.java

其实就是一个很简单的test01()方法,在该方法中我们分别先后调用classService.saveOrUpdateTClass(tClass);teacherService.saveOrUpdateTeacher(teacher);

实现先后操作两个数据源:然后我们可以自己debug跟踪事务的提交时机,此外,也可以在在两个方法全执行结束之后,手动制造一个运行时异常,来检查分布式事务是否全部回滚;

注意:

在实现类的方法中我使用的是:

@Transactional(transactionManager="xatx",propagation=Propagation.REQUIRED,rollbackFor={java.lang.RuntimeException.class})

从而指定了使用哪个事务管理器,事务隔离级别(一般都用我这个默认的),回滚的条件(一般可以使用Exception),这三个可以自己根据业务实际修改;

packagecom.zjt.service3;

importjava.util.Map;

publicinterfaceJtaTestService{

publicMaptest01();

}
packagecom.zjt.service3.impl;


importcom.zjt.entity.TClass;
importcom.zjt.entity.Teacher;
importcom.zjt.service.TClassService;
importcom.zjt.service2.TeacherService;
importcom.zjt.service3.JtaTestService;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Qualifier;
importorg.springframework.stereotype.Service;
importorg.springframework.transaction.annotation.Propagation;
importorg.springframework.transaction.annotation.Transactional;

importjava.util.LinkedHashMap;
importjava.util.Map;

@Service("jtaTestServiceImpl")
publicclassJtaTestServiceImplimplementsJtaTestService{

@Autowired
@Qualifier("teacherServiceImpl")
privateTeacherServiceteacherService;
@Autowired
@Qualifier("tclassServiceImpl")
privateTClassServicetclassService;

@Override
@Transactional(transactionManager="xatx",propagation=Propagation.REQUIRED,rollbackFor={java.lang.RuntimeException.class})
publicMap<String,Object>test01(){
LinkedHashMapresultMap=newLinkedHashMap();
TClasstClass=newTClass();
tClass.setName("8888");
tclassService.saveOrUpdateTClass(tClass);

Teacherteacher=newTeacher();
teacher.setName("8888");
teacherService.saveOrUpdateTeacher(teacher);

System.out.println(1/0);

resultMap.put("state","success");
resultMap.put("message","分布式事务同步成功");
returnresultMap;
}
}
六、建立JtaTestContoller.java,接受一个来自前端的http请求,触发JtaTestService 的test01方法:
packagecom.zjt.web;


importcom.zjt.service3.JtaTestService;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Qualifier;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.ResponseBody;

importjava.util.LinkedHashMap;
importjava.util.Map;

@Controller
@RequestMapping("/jtaTest")
publicclassJtaTestContoller{

@Autowired
@Qualifier("jtaTestServiceImpl")
privateJtaTestServicetaTestService;



@ResponseBody
@RequestMapping("/test01")
publicMaptest01(){
LinkedHashMapresultMap=newLinkedHashMap();
try{
returntaTestService.test01();
}catch(Exceptione){
resultMap.put("state","fail");
resultMap.put("message","分布式事务同步失败");
returnresultMap;
}
}
}
七、在test.ftl中增加一个按钮来测试;
//分布式事务测试
$("#JTATest").click(function(){
    $.ajax({
        type: "POST",
        url: "${basePath!}/jtaTest/test01",
        data: {}    ,
        async: false,
        error: function (request) {
            layer.alert("与服务器连接失败/(ㄒoㄒ)/~~");
            return false;
        },
        success: function (data) {
            if (data.state == 'fail') {
                layer.alert(data.message);
                return false;
            }else if(data.state == 'success'){
                layer.alert(data.message);
            }
        }
    });
});
 

八、启动服务,验证结果:
ca76e2aa-b943-11ec-aa7f-dac502259ad0.png

点击这个按钮,跳转到controller:

ca88376c-b943-11ec-aa7f-dac502259ad0.png

当正常执行了sql语句之后,我们可以发现数据库并没有变化,因为整个方法的事务还没有走完,当我们走到1/0这步时:

ca9d69c0-b943-11ec-aa7f-dac502259ad0.png

抛出运行时异常,并被spring事务拦截器拦截,并捕获异常:

caae8480-b943-11ec-aa7f-dac502259ad0.png

this.completeTransactionAfterThrowing(txInfo, var16);方法中会将事务全部回滚:

2204.243logback[http-nio-8080-exec-5]INFOc.a.i.imp.CompositeTransactionImp-rollback()doneoftransaction192.168.1.103.tm0000400006

此时,当我们再次打开数据库验证,依旧没有变化,证明分布式事务配置成功;

大家可以基于我的代码自己练习一下,自己尝试着使用多事务管理器的情况下的灵活配置;

九、后记:

本文源代码:

https://github.com/zhaojiatao/springboot-zjt-chapter10-springboot-atomikos-mysql-mybatis-druid.git

代码在tomcat和jetty环境下均可完成事务回滚;

在事务回滚时可能报一个Transactional not active的警告,我google后,老外也说不出这个具体作用,大部分人认为这只是一个警告,可以忽略;

-End-

审核编辑 :李倩
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • API
    API
    +关注

    关注

    2

    文章

    2483

    浏览量

    67070
  • 分布式
    +关注

    关注

    1

    文章

    1114

    浏览量

    76712
  • 数据源
    +关注

    关注

    1

    文章

    66

    浏览量

    10103
  • SpringBoot
    +关注

    关注

    0

    文章

    178

    浏览量

    718

原文标题:SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源)

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    AI Ceph 分布式存储教程资料大模型学习资料2026

    的实战应用中,优化数据加载路径是提升训练效率的关键技术手段。科技视角下的解决方案,引入了多级缓存与智能预取机制。 针对训练数据集中频繁访问的热点数据,高性能的
    发表于 05-01 17:35

    探索SP6121 Demo Board:分布式电源系统的高效解决方案

    探索SP6121 Demo Board:分布式电源系统的高效解决方案 引言 在分布式电源系统的设计中,找到一款高效、稳定且性能卓越的DC/DC同步降压转换器至关重要。SP6121 Demo
    的头像 发表于 04-27 15:30 135次阅读

    2022全新版!Java分布式架构设计与开发实战(完结)

    。 分库分表带来的挑战远不止技术实现层面。跨库查询需要避免JOIN操作,可通过应用层聚合或数据冗余解决;分布式事务需要采用两阶段提交或柔性事务补偿机制;
    发表于 03-30 15:20

    ADW600 适配微电网!打造分布式能源计量核心方案

    ,容易出现数据混乱、计量不准等问题。安科瑞 ADW600 多回路计量系列,专为微电网计量需求打造,以 12 路三相双向计量、多数据集成、全场景适配 为核心优势,成为微电网分布式能源计
    的头像 发表于 03-13 13:54 1011次阅读

    TiDB分布式数据库运维实践

    TiDB 是 PingCAP 开发的开源分布式关系型数据库,兼容 MySQL 5.7 协议,底层存储基于 TiKV(分布式 KV 存储)和 RocksDB。它解决的核心问题是:当单机 MySQL 无法承载
    的头像 发表于 03-04 15:44 350次阅读

    配电自动化站所终端智能分布式功能闭环仿真测试案例

    深圳市科瑞杰科技有限公司-本次项目用到的是智能分布式DTU典型测试配网模型,实时仿真的结果符合实际情况,各种动态响应很好的模拟了现场实际工况,为分布式DTU的测试提供了很好的解决方案
    的头像 发表于 02-04 17:35 721次阅读
    配电自动化站所终端智能<b class='flag-5'>分布式</b>功能闭环仿真测试案例

    意法半导体与AutoCore推出基于以太网的ZCU分布式音频解决方案

    ,意法半导体(STMicroelectronics,简称ST)与奥特酷智能科技(南京)有限公司(简称AutoCore)近日联合宣布,双方已达成深度战略合作,并共同推出了一款极具行业颠覆性的创新成果——基于以太网的ZCU分布式音频解决方案
    的头像 发表于 02-01 17:33 1995次阅读
    意法半导体与AutoCore推出基于以太网的ZCU<b class='flag-5'>分布式</b>音频<b class='flag-5'>解决方案</b>

    分布式能源管理物联网解决方案

    ,构建全链路能源数据采集与管控体系,实现分布式能源的精细化管理与智能化运维。 方案架构 终端设备层:现场设备包括光伏逆变器、智能电表、电池管理系统(BMS)等各类能源设备,支持IEC61850、IEC101/103/104、DL
    的头像 发表于 01-21 11:39 503次阅读
    <b class='flag-5'>分布式</b>能源管理物联网<b class='flag-5'>解决方案</b>

    全新分布式智慧投屏终端开启智慧教学新时代!

    全新分布式智慧教室系统的核心设备是分布式智慧投屏终端,集无线投屏、白板书写、多机联动、信息发布于一体,为老师学生分组投屏、互动分享提供多屏协作解决方案。智能书写功能与方案中多屏互动相辅
    的头像 发表于 09-19 11:35 993次阅读
    全新<b class='flag-5'>分布式</b>智慧投屏终端开启智慧教学新时代!

    【节能学院】Acrel-1000DP分布式光伏监控系统在奉贤平高食品 4.4MW 分布式光伏中应用

    分布式光伏本地和远程通信方案,并研究分布式光伏采集模型的构建、多数据融合估计、面向分布式光伏的
    的头像 发表于 08-23 08:04 3692次阅读
    【节能学院】Acrel-1000DP<b class='flag-5'>分布式</b>光伏监控系统在奉贤平高食品 4.4MW <b class='flag-5'>分布式</b>光伏中应用

    分布式光伏发电监测系统技术方案

    分布式光伏发电监测系统技术方案 柏峰【BF-GFQX】一、系统目标 :分布式光伏发电监测系统旨在通过智能化的监测手段,实现对分布式光伏电站的全方位、高精度、实时化管理。该系统能
    的头像 发表于 08-22 10:51 3512次阅读
    <b class='flag-5'>分布式</b>光伏发电监测系统技术<b class='flag-5'>方案</b>

    分布式IO选型指南:2025年分布式无线远程IO品牌及采集控制方案详解

    。2025年,分布式IO市场呈现出技术革新与品牌竞争加剧的态势。本文基于权威数据平台(如Statista、MarketsandMarkets、Grand View Research)的市场分析,全面解读分布式无线远程IO的选型要
    的头像 发表于 06-23 09:48 1500次阅读

    分布式IO模组选购指南:2025主流品牌盘点与应用方案解析

    分布式IO模块市场进入快速增长期。本文基于权威数据平台的市场分析,盘点2025年主流分布式IO模块品牌,介绍优势产品,并解析典型应用方案,旨在为企业选购提供权威参考。
    的头像 发表于 06-10 16:57 1680次阅读

    安科瑞分布式光伏监控系统:高效、安全、智能的绿色能源解决方案

    ?并网标准如何满足?运维成本如何降低?安科瑞电气股份有限公司凭借多年行业经验,创新推出Acrel-1000DP分布式光伏监控系统,为光伏电站提供全生命周期解决方案。 一、分布式光伏发电系统标准规范 1.并网标准
    的头像 发表于 05-08 16:40 887次阅读

    从430到531,安科瑞分布式光伏方案以智应变破局未来

    日之后至 5 月 31 日建成并网的项目,部分不再适用固定上网电价政策;5 月 31 日之后并网的项目,都不再享受固定上网电价政策。政策更迭在行业内掀起抢装热潮。 安科瑞分布式光伏解决方案 安科瑞分布式光伏
    的头像 发表于 05-08 15:24 664次阅读
    从430到531,安科瑞<b class='flag-5'>分布式</b>光伏<b class='flag-5'>方案</b>以智应变破局未来