MyBatis多数据源以及动态切换实现(基于SpringBoot 2.7.x)

MyBatis多数据源以及动态切换实现可以实现不同功能模块可以对应到不同的数据库,现在就让我们来讲解一下。

目录

  • 一、引入Maven
  • 二、配置文件
  • 三、实现多数据源
  • 四、动态切换数据源

一、引入Maven

注意:博主这边使用的springboot版本是2.7.14的

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.75</version>
</dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.6</version><scope>provided</scope>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency><!-- MyBatis依赖 -->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version>
</dependency><!-- 数据库连接池依赖(这里以HikariCP为例) -->
<dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId>
</dependency><!-- MySQL驱动 -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.12</version>
</dependency><!-- https://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbc -->
<!-- SQL Server驱动 -->
<dependency><groupId>com.microsoft.sqlserver</groupId><artifactId>mssql-jdbc</artifactId><version>8.2.0.jre8</version>
</dependency><!-- Spring Boot AOP依赖 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

二、配置文件

以application.properties讲解

server.port=8099# MySQL1
spring.datasource.mysqldb1.url=jdbc:mysql://localhost:3306/mysql?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.mysqldb1.username=root
spring.datasource.mysqldb1.password=123456
# MySQL2
spring.datasource.mysqldb2.url=jdbc:mysql://localhost:3306/ke_prd?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.mysqldb2.username=root
spring.datasource.mysqldb2.password=123456
# sqlserver
spring.datasource.sqlserver.url=jdbc:sqlserver://localhost:1433;database=TEST
spring.datasource.sqlserver.username=sa
spring.datasource.sqlserver.password=123#mybatis
#pojo对应路径
mybatis.type-aliases-package=com.zhangximing.springbootmybatis_datasource.pojo
# 默认扫描xml
mybatis.mapper-locations=classpath:mybatis/mapper/**/*.xml
# sqlserver数据库对应扫描xml
custom.mapper.xml.sqlserver=classpath:mybatis/mapper/sqlserver/*.xml
# mysql数据库对应扫描xml
custom.mapper.xml.mysql=classpath:mybatis/mapper/mysql/*.xml
# 动态切换数据库对应扫描xml
custom.mapper.xml.dynamic=classpath:mybatis/mapper/dynamic/*.xml# 编码utf-8
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true

三、实现多数据源

先实现普通的mybatis写法,写三个(两个mysql,一个sqlserver)(冗余的代码不贴出)

接口入口写法都一样,就是名称换了而已,LogMapperMySql 换 LogMapperMySqlT和LogMapperSqlServer

import com.zhangximing.springbootmybatis_datasource.pojo.LogInfo;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;import java.util.List;/*** @Author: zhangximing* @Email: 530659058@qq.com* @Date: 2023/6/14 13:54* @Description: 日志操作*/
/*加了这个注解 就表示了 这是一个Mybatis的mapper类
就相当于之前使用的spring整合mybatis接口 也可以使用@MapperScan("com.kuang.mapper")*/
@Mapper
/**@Component 也可以用这个 万能的*/
@Repository
public interface LogMapperMySql {List<LogInfo> queryLogList();LogInfo queryLogById(int id);int addLog(LogInfo logInfo);int updateLog(LogInfo logInfo);int deleteLog(LogInfo logInfo);
}

xml文件方面,除了namespace需要修改外,当是sqlserver时NOW()函数要改为GETDATE()

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhangximing.springbootmybatis_datasource.mapper.mysql.LogMapperMySql"><select id="queryLogList" resultType="LogInfo">select * from log_center</select><select id="queryLogById" resultType="LogInfo">select * from log_centerwhere id=#{id};</select><insert id="addLog" parameterType="LogInfo">insert into log_center(method,requestJson,responseJson,createDate)values(#{method},#{requestJson},#{responseJson},NOW());</insert><update id="updateLog" parameterType="LogInfo">update mybatis.userset responseJson=#{responseJson},requestJson=#{requestJson}where id=#{id};</update><delete id="deleteLog" parameterType="int">deletefrom log_centerwhere id=#{id};</delete></mapper>

pojo实体 LogInfo

//import io.swagger.annotations.ApiModel;
//import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.io.Serializable;/*** @Author: zhangximing* @Email: 530659058@qq.com* @Date: 2023/5/31 13:07* @Description: 日志实体类*/
@Data
//@ApiModel(value = "日志类")
public class LogInfo implements Serializable {//    @ApiModelProperty(value = "",required = false)private String id;//    @ApiModelProperty(value = "方法名",required = false)private String method;//    @ApiModelProperty(value = "请求参数",required = false)private String requestJson;//    @ApiModelProperty(value = "返回参数",required = false)private String responseJson;//    @ApiModelProperty(value = "创建日期",required = false)private String createDate;
}

开始重点部分啦,如何实现多数据源啦
先写多数据源配置类

package com.zhangximing.springbootmybatis_datasource.config.datasource;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;/*** 多数据源配置类*/
@Configuration
public class DataSourceConfig {@Autowiredprivate Environment env;// 多数据源一:默认mysql// Primary注解是在没有指明使用哪个数据源的时候指定默认使用的主数据源// Primary在无动态切换的情况下可以用@Primary@Bean(name = "mysqlDataSource")//注意:该注解可能失效导致无法直接注入,所以手动获取装配
//    @ConfigurationProperties(prefix = "spring.datasource.mysqldb1")public DataSource mysqlDataSource() {DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();dataSourceBuilder.url(env.getProperty("spring.datasource.mysqldb1.url"));dataSourceBuilder.username(env.getProperty("spring.datasource.mysqldb1.username"));dataSourceBuilder.password(env.getProperty("spring.datasource.mysqldb1.password"));return dataSourceBuilder.build();
//        return DataSourceBuilder.create().build();}// 多数据源二:mysql库2@Bean(name = "mysqlDataSourceT")
//    @ConfigurationProperties(prefix = "spring.datasource.mysqldb2")public DataSource mysqlDataSourceT() {DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();dataSourceBuilder.url(env.getProperty("spring.datasource.mysqldb2.url"));dataSourceBuilder.username(env.getProperty("spring.datasource.mysqldb2.username"));dataSourceBuilder.password(env.getProperty("spring.datasource.mysqldb2.password"));return dataSourceBuilder.build();}// 多数据源三:sqlserver@Bean(name = "sqlserverDataSource")
//    @ConfigurationProperties(prefix = "spring.datasource.sqlserver")public DataSource sqlserverDataSource() {DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();dataSourceBuilder.url(env.getProperty("spring.datasource.sqlserver.url"));dataSourceBuilder.username(env.getProperty("spring.datasource.sqlserver.username"));dataSourceBuilder.password(env.getProperty("spring.datasource.sqlserver.password"));return dataSourceBuilder.build();}

针对数据源配置(mysql)

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import javax.annotation.Resource;
import javax.sql.DataSource;@Configuration
@MapperScan(// 指定该数据源扫描指定包下面的Mapper接口文件basePackages = "com.zhangximing.springbootmybatis_datasource.mapper.mysql",sqlSessionFactoryRef = "sqlSessionFactoryPrimary",sqlSessionTemplateRef = "sqlSessionTemplatePrimary")
public class DataSourceMySqlConfig {// mapper扫描xml文件的路径@Value("${custom.mapper.xml.mysql}")private String MAPPER_LOCATION;private DataSource primaryDataSource;// 通过构造方法进行注入public DataSourceMySqlConfig(@Qualifier("mysqlDataSource") DataSource primaryDataSource) {this.primaryDataSource = primaryDataSource;}/*** SqlSession工厂方法* 用于创建SqlSession对象。* 用于管理SqlSession对象的的生命周期。* 可以根据需要创建不同的SqlSession子类,以支持不同的数据库操作需求。* 可以将SqlSession对象存储在持久化缓存中,以提高性能。* @return* @throws Exception*/@Bean@Primarypublic SqlSessionFactory sqlSessionFactoryPrimary() throws Exception {SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(primaryDataSource);sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION));sqlSessionFactoryBean.setTypeAliasesPackage("com.zhangximing.springbootmybatis_datasource.pojo");return sqlSessionFactoryBean.getObject();}@Bean@Primarypublic SqlSessionTemplate sqlSessionTemplatePrimary() throws Exception {return new SqlSessionTemplate(sqlSessionFactoryPrimary());}
}

针对数据源配置(mysql库2)(sqlserver的参考这个写即可,扫描路径以及配置文件获取修改)

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;import javax.sql.DataSource;/*** sqlserver数据源配置*/
@Configuration
@MapperScan(basePackages = "com.zhangximing.springbootmybatis_datasource.mapper.mysql",sqlSessionFactoryRef = "sqlSessionFactorySecondaryMySql")
public class DataSourceMySqlTConfig {// mapper扫描xml文件的路径@Value("${custom.mapper.xml.mysql}")private String MAPPER_LOCATION;private DataSource secondaryDataSource;// 通过构造方法进行注入public DataSourceMySqlTConfig(@Qualifier("mysqlDataSourceT") DataSource secondaryDataSource) {this.secondaryDataSource = secondaryDataSource;}@Bean("sqlSessionFactorySecondaryMySql")public SqlSessionFactory sqlSessionFactorySecondary() throws Exception {SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();// 指定数据源sqlSessionFactoryBean.setDataSource(secondaryDataSource);/*获取xml文件资源对象当Mapper接口所对应的.xml文件与Mapper接口文件分离,存储在 resources文件夹下的时候,需要手动指定.xml文件所在的路径*/sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION));//指定实体目录sqlSessionFactoryBean.setTypeAliasesPackage("com.zhangximing.springbootmybatis_datasource.pojo");return sqlSessionFactoryBean.getObject();}@Bean("SecondaryDataSourceManagerMySql")public DataSourceTransactionManager SecondaryDataSourceManager() {return new DataSourceTransactionManager(secondaryDataSource);}
}

到这里基本上就可以了,写测试类测试

import com.alibaba.fastjson.JSONObject;
//import io.swagger.annotations.Api;
//import io.swagger.annotations.ApiOperation;
import com.zhangximing.springbootmybatis_datasource.annotation.DataBase;
import com.zhangximing.springbootmybatis_datasource.mapper.mysql.LogMapperMySql;
import com.zhangximing.springbootmybatis_datasource.mapper.mysql.LogMapperMySqlT;
import com.zhangximing.springbootmybatis_datasource.mapper.sqlserver.LogMapperSqlServer;
import com.zhangximing.springbootmybatis_datasource.pojo.LogInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/*** @Author: zhangximing* @Email: 530659058@qq.com* @Date: 2023/5/31 13:00* @Description: 测试接口*/
//@Api(value="日志模块",tags = "日志模块管理")
@RestController
@RequestMapping("/log")
public class LogController {@Autowiredprivate LogMapperMySql logMapper_mysql;@Autowiredprivate LogMapperMySqlT logMapper_mysqlT;@Autowiredprivate LogMapperSqlServer logMapper_sqlserver;//    @ApiOperation(value="插入日志")@PostMapping(value = "/addLog", produces = {"text/plain;charset=UTF-8"})public String addLog(@RequestBody LogInfo logInfo){int cnt = logMapper_sqlserver.addLog(logInfo);JSONObject result = new JSONObject();result.put("count",cnt);return result.toJSONString();}@RequestMapping("/getLogById/{id}")public String getLogById(@PathVariable("id") int logId){System.out.println("logId:"+logId);LogInfo logInfo = logMapper_sqlserver.queryLogById(logId);JSONObject result = new JSONObject();result.put("data",JSONObject.toJSONString(logInfo));return result.toJSONString();}
}

测试结果就不展示了,就手动修改需要调用的数据源进行请求测试

四、动态切换数据源

在第三点的基础上,我们在 多数据源配置类 增加 如下代码

/***  动态数据源配置*/
@Primary
@Bean(name = "dynamicDataSource")
public DataSource dynamicDataSource(){DynamicDataSource dynamicDataSource = new DynamicDataSource();//默认数据源dynamicDataSource.setDefaultTargetDataSource(mysqlDataSource());//配置多数据源Map<Object, Object> dsMap = new HashMap<Object, Object>(5);dsMap.put("mysqldb1", mysqlDataSource());dsMap.put("mysqldb2", mysqlDataSourceT());dsMap.put("sqlserver", sqlserverDataSource());dynamicDataSource.setTargetDataSources(dsMap);return dynamicDataSource;
}/*** 配置@Transactional注解事物(管理事务)*  @return*/
@Bean
public PlatformTransactionManager transactionManager(){return new DataSourceTransactionManager(dynamicDataSource());
}

DynamicDataSource(动态数据源配置类)

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/*** 动态数据源配置*/
public class DynamicDataSource extends AbstractRoutingDataSource {// 确定当前的数据源键@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDB();}
}

DataSourceContextHolder(切换数据库类)

import lombok.extern.slf4j.Slf4j;/*** 上下文切换(切换数据库)*/
@Slf4j
public class DataSourceContextHolder {// 默认数据源public static final String DEFAULT_DS = "mysqldb1";// 本地线程共享变量private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();public static void setDB(String dbType) {log.info("切换至" + dbType + "数据源");contextHolder.set(dbType);}public static String getDB() {return (contextHolder.get());}public static void clearDB() {contextHolder.remove();}
}

增加与mysql配置mybatis一致的xml和接口(由于我们只用一个表测试,所以就以同类型数据库切换进行演示),此处省略代码…

自定义注解(这边打算用注解标记哪些接口需要进行切换数据库的)

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 自定义注解:参数为数据库标识*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataBase {String value() default "mysqldb1";
}

切面部分,这里测试是以请求头传数据库标识来动态实现,也可以通过数据库或配置文件存储多种方式

import com.zhangximing.springbootmybatis_datasource.annotation.DataBase;
import com.zhangximing.springbootmybatis_datasource.config.datasource.DataSourceContextHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;/***  切面拦截切换数据库*/
@Aspect
@Component
public class DataBaseAspect {// 拦截用过注释的@Pointcut("@annotation(com.zhangximing.springbootmybatis_datasource.annotation.DataBase)")public void dbPointCut(){}// 拦截切换数据源@Before("dbPointCut()")public void beforeSwitchDS(JoinPoint point){//获得当前访问的classClass<?> className = point.getTarget().getClass();//获得访问的方法名String methodName = point.getSignature().getName();//得到方法的参数的类型Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();//获取请求头数据库(模拟动态切换数据库)String myDataSource = request.getHeader("dataSource");// 获取默认数据源String dataSource = DataSourceContextHolder.DEFAULT_DS;try {// 得到访问的方法对象Method method = className.getMethod(methodName, argClass);// 判断是否存在@DateBase注解if (method.isAnnotationPresent(DataBase.class)) {DataBase annotation = method.getAnnotation(DataBase.class);// 取出注解中的数据源名dataSource = annotation.value();}if (null != myDataSource && myDataSource.length() > 0){dataSource = myDataSource;}} catch (Exception e) {e.printStackTrace();}// 切换数据源DataSourceContextHolder.setDB(dataSource);}// 结束后清除线程共享变量@After("dbPointCut()")public void afterSwitchDS(JoinPoint point){DataSourceContextHolder.clearDB();}
}

测试类增加如下代码

//置空根据请求头dataSource动态切库@DataBase()@PostMapping(value = "/addLogDy", produces = {"text/plain;charset=UTF-8"})public String addLogDy(@RequestBody LogInfo logInfo){int cnt = logMapperDynamic.addLog(logInfo);JSONObject result = new JSONObject();result.put("count",cnt);return result.toJSONString();}//可注解指定数据库@DataBase("mysqldb2")@RequestMapping("/getLogByIdDy/{id}")public String getLogByIdDy(@PathVariable("id") int logId){System.out.println("logId:"+logId);LogInfo logInfo = logMapperDynamic.queryLogById(logId);JSONObject result = new JSONObject();result.put("data",JSONObject.toJSONString(logInfo));return result.toJSONString();}
--附上表结构创建(mysql)
CREATE TABLE IF NOT EXISTS `log_center`(`id` INT UNSIGNED AUTO_INCREMENT,`method` VARCHAR(200),`requestJson` TEXT,`responseJson` TEXT,`createDate` DATE,PRIMARY KEY ( `id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

整体代码结构
在这里插入图片描述

功能测试正常,大家可以自行试下,代码完整包已放到博主资源(SpringBoot-MyBatis-DataSource(多数据源以及动态切换))。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode:26.删除有序数组中的重复项

26. 删除有序数组中的重复项 - 力扣&#xff08;LeetCode&#xff09; 目录 题目&#xff1a; 思路&#xff1a; 代码注释&#xff1a; 每日表情包&#xff1a; 题目&#xff1a; 思路&#xff1a; 没啥特殊的&#xff0c;老老实实双指针遍历数组&#xff0c;&#xff0…

获取旁站 / C 段:第三方网站(附链接)

一、介绍 1.1 旁段 在网络安全的上下文中&#xff0c;"旁段"&#xff08;Pivot&#xff09;是指攻击者通过入侵一个网络中的一台计算机&#xff0c;然后利用该计算机作为跳板&#xff08;或者称之为“旁道”&#xff09;来访问其他计算机或网络资源的行为。 攻击者…

如何启动若依框架

Mysql安装 一、下载 链接&#xff1a;https://pan.baidu.com/s/1s8-Y1ooaRtwP9KnmP3rxlQ?pwd1234 提取码&#xff1a;1234 二、安装(解压) 下载完成后我们得到的是一个压缩包&#xff0c;将其解压&#xff0c;我们就可以得到MySQL 5.7.24的软件本体了(就是一个文件夹)&…

虚幻5源码版打包服务端

适用情况&#xff0c;windows系统&#xff0c;已经安装vs2022之类的&#xff0c;和UE5适配的版本 源码版使用 1.下载源码版&#xff0c;推荐下载 压缩包 tar.gz那个&#xff0c;zip和git clone我老是下载不下载来&#xff0c;只是这个压缩包要解压1个多小时… 2.点击 源码的…

【RT-DETR有效改进】利用SENetV1重构化网络结构 (ILSVRC冠军得主)

👑欢迎大家订阅本专栏,一起学习RT-DETR👑 一、本文介绍 本文给大家带来的改进机制是SENet(Squeeze-and-Excitation Networks)其是一种通过调整卷积网络中的通道关系来提升性能的网络结构。SENet并不是一个独立的网络模型,而是一个可以和现有的任何一个模型相结合…

自动暂停和恢复网页中的视频播放

序言 在日常开发中&#xff0c;有时候一级栏目可能是个H5页面&#xff0c;当切换到其他栏目的时候需要自动暂停H5中的视频&#xff0c;切换回来以后需要自动恢复播放。实现的思路是通过JS来操作&#xff0c;难点是感知fragment的可见状态。还有js代码的编写。 比如下面这个页…

PyTorch的10个基本张量操作

PyTorch是一个基于python的科学计算包。它的灵活性允许轻松集成新的数据类型和算法&#xff0c;并且框架也是高效和可扩展的&#xff0c;下面我们将介绍一些Pytorch的基本张量操作。 Tensors 张量Tensors是一个向量&#xff0c;矩阵或任何n维数组。这是深度学习的基本数据结构…

DevExpress WinForms中文教程 - 如何创建可访问的WinForms应用?(二)

为用户创建易访问的Windows Forms应用程序不仅是最佳实践的体现&#xff0c;还是对包容性和以用户为中心的设计承诺。在应用程序开发生命周期的早期考虑与可访问性相关的需求可以节省长期运行的时间(因为它将决定设计决策和代码实现)。 一个可访问的WinForms应用程序提供了各种…

20240202在Ubuntu20.04.6下使用whisper.cpp的显卡模式

20240202在Ubuntu20.04.6下使用whisper.cpp的显卡模式 2024/2/2 19:43 【结论&#xff1a;在Ubuntu20.04.6下&#xff0c;确认large模式识别7分钟中文视频&#xff0c;需要356447.78 ms&#xff0c;也就是356.5秒&#xff0c;需要大概5分钟&#xff01;效率太差&#xff01;】 …

CleanMyMac2024如何识别并清理垃圾文件?

CleanMyMac识别并清理垃圾文件的过程主要依赖于其强大的扫描功能和智能算法。以下是具体的步骤&#xff1a; 扫描垃圾文件&#xff1a;首先&#xff0c;用户需要打开CleanMyMac软件&#xff0c;并点击“智能扫描”功能。然后&#xff0c;软件将开始自动扫描Mac系统上的各种垃圾…

微信小程序(基本操作)

概念&#xff1a; 小程序&#xff1a;就是小程序&#xff0c;mini program。现在市面上有微信小程序&#xff0c;百度智能小程序等等。 微信小程序&#xff0c;简称小程序&#xff0c;英文名Mini Program&#xff0c;是一种不需要下载安装即可使用的应用&#xff0c;它实现了…

5-4、S加减单片机程序【51单片机+L298N步进电机系列教程】

↑↑↑点击上方【目录】&#xff0c;查看本系列全部文章 摘要&#xff1a;本节介绍实现步进电机S曲线运动的代码 一、目标功能 实现步进电机转动总角度720&#xff0c;其中加减速各90 加速段&#xff1a;加速类型&#xff1a;S曲线  加速角度&#xff1a;角度为90  起步速度…

CSS太极动态图

CSS太极动态图 1. 案例效果 我们今天学习用HTML和CSS实现动态的太极&#xff0c;看一下效果。 2. 分析思路 太极图是由两个旋转的圆组成&#xff0c;一个是黑圆&#xff0c;一个是白圆。实现现原理是使用CSS的动画和渐变背景属性。 首先&#xff0c;为所有元素设置默认值为0…

Topaz Photo AI for Mac v2.3.1 补丁版人工智能降噪软件无损放大

想要将模糊的图片变得更加清晰&#xff1f;不妨试试Topaz Photo AI for Mac 这款人工智能、无损放大软件。Topaz Photo AI for Mac 一款强大的人工智能降噪软件&#xff0c;允许用户使用复杂的锐化算法来提高图像清晰度&#xff0c;还包括肖像编辑选项&#xff0c;如面部重塑、…

Visual Studio 2010+C#实现信源和信息熵

1. 设计要求 以图形界面的方式设计一套程序&#xff0c;该程序可以实现以下功能&#xff1a; 从输入框输入单个或多个概率&#xff0c;然后使用者可以通过相关按钮的点击求解相应的对数&#xff0c;自信息以及信息熵程序要能够实现马尔可夫信源转移概率矩阵的输入并且可以计算…

Netty源码系列 之 EventLoop run()方法 源码

EventLoop[实现类为NioEventLoop&#xff0c;我们研究NioEventLoop即可] EventLoop是一个单线程的线程池 核心作用&#xff1a;处理执行IO操作&#xff08;accept&#xff0c;read&#xff0c;write事件&#xff09;&#xff0c;普通任务&#xff0c;定时任务 EventLoop封装…

精酿啤酒:发酵过程中的温度控制与效果

在啤酒酿造过程中&#xff0c;发酵温度的控制重要&#xff0c;它不仅影响酵母菌的活性&#xff0c;还决定了啤酒的口感、香气和风味。对于Fendi Club啤酒来说&#xff0c;切确控制发酵温度是确保啤酒品质和口感的关键环节。 在Fendi Club啤酒的发酵过程中&#xff0c;温度控制尤…

c#cad 创建-正方形(四)

运行环境 vs2022 c# cad2016 调试成功 一、程序说明 创建一个正方形&#xff0c;并将其添加到当前活动文档的模型空间中。 程序首先获取当前活动文档和数据库&#xff0c;并创建一个编辑器对象。 然后&#xff0c;使用事务开始创建正方形的操作。获取模型空间的块表记录&a…

Vue3大事件项目(ing)

文章目录 核心内容1.大事件项目介绍2.大事件项目创建3.Eslint配置代码风格4.配置代码检查工作流问题: pnpm lint是全量检查,耗时问题,历史问题 5.目录调整6.vue-router4 路由代码解析7.引入 Element Plus 组件库8.Pinia 构建仓库 和 持久化9.Pinia 仓库统一管理 核心内容 Vue3…

C# 夺冠,微软.NET前途光明!

本文以C# 摘得 “2023 年度编程语言“称号为背景&#xff0c;介绍.NET的历史、生态及发展势头&#xff0c;该文章是本人C#专栏的第一篇文章。 这里写目录标题 1.C#摘得"2023年度编程语言"奖项2.什么是.NET&#xff1f;2.1.NET简史2.2.NET是用于应用程序开发的生态系…