MySQL 读写分离
MySQL 读写分离
一、配置主库(Master)
1.修改主库的配置文件
修改主库的 my.cnf
配置文件,生成二进制日志 (binary log) 和服务器唯一ID,这是实现主从复制的必要配置
[mysqld]
# skip-grant-tables
user=root
port=3306
basedir=/usr/local/mysql
datadir=/data/mysql
socket=/usr/local/mysql/socket/mysql.sock
# Disabling symbolic-links is recommended to prevent assorted security risks
# Settings user and group are ignored when systemd is used.
# If you need to run mysqld under a different user or group,
# customize your systemd unit file for mariadb according to the
# instructions in http://fedoraproject.org/wiki/Systemd
log-error=/usr/local/mysql/logs/mysqld.log
pid_file=/var/run/mysqld/mysqld.pid
symbolic-links=0# master 配置
server-id=1 # 主库的服务器ID,必须唯一
log-bin=mysqls-bin # 开启二进制日志,文件名可选
binlog-format=ROW # (可选,不指定默认 STATEMENT )使用行级复制(推荐)# 需要重启mysql服务,master配置才会生效
2.创建用于复制的用户
- 登录到Mysql 的主库中,创建一个专门的用户供从库使用,用于复制
# 创建用户
CREATE USER '用户名'@'%' IDENTIFIED BY '用户密码';
e.g
CREATE USER 'replica_user'@'%' IDENTIFIED BY 'replica123456';# 给用户赋予 '复制' 的权限
GRANT REPLICATION SLAVE ON *.* TO '用户名'@'%';
e.g
GRANT REPLICATION SLAVE ON *.* TO 'replica_user'@'%';# 这里必须要执行,否则在从库执行 SHOW SLAVE STATUS\G; 时会报错 2061
alter user '用户名'@'%' identified with mysql_native_password by 'mysql数据库登录密码';
e.g
alter user 'replica_user'@'%' identified with mysql_native_password by 'replica123456';# 刷新权限
FLUSH PRIVILEGES;
Tip
从库配置启动 复制时报错
SHOW SLAVE STATUS\G;
报错:Last_IO_Errno: 2061
Last_IO_Error: error connecting to master ‘replica_user@120.77.27.139:3306’ - rery-time: 60 retries: 1 message: Authentication plugin ‘caching_sha2_password’ reported error: Auhentication requires secure connection.
3 获取主库的二进制日志位置
- 锁住主库防止数据变化,获取当前的二进制文件名和位置
# 锁住主库
mysql> FLUSH TABLES WITH READ LOCK;
Query OK, 0 rows affected (0.01 sec)# 获取当前二进制文件名和位置
mysql> SHOW MASTER STATUS;
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| mysqls-bin.000001 | 157 | | | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)# 解锁主库
mysql> UNLOCK TABLES;
Query OK, 0 rows affected (0.00 sec)
二、配置从库(Slave)
1.修改从库的配置文件
- 在从库的MySQL的配置文件
my.cnf
中进行必要的配置,确保其有唯一的服务器ID并启用中继日志
[mysqld]
server-id=2 # 从库的服务器ID,确保唯一
relay-log=relay-bin # 启用中继日志(用于接收主库的二进制日志)
replicate-do-db=tbb-iov # 指定从主库中需要复制的数据库
read-only=1 # 只读
2.连接到主库并启动复制
- 登录从库,通过以下配置指定主库的信息并启动复制
CHANGE MASTER TOMASTER_HOST='主库的IP地址', # 主库的IP地址MASTER_PORT=3306, -- 如果主库使用非默认端口,这里需要指定 MASTER_USER='replica_user', # 复制用户MASTER_PASSWORD='replica_password', # 复制用户的密码MASTER_LOG_FILE='mysql-bin.000001', # 主库的二进制日志文件名MASTER_LOG_POS=154; # 主库的二进制日志位置e.g
CHANGE MASTER TOMASTER_HOST='1x0.xx.xx.13x',MASTER_PORT=3306,MASTER_USER='replica_user',MASTER_PASSWORD='replica123456',MASTER_LOG_FILE='mysqls-bin.000001',MASTER_LOG_POS=157;
- 启动从库的复制相关命令
# 启动
START SLAVE;
# 停止
STOP SLAVE;
# 查看同步状态
SHOW SLAVE STATUS\G;
- 主从复制状态参数
Slave_IO_State: Waiting for source to send eventMaster_Host: xx.xx.xx.xxMaster_User: replica_userMaster_Port: 3306Connect_Retry: 60Master_Log_File: mysqls-bin.000001Read_Master_Log_Pos: 7657Relay_Log_File: relay-bin.000006Relay_Log_Pos: 2135Relay_Master_Log_File: mysqls-bin.000001Slave_IO_Running: YesSlave_SQL_Running: YesReplicate_Do_DB: tbb-iov,demo
Slave_IO_Running 和 Slave_SQL_Running 必须要为 Yes 才表示成功启动主从复制
- 查询同步状态的参数说明
连接和状态信息
Slave_IO_State: 当前 IO 线程的状态。例如,Waiting for source to send event 表示从库正在等待主库发送事件。
Master_Host: 主库的 IP 地址或主机名。
Master_User: 用于复制的用户名。
Master_Port: 主库的端口号。
Connect_Retry: 从库尝试重新连接到主库的间隔时间(秒)。
Master_Log_File: 当前正在读取的主库二进制日志文件。
Read_Master_Log_Pos: 当前读取的主库二进制日志的位置。
Relay_Log_File: 当前正在使用的中继日志文件。
Relay_Log_Pos: 当前中继日志的位置。
Relay_Master_Log_File: 当前中继日志对应的主库二进制日志文件。
Slave_IO_Running: IO 线程是否正在运行。Yes 表示正在运行,No 表示停止。
Slave_SQL_Running: SQL 线程是否正在运行。Yes 表示正在运行,No 表示停止。
Slave_SQL_Running_State: SQL 线程的当前状态。例如,Replica has read all relay log; waiting for more updates 表示从库已经读取了所有中继日志,正在等待更多的更新。复制过滤规则
Replicate_Do_DB: 需要复制的数据库列表。
Replicate_Ignore_DB: 不需要复制的数据库列表。
Replicate_Do_Table: 需要复制的表列表。
Replicate_Ignore_Table: 不需要复制的表列表。
Replicate_Wild_Do_Table: 需要复制的表的通配符模式。
Replicate_Wild_Ignore_Table: 不需要复制的表的通配符模式。错误信息
Last_Errno: 最近一次错误的错误码。
Last_Error: 最近一次错误的错误信息。
Skip_Counter: 跳过的错误事务计数器。
Exec_Master_Log_Pos: 当前已执行的主库二进制日志的位置。
Last_IO_Errno: 最近一次 IO 错误的错误码。
Last_IO_Error: 最近一次 IO 错误的错误信息。
Last_SQL_Errno: 最近一次 SQL 错误的错误码。
Last_SQL_Error: 最近一次 SQL 错误的错误信息。其他信息
Relay_Log_Space: 中继日志占用的空间大小(字节)。
Until_Condition: 停止复制的条件。
Until_Log_File: 停止复制的日志文件。
Until_Log_Pos: 停止复制的日志位置。
Master_SSL_Allowed: 是否允许 SSL 连接。
Master_SSL_CA_File: SSL 证书颁发机构文件路径。
Master_SSL_CA_Path: SSL 证书颁发机构路径。
Master_SSL_Cert: SSL 证书文件路径。
Master_SSL_Cipher: SSL 密码套件。
Master_SSL_Key: SSL 私钥文件路径。
Seconds_Behind_Master: 从库落后于主库的时间(秒)。
Master_SSL_Verify_Server_Cert: 是否验证主库的 SSL 证书。
Master_Server_Id: 主库的服务器 ID。
Master_UUID: 主库的 UUID。
Master_Info_File: 存储主库信息的文件。
SQL_Delay: SQL 线程延迟时间(秒)。
SQL_Remaining_Delay: 剩余的延迟时间。
Replicate_Ignore_Server_Ids: 不需要复制的服务器 ID 列表。
Master_Retry_Count: 从库尝试重新连接到主库的最大次数。
Master_Bind: 绑定的网络接口。
Last_IO_Error_Timestamp: 最近一次 IO 错误的时间戳。
Last_SQL_Error_Timestamp: 最近一次 SQL 错误的时间戳。
Master_SSL_Crl: SSL 证书吊销列表文件路径。
Master_SSL_Crlpath: SSL 证书吊销列表路径。
Retrieved_Gtid_Set: 已检索的 GTID 集合。
Executed_Gtid_Set: 已执行的 GTID 集合。
Auto_Position: 是否启用自动定位(基于 GTID)。
Replicate_Rewrite_DB: 数据库重写规则。
Channel_Name: 复制通道名称。
Master_TLS_Version: 主库支持的 TLS 版本。
Master_public_key_path: 主库的公钥文件路径。
Get_master_public_key: 是否获取主库的公钥。
Network_Namespace: 网络命名空间。
Tip
数据库开启主从复制之前,主库和从库的数据需要保持一致,
三、Spring Boot + MySQL+ Mybatis 主从复制,读写分离
1、Maven 依赖引入
主要依赖如下
<properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.6.13</spring-boot.version><mybatis.version>2.2.2</mybatis.version><mysql.version>8.0.30</mysql.version><alibabadruid.version>1.2.16</alibabadruid.version><lombok.version>1.18.26</lombok.version></properties>
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- web依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- aop --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- mybatis --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis.version}</version></dependency><!-- mysql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><!-- druid mysql数据库连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${alibabadruid.version}</version></dependency><!-- lombok 工具 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency></dependencies>
2、mysql主从配置
自定义mysql的主从数据源的连接参数,以及mybatis的配置
server:port: 8082# 自定义mysql配置
mysql:datasource:master:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://ip1:port/demo?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=trueusername: xxxpassword: xxxinitial-size: 5max-active: 20min-idle: 5max-wait: 60000time-between-eviction-runs-millis: 60000min-evictable-idle-time-millis: 300000max-evictable-idle-time-millis: 900000validation-query: SELECT 1 FROM DUALtest-while-idle: truetest-on-borrow: falsetest-on-return: falsepool-prepared-statements: truemax-open-prepared-statements: 50max-pool-prepared-statement-per-connection-size: 20filters: stat,walluse-global-data-source-stat: trueconnect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000slave:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://ip2:port/demo?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=trueusername: xxxx # 这里的账号最好是只读权限的mysql用户,从库只负责读,不能写入数据password: xxxxinitial-size: 5max-active: 25min-idle: 5max-wait: 60000time-between-eviction-runs-millis: 60000min-evictable-idle-time-millis: 300000max-evictable-idle-time-millis: 900000validation-query: SELECT 1 FROM DUALtest-while-idle: truetest-on-borrow: falsetest-on-return: falsepool-prepared-statements: truemax-open-prepared-statements: 50max-pool-prepared-statement-per-connection-size: 20filters: stat,walluse-global-data-source-stat: trueconnect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000# 指定mapper*.xml加载位置
mybatis:config-location: classpath:mybatis/mybatis-config.xmlmapper-locations: classpath:mybatis/mapper/*.xml
3、数据源配置
1. DataSourceConfig 数据源配置类
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.datasource.demo.enums.DataSourceType;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;import java.util.HashMap;
import java.util.Map;/*** ClassName: DataSourceConfig* Package: com.datasource.demo.config* Description:* 数据源配置** @Author wfk* @Create 2024/11/12 14:15* @Version 1.0*/
@Configuration
public class DataSourceConfig {/*** 主库数据源** @return*/@Bean("master")@ConfigurationProperties(prefix = "mysql.datasource.master")public DruidDataSource dataSource1() {return DruidDataSourceBuilder.create().build();}/*** 从库数据源** @return*/@Bean("slave")@ConfigurationProperties(prefix = "mysql.datasource.slave")public DruidDataSource dataSource2() {return DruidDataSourceBuilder.create().build();}/*** 配置默认数据源** @param masterDataSource* @param slaveDataSource** 必须要加 @Primary 注解,优先下面的配置* @return*/@Primary@Bean("dynamicDataSource")public DynamicDataSource dataSource(@Qualifier("master") DruidDataSource masterDataSource,@Qualifier("slave") DruidDataSource slaveDataSource) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DataSourceType.MASTER.getName(), masterDataSource);targetDataSources.put(DataSourceType.SLAVE.getName(), slaveDataSource);DynamicDataSource dynamicDataSource = new DynamicDataSource();dynamicDataSource.setTargetDataSources(targetDataSources);dynamicDataSource.setDefaultTargetDataSource(masterDataSource);return dynamicDataSource;}
}
以上源码分析:
-
采用了阿里云的Druid数据库连接池,所以需要使用 DruidDataSource
-
@ConfigurationProperties(prefix = “mysql.datasource.slave”) 加载 yml 配置文件的自定义属性,自定义参数名称需要和 druid 的配置的标准名称一样,不然无法自动加载
-
DynamicDataSource 继承了 抽象类 AbstractRoutingDataSource,是实现动态数据源的核心类,将所有数据源注入到这个类中,通过 DataSourceContextHolder 修改数据源,实现动态切换。
-
@Primary 注解必须要加上,标记为优先使用的数据源
2.DataSourceContextHolder 数据源上下文
/*** ClassName: DataSourceContextHolder* Package: com.datasource.demo.config.datasource* Description:* 本地线程,数据源上下文* @Author wfk* @Create 2024/11/12 14:45* @Version 1.0*/
public class DataSourceContextHolder {// 定义一个 ThreadLocal 变量,用于保存当前线程的数据源标识private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();// 设置当前线程的数据源标识public static void setDataSource(String dataSource){contextHolder.set(dataSource);}// 获取当前线程的数据源标识public static String getDataSource(){return contextHolder.get();}// 清除当前线程的数据源标识public static void clearDataSource(){contextHolder.remove();}
}
以上源码分析:
-
ThreadLocal
是一个线程局部变量容器,每个线程都有自己独立的副本。这意味着每个线程都可以独立地设置和获取自己的ThreadLocal
变量值,而不会影响其他线程。 -
setDataSource(String dataSource)
方法用于设置当前线程的数据源标识。调用这个方法时,传入的数据源标识会被保存在当前线程的ThreadLocal
变量中。 -
getDataSource()
方法用于获取当前线程的数据源标识。这个方法通常在数据源路由逻辑中被调用,根据当前线程的数据源标识选择合适的数据源进行数据库操作。 -
clearDataSource()
方法用于清除当前线程的数据源标识。这个方法通常在请求处理完毕后被调用,以释放资源并防止内存泄漏。
3.DynamicDataSource 数据源路由
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/*** ClassName: DynamicDataSource* Package: com.datasource.demo.config.datasource* Description:* * @Author wfk* @Create 2024/11/12 14:42* @Version 1.0*/
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {String dataSource = DataSourceContextHolder.getDataSource();log.info("当前数据源 {}", dataSource);return dataSource;}
}
以上源码分析:
-
AbstractRoutingDataSource
是 Spring 框架提供的一个抽象类,用于实现数据源的动态切换。它提供了一个determineCurrentLookupKey
方法,该方法返回一个键值,用于从配置的数据源映射中查找当前应使用的数据源。 -
determineCurrentLookupKey
方法用于确定当前线程应该使用哪个数据源,通过调用DataSourceContextHolder.getDataSource()
来获取当前线程的数据源标识
4.DataSourceType 自定义数据源类别枚举
public enum DataSourceType {MASTER("master"),SLAVE("slave");private String name;DataSourceType(String name) {this.name = name;}public String getName() {return name;}
}
4、数据源切换
1.自定义注解实现
自定义注解,作用于方法上,通过AOP切面拦截,根据注解的value所对应的数据库源类别,实现数据源切换。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBDataSource {DataSourceType value() default DataSourceType.MASTER;
}
2.AOP切面实现
import com.datasource.demo.annotions.DBDataSource;
import com.datasource.demo.config.datasource.DataSourceContextHolder;
import com.datasource.demo.enums.DataSourceType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
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.aspectj.lang.annotation.Aspect;import java.lang.reflect.Method;/*** ClassName: DataSourceAspect* Package: com.datasource.demo.aspect* Description:* 数据源AOP切面** @Author wfk* @Create 2024/11/12 16:05* @Version 1.0*/@Slf4j
@Aspect
@Component
public class DataSourceAspect {@Pointcut("execution(* com.datasource.demo.service..*.*(..))")public void aspect() {}@Before("aspect()")private void doBefore(JoinPoint joinPoint) {Object target = joinPoint.getTarget();Class<?> clazz = target.getClass();// 获取方法签名MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();// 获取方法名称String methodName = methodSignature.getName();// 获取方法参数列表Class<?>[] parameterTypes = methodSignature.getMethod().getParameterTypes();try {// 通过方法名称和参数列表可以唯一获取方法(可能有重载的同名方法)Method method = clazz.getMethod(methodName, parameterTypes);// 判断方法是否存在指定的注解if (method !=null && method.isAnnotationPresent(DBDataSource.class)){DBDataSource annotation = method.getAnnotation(DBDataSource.class);// 如果是从库那就切换当前线程的数据源if (DataSourceType.SLAVE == annotation.value()) {DataSourceContextHolder.setDataSource(DataSourceType.SLAVE.getName());return;}}} catch (NoSuchMethodException e) {e.printStackTrace();}// 默认是使用主库DataSourceContextHolder.setDataSource(DataSourceType.MASTER.getName());}
}
以上源码分析:
1.@Pointcut("execution( com.datasource.demo.service….(…))")*
execution()
:这是定义切入点表达式的关键字,用来匹配Java方法的执行连接点。*
:第一个星号表示返回值类型,这里的星号意味着匹配任何返回类型的方法。‘com.datasource.demo.service…*
.*
(…):这部分是切入点表达式的主体,指定了要匹配的方法的位置和名称。com.datasource.demo.service
:这是包名,指明了要匹配的方法所在的包。..
:两个点号表示该包下的所有子包。*.*
:第一个星号代表类名,第二个星号代表方法名,这里使用两个星号表示匹配该包及其子包下所有类的所有方法。(..)
:括号内的两个点号表示参数列表,这里表示匹配任何参数列表的方法。
2.方法调用和注解检查
- 获取目标对象和方法签名。
- 通过反射获取方法对象,并检查方法是否标注了
DBDataSource
注解。 - 如果方法标注了
DBDataSource
注解且注解值为DataSourceType.SLAVE
,则设置当前线程的数据源为从库。 - 否则,默认设置当前线程的数据源为主库。
3.最终实现如下
在service层的实现类中,添加注解,查询相关的业务,通过注解指定从库,写入数据默认使用主库,实现读写分离。
@DBDataSource(DataSourceType.SLAVE)
@Override
public List<BookInfoPO> getBookInfoList() {return bookInfoMapper.getBookInfoListMapper();
}
总结
关于数据源切换还有很多种方式
- 在mapper层做拦截,对insert、update、delete 和 select 完全分离,可以通过MyCat、shardingsphere 等数据库中间件实现自动分离。
- 也可以通过规范方法名前缀,对get、find、query 开头等方法进行拦截,也可以实现读写分离。
相关文章:
MySQL 读写分离
MySQL 读写分离 一、配置主库(Master) 1.修改主库的配置文件 修改主库的 my.cnf 配置文件,生成二进制日志 (binary log) 和服务器唯一ID,这是实现主从复制的必要配置 [mysqld] # skip-grant-tables userroot port3306 basedir/usr/local/mysql datad…...
记一次音频无输出的解决方案
啊啊啊,刷个抖音就发现个死电脑死都不出声,捣鼓了一天才解决 打开wav文件时,提示错误找不到音频播放设备 0xc00d36fa 起初以为是声卡坏了,就到官网下载、更新了声卡驱动。无用什么驱动精灵也检测了,但也测不出啥来。…...
3D数学基础2
矩阵的行列式 在任意方阵中都存在至少一个标量,称作该方阵的行列式。在线性代数中,行列式有很多有用的性质 线性运算法则 方阵 M M M的行列式记作 ∣ M ∣ |M| ∣M∣或“det M”。非方阵矩阵的行列式是未定义的。 注意,在书写行列式时&…...
Java开发生态2024年度总结报告
1 关键要点 尽管数据显示 Java 17 是最常用 JDK,但其用户占比并未超过半数。根据 New Relic 2024 Java 生态系统状态报告,Java 17、11 和 8 的用户比例分别为 35%、33% 和 29%。New Relic 数据中所谓“快速采用”指 Java 21 的采用率仅为 1.4%。虽相较 J…...
1月第三讲:Java子线程无法获取Attributes的解决方法
在Java多线程编程中,开发者经常会遇到子线程无法获取主线程设置的Attributes的问题。Attributes通常用于存储与当前线程相关的数据,尤其在Web应用中,它们常用于请求上下文的管理。然而,由于Java线程是独立运行的,每个线…...
更新金碟云星空单据供应商和币别
--应付单 select FSUPPLIERID from [dbo].[T_AP_PAYABLE] where FBILLNO=AP2024121670 select FSUPPLIERID,FCURRENCYID,* from [dbo].[T_AP_PAYABLE] where FBILLNO=AP2024121670 -- update T_AP_PAYABLE set FSUPPLIERID=100567 where FBILLNO=AP2024121670 -- update T_…...
from memory cache 修复记录
背景 浏览器的页签图标,不想要了 改代码:设置浏览器页签的代码 本地环境测试,没有问题,一次性修改成功 于是打包,部署到测试环境,然而,还是有 接下的解决方法: 1、清除浏览器缓…...
spring入门程序
安装eclipse https://blog.csdn.net/qq_36437991/article/details/131644570 新建maven项目 安装依赖包 pom.xml <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation&quo…...
用于实现无缝滚动效果的vue-seamless-scroll插件
它通常用于在网页或应用中实现内容的自动滚动效果,如新闻公告、图片轮播等,支持横向和纵向滚动,并且可以自定义滚动速度、方向等参数,适合展示一些需要持续循环展示的信息。 在Vue2项目中使用vue-seamless-scroll插件的步骤如下&…...
借助 FinClip 跨端技术探索鸿蒙原生应用开发之旅
在当今数字化浪潮汹涌澎湃的时代,移动应用开发领域正经历着深刻的变革与创新。鸿蒙操作系统的崛起,以其独特的分布式架构和强大的性能表现,吸引了众多开发者的目光。而FinClip 跨端技术的出现,为开发者涉足鸿蒙原生应用开发提供了…...
【机器学习】机器学习的基本分类-自监督学习-对比学习(Contrastive Learning)
对比学习是一种自监督学习方法,其目标是学习数据的表征(representation),使得在表征空间中,相似的样本距离更近,不相似的样本距离更远。通过设计对比损失函数(Contrastive Loss)&…...
python之eval函数
功能:将字符串str当成有效的表达式来求值并返回计算结果 语法:eval(source,[,globals[,locals]])->value 参数: source:一个python表达式或函数compile()返回的代码对象globals:可选。必须是dictionarylocals&am…...
NXP i.MX8系列平台开发讲解 - 5.3 调试篇(二) - 掌握Dynamic debug调试
专栏文章目录传送门:返回专栏目录 Hi, 我是你们的老朋友,主要专注于嵌入式软件开发,有兴趣不要忘记点击关注【码思途远】 文章目录 目录 掌握Dynamic debug调试 1. 认识Dynamic debug 2. 内核配置 3. 使用Dynamic debug 3.1 查看当前的…...
QT----------常用界面组件的使用
一、QComboBox 类 主要功能:提供一个下拉列表,用户可以从中选择一个或多个选项。 #include <QApplication> #include <QComboBox> #include <QVBoxLayout> #include <QWidget> #include <QMessageBox>int main(int argc…...
重新整理机器学习和神经网络框架
本篇重新梳理了人工智能(AI)、机器学习(ML)、神经网络(NN)和深度学习(DL)之间存在一定的包含关系,以下是它们的关系及各自内容,以及人工智能领域中深度学习分支对比整理。…...
AJAX详解
AJAX是前后端交互的重要工具 结合前后端交互基础理解:前后端交互详解(建议收藏)-CSDN博客 1. AJAX - 到底什么是Ajax? ajax 全名 async javascript and XML(异步JavaScript和XML),是一种用于向服务器异步发送 HTTP 请求并接收响应的技术。 XML 指可扩…...
golang中的异常处理机制
今天是2024最后一天,祝大家新年梦想成真,继续我的魅力golang,昨天发的错误处理,是明显的可预见、可恢复的问题,然而,不可预见的问题,往往更多,golang也有自己的一套,完全…...
HTML5 开关(Toggle Switch)详细讲解
HTML5 开关(Toggle Switch)详细讲解 1. 任务概述 开关(Toggle Switch)是一种用于表示二元状态(如开/关)的用户界面控件。用户可以通过点击开关来切换状态,常见于设置选项、开关功能等场景。 2…...
【前端】Node.js使用教程
目录 一、?Node.js开发环境和编译 1.1 安装Node.js 1.2 创建一个Node.js项目 1.3 编写Node.js程序 1.4 运行Node.js程序 1.5 使用Node.js模块 二、高级的Node.js编程概念和示例 2.1 异步编程 2.2 错误处理 2.3 网络请求 2.4 构建Web服务器 2.5 数据库交互 三、No…...
在CodeBlocks搭建SDL2工程构建TFT彩屏模拟器虚拟TFT彩屏幕显示
在CodeBlocks搭建SDL2工程构建TFT彩屏模拟器虚拟TFT彩屏幕显示 参考文章源码下载地址一、SDL2的创建、初始化、退出二、系统基本Tick、彩屏刷新、按键事件三、彩屏获取与设置颜色四、彩屏填充颜色及清屏五、彩屏显示中文和英文字符串六、彩屏显示数字七、彩屏初始化八、主函数测…...
BurstAttention:高效的分布式注意力计算框架
BurstAttention:高效的分布式注意力计算框架 在现代大型语言模型(LLMs)的应用中,提升注意力机制的计算效率已成为研究的热点。当前,提升计算效率主要有两种方法:一种是优化单设备的计算和存储能力…...
sentinel集成nacos启动报[check-update] get changed dataId error, code: 403错误排查及解决
整合nacos报403错误 因为平台写的一个限流代码逻辑有问题,所以准备使用sentinel来限流。平台依赖里面已经引入了,之前也测试过,把sentinel关于nacos的配置加上后,启动一直输出403错误 [fixed-10.0.20.188_8848-test] [check-upda…...
[TOTP]android kotlin实现 totp身份验证器 类似Google身份验证器
背景:自己或者公司用一些谷歌身份验证器或者microsoft身份验证器,下载来源不明,或者有广告,使用不安全。于是自己写一个,安全放心使用。 代码已开源:shixiaotian/sxt-android-totp: android totp authenti…...
IDEA+Docker一键部署项目SpringBoot项目
文章目录 1. 部署项目的传统方式2. 前置工作3. SSH配置4. 连接Docker守护进程5. 创建简单的SpringBoot应用程序6. 编写Dockerfile文件7. 配置远程部署 7.1 创建配置7.2 绑定端口7.3 添加执行前要运行的任务 8. 部署项目9. 开放防火墙的 11020 端口10. 访问项目11. 可能遇到的问…...
【发票提取明细+发票号改名】批量提取PDF电子发票明细导出Excel表格并改名技术难点,批量PDF多区域内容识别提取明细并用内容改名的小结
1、图片版的发票提取表格改名 【批量图片发票识别表格】批量图片发票的提取Excel表格和提取字段改名,扫描发票识别表格,拍照发票识别表格,图片发票识别改名我们在工作中很多扫描发票,拍照发票,需要整理成excel表格&am…...
pyQT + OpenCV相关练习
一、设计思路 1、思路分析与设计 本段代码是一个使用 PyQt6 和 OpenCV 创建的图像处理应用程序。其主要功能是通过一个图形界面让用户对图片进行基本的图像处理操作,如灰度化、翻转、旋转、亮度与对比度调整,以及一些滤镜效果(模糊、锐化、边…...
石岩路边理发好去处
周末带娃去罗租公园玩,罗租公园旁边就是百佳华和如意豪庭小区,发现如意豪庭小区对面挺多路边理发摊点 理发摊点聚焦在这里的原因是刚好前面城管来了暂时避避,例如还有一个阿姨剪到一半就跟着过来。这里的城管只是拍了一处没有摊位的地方&…...
音视频入门基础:MPEG2-PS专题(2)——使用FFmpeg命令生成ps文件
一、错误的命令 通过FFmpeg命令可以将mp4文件转换为ps文件,PS文件中包含PS流数据。 由于PS流/PS文件对应的FFInputFormat结构为: const FFInputFormat ff_mpegps_demuxer {.p.name "mpeg",.p.long_name NULL_IF_CONFIG_SMALL…...
整合版canal ha搭建--基于1.1.4版本
开启MySql Binlog(1)修改MySql配置文件(2)重启MySql服务,查看配置是否生效(3)配置起效果后,创建canal用户,并赋予权限安装canal-admin(1)解压 canal.admin-1…...
[python SQLAlchemy数据库操作入门]-15.联合查询,跨表获取股票数据
哈喽,大家好,我是木头左! 在开始探讨如何利用SQLAlchemy实现复杂的联合查询之前,首先需要深入理解其核心组件——对象关系映射(ORM)。ORM允许开发者使用Python类来表示数据库中的表,从而以一种更直观、面向对象的方式来操作数据库。 SQLAlchemy中的JOIN操作详解 在SQLA…...
PTA数据结构作业一
6-1 链表的插入算法 本题要求实现一个插入函数,实现在链表llist中的元素x之后插入一个元素y的操作。 函数接口定义: int InsertPost_link(LinkList llist, DataType x, DataType y); 其中 llist是操作的链表,x是待插入元素y的前驱节点元素…...
前端(九)js介绍(2)
js介绍(2) 文章目录 js介绍(2)一、函数1.1函数的两种形式1.2函数的作用域1.3声明与提升 二、bom操作三、dom操作 一、函数 1.1函数的两种形式 //有参函数 //js中的函数只能返回一个值,如果要返回多个需要放在数组或对象中 function func(a,b){return ab } func(1,…...
CUTLASS:高性能 CUDA 线性代数模板库详解
CUTLASS:高性能 CUDA 线性代数模板库详解 引言什么是 CUTLASS?CUTLASS 的主要特点: CUTLASS 的用途如何安装 CUTLASS1. 环境准备2. 下载 CUTLASS3. 构建 CUTLASS4. 设置环境变量5. 验证安装 使用 CUTLASSCUTLASS 的优势总结 引言 在深度学习…...
关于CISP报名费用详情
CISP即“注册信息安全专业人员”,是中国信息安全测评中心实施的国家认证项目,旨在培养信息安全领域的专业人才。对于有意报考CISP的考生而言,了解报名考试费用是备考过程中不可或缺的一环。 CISP的报名考试费用主要包括培训费用、考试费用、…...
css 关于flex布局中子元素的属性flex
css flex布局中子元素的属性flex 1. flex 是 flex-grow、flex-shrink 和 flex-basis 的简写 语法格式: flex: [flex-grow] [flex-shrink] [flex-basis];各属性解析: flex-grow: 子元素如何按比例分配父元素的 剩余空间。 默认值:0&#…...
功率器件热设计基础(四)——功率半导体芯片温度和测试方法
/ 前言 / 功率半导体热设计是实现IGBT、碳化硅SiC高功率密度的基础,只有掌握功率半导体的热设计基础知识,才能完成精确热设计,提高功率器件的利用率,降低系统成本,并保证系统的可靠性。 功率器件热设计基础系列文章会…...
OpenStack系列第四篇:云平台基础功能与操作(Dashboard)
文章目录 1. 镜像(Image)添加镜像查看镜像删除镜像 2. 卷(Volume)创建卷查看卷删除卷 3. 网络(虚拟网络)创建网络查看网络删除网络 4. 实例类型创建实例类型查看实例类型删除实例类型 4. 密钥对(…...
WebSocket封装
提示:记录工作中遇到的需求及解决办法 文章目录 前言二、背景三、WebSocket3.1 什么是 WebSocket ?为什么使用他?四、封装 WebSocket4.1 Javascript 版本4.2 Typescript 版本4.3 如何使用?五、我的痛点如何处理前言 本文将介绍 WebSocket 的封装,比如:心跳机制,重连和一…...
面试题解,JVM的运行时数据区
一、请简述JVM运行时数据区的组成结构及各部分作用 总览 从线程持有的权限来看 线程私有区 虚拟机栈 虚拟机栈是一个栈结构,由许多个栈帧组成,一个方法分配一个栈帧,线程每执行一个方法时都会有一个栈帧入栈,方法执行结束后栈帧…...
【Ubuntu使用技巧】Ubuntu22.04无人值守Crontab工具实战详解
一个愿意伫立在巨人肩膀上的农民...... Crontab是Linux和类Unix操作系统下的一个任务调度工具,用于周期性地执行指定的任务或命令。Crontab允许用户创建和管理计划任务,以便在特定的时间间隔或时间点自动运行命令或脚本。这些任务可以按照分钟、小时、日…...
Caffeine Cache Java缓存组件
缓存组件Caffeine Cache 定义介绍整合springboot用法整合spring-boot-starter-cache用法 定义介绍 特性 高性能:基于高效并发设计和 TinyLFU 算法,命中率高。 丰富策略:支持容量限制、过期时间、异步加载、自定义清理策略。 统计监控&#x…...
电子电气架构 --- 什么是自动驾驶技术中的域控制单元(DCU)?
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的…...
Redis核心技术知识点全集
Redis数据结构和常用命令 1. String字符串2. Hash哈希3. List列表4. Set集合5. Sorted Set有序集合6. Redis常用命令参考Redis事务机制...
【每日学点鸿蒙知识】文件读写、屏幕宽度亮度、扫一扫权限、编码器问题、wlan设置
1、参照文档,在操作文件时,读取不到内容或出现程序闪退? 参照文档,进行文件写入和读取时,出现读取不到或闪退 export function createFile() {// 获取应用文件路径let context getContext(this) as common.UIAbilit…...
后端开发-Maven
环境说明: windows系统:11版本 idea版本:2023.3.2 Maven 介绍 Apache Maven 是一个 Java 项目的构建管理和理解工具。Maven 使用一个项目对象模型(POM),通过一组构建规则和约定来管理项目的构建…...
LiteFlow 流程引擎引入Spring boot项目集成pg数据库
文章目录 官网地址简要项目引入maven 所需jar包配置 PostgreSQL 数据库表使用LiteFlow配置 yml 文件通过 代码方式使用 liteflow数据库sql 数据在流程中周转 官网地址 https://liteflow.cc/ 简要 如果你要对复杂业务逻辑进行新写或者重构,用LiteFlow最合适不过。…...
电子电气架构 --- 汽车电子电器设计概述
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的…...
API 设计:从基础到最佳实践
https://levelup.gitconnected.com/api-design-101-from-basics-to-best-practices-a0261cdf8886 在本次深入研究中,我们将从基础开始,逐步了解 API 设计,并逐步实现定义卓越 API 的最佳实践。 作为开发人员,您可能熟悉其中的许多…...
简易内存池(中)
提示:文章 文章目录 前言一、背景二、第二版代码用例2用例3用例4用例5 总结 前言 前期疑问: 本文目标: 一、背景 最近 二、 针对上述失败用例,修改代码如下 第二版代码 #include <stdbool.h> #include <stdio.h>…...
svn不能添加.a文件
解决办法 在home目录下有一个.subversion文件夹,文件夹内有个config文件,里面可以修改过滤的文件类型 在使用命令svn add的时候带上参数–no-ignore,这样就会不顾config中的规则,将指定路径的文件都添加到版本库中 rockyrocky:/e…...