SpringBoot+Mybatis多数据源实战:TDengine与MySQL混搭的物联网数据存储方案
SpringBootMybatis多数据源实战TDengine与MySQL混搭的物联网数据存储方案在物联网系统开发中数据存储架构的设计往往面临一个核心矛盾海量设备时序数据的高效存储与业务数据的复杂关系处理如何平衡传统单一数据库方案要么在时序数据处理上捉襟见肘要么无法满足业务系统的灵活查询需求。本文将揭示如何通过SpringBootMybatis构建多数据源系统让TDengine与MySQL各司其职实现112的存储效果。1. 物联网数据存储的架构抉择当单个传感器每天产生上千条数据时十万级设备规模的系统很快就会面临单表亿级数据的处理压力。我们曾在一个智慧农业项目中实测发现MySQL单表存储传感器数据达到3000万条时按设备ID时间范围查询响应时间超过8秒同样的查询条件在TDengine中执行仅需23毫秒但TDengine在处理用户权限、设备元数据等关联查询时性能反而不及MySQL这种差异源于两种数据库的设计哲学特性MySQLTDengine数据模型关系型时序型索引效率B树索引适合点查询时间线索引适合范围扫描压缩比一般2-3倍典型10-20倍分布式支持需中间件原生支持事务完整性ACID完备最终一致性提示时序数据库并非要替代关系型数据库而是专为时间序列数据优化的特殊形态2. SpringBoot多数据源的核心配置实现双数据库协同工作的关键在于正确的依赖配置和数据源隔离。以下是经过生产验证的POM配置要点!-- 基础依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-jdbc/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.2.0/version /dependency !-- 数据库驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdcom.taosdata.jdbc/groupId artifactIdtaos-jdbcdriver/artifactId version3.2.8/version /dependency !-- 分页插件 -- dependency groupIdcom.github.pagehelper/groupId artifactIdpagehelper-spring-boot-starter/artifactId version1.4.1/version /dependency应用配置文件中需要明确区分两个数据源# MySQL数据源 spring.datasource.mysql.jdbc-urljdbc:mysql://host:3306/iot_biz?useSSLfalse spring.datasource.mysql.usernameroot spring.datasource.mysql.password123456 spring.datasource.mysql.driver-class-namecom.mysql.cj.jdbc.Driver # TDengine数据源 spring.datasource.taos.jdbc-urljdbc:TAOS://host:6030/iot_tsdb spring.datasource.taos.usernameroot spring.datasource.taos.passwordtaosdata spring.datasource.taos.driver-class-namecom.taosdata.jdbc.TSDBDriver3. Mybatis的多数据源隔离策略实现真正的数据源隔离需要三个层面的配合3.1 数据源配置类MySQL主数据源配置带Primary注解Configuration MapperScan(basePackages com.iot.dao.mysql, sqlSessionFactoryRef mysqlSqlSessionFactory) public class MysqlDataSourceConfig { Bean Primary ConfigurationProperties(spring.datasource.mysql) public DataSource mysqlDataSource() { return DataSourceBuilder.create().build(); } Bean Primary public SqlSessionFactory mysqlSqlSessionFactory( Qualifier(mysqlDataSource) DataSource dataSource) throws Exception { SqlSessionFactoryBean bean new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources(classpath:mapper/mysql/*.xml)); return bean.getObject(); } Bean Primary public DataSourceTransactionManager mysqlTransactionManager( Qualifier(mysqlDataSource) DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }TDengine从数据源配置Configuration MapperScan(basePackages com.iot.dao.taos, sqlSessionFactoryRef taosSqlSessionFactory) public class TaosDataSourceConfig { Bean ConfigurationProperties(spring.datasource.taos) public DataSource taosDataSource() { return DataSourceBuilder.create().build(); } Bean public SqlSessionFactory taosSqlSessionFactory( Qualifier(taosDataSource) DataSource dataSource) throws Exception { SqlSessionFactoryBean bean new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources(classpath:mapper/taos/*.xml)); return bean.getObject(); } Bean public DataSourceTransactionManager taosTransactionManager( Qualifier(taosDataSource) DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }3.2 Mapper接口与XML的物理隔离建议采用以下项目结构src/main/java └── com.iot.dao ├── mysql │ ├── DeviceMapper.java │ └── UserMapper.java └── taos ├── SensorDataMapper.java └── AlertLogMapper.java src/main/resources └── mapper ├── mysql │ ├── DeviceMapper.xml │ └── UserMapper.xml └── taos ├── SensorDataMapper.xml └── AlertLogMapper.xml3.3 事务管理的明确指定在Service层必须显式声明使用的事务管理器Service public class HybridService { // MySQL操作使用主事务管理器 Transactional(transactionManager mysqlTransactionManager) public void updateDeviceInfo(Device device) { deviceMapper.update(device); } // TDengine操作使用从事务管理器 Transactional(transactionManager taosTransactionManager) public void batchInsertSensorData(ListSensorData dataList) { sensorDataMapper.batchInsert(dataList); } // 跨库事务需采用最终一致性模式 public void processDeviceAlert(Device device, Alert alert) { updateDeviceStatus(device); // MySQL操作 saveAlertLog(alert); // TDengine操作 // 这里不能保证原子性需要业务层补偿机制 } }4. 性能优化实战技巧4.1 TDengine的表设计策略针对物联网场景的典型优化方案超级表子表模式CREATE STABLE IF NOT EXISTS sensors ( ts TIMESTAMP, temperature FLOAT, humidity FLOAT ) TAGS (device_id BINARY(64), region BINARY(32)); -- 每个设备自动建子表 INSERT INTO device_001 USING sensors TAGS (device_001, east) VALUES (now, 25.3, 60.2);批量写入优化Repository public interface SensorDataMapper { Insert({ script, INSERT INTO ${tableName} VALUES, foreach collectionlist itemitem separator,, (#{item.ts}, #{item.value}, #{item.status}), /foreach, /script }) void batchInsert(Param(tableName) String tableName, Param(list) ListSensorData data); }查询性能对比测试环境单节点TDengine 3.0设备数量10万数据总量15亿条查询类型响应时间(MySQL)响应时间(TDengine)单设备最近24小时数据3200ms28ms设备组7天统计报表超时(30s)420ms全系统1小时异常检测不可行680ms4.2 MySQL业务查询优化对于必须保留在MySQL的业务数据建议为设备元数据表添加复合索引ALTER TABLE device_info ADD INDEX idx_region_status (region, status);使用覆盖索引减少回表Select(SELECT device_id, device_name FROM device_info WHERE region #{region}) ListDeviceSimple listByRegion(String region);分页查询优化方案select idselectDevicePage resultTypeDevice SELECT * FROM device_info WHERE id #{lastId} ORDER BY id ASC LIMIT #{pageSize} /select5. 混合查询的优雅实现当需要同时关联业务属性与时序数据时可采用以下模式public ListDeviceDetail getDeviceDashboard(String deviceId) { // 从MySQL获取设备元数据 DeviceMeta meta deviceMapper.selectById(deviceId); // 从TDengine获取实时监测数据 SensorData data sensorDataMapper.selectLatest(deviceId); // 组合业务对象 return DeviceDetail.builder() .deviceId(deviceId) .deviceName(meta.getName()) .location(meta.getLocation()) .currentTemp(data.getTemperature()) .currentHumidity(data.getHumidity()) .status(calculateStatus(data)) .build(); }对于需要复杂关联的场景可以考虑物化视图模式定期将TDengine的统计结果同步到MySQL缓存层加速用Redis缓存热点设备的混合查询结果异步预处理通过消息队列触发后台计算任务在最近的一个智慧楼宇项目中这种混合架构帮助我们将系统响应时间从平均4.7秒降低到380毫秒同时存储成本下降60%。某能源监控平台实施后单服务器最高支持了12万台设备的实时数据采集95%的查询响应时间在1秒内完成。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2464553.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!