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,一经查实,立即删除!

相关文章

正则表达式 regex

文章目录 参考 参考 https://blog.csdn.net/Conradine_Lian/article/details/108890595 regex可以很简单 也可以很复杂 /* 限定符 修饰前面的一个字符,可以是元字符* 重复0次或更多次 重…

计算机系统基本概念白话解释

时钟&#xff08;Clock&#xff09; 时钟是计算机系统中的一个关键组件&#xff0c;它负责生成一系列的定时信号&#xff0c;以驱动计算机的各种操作和组件。时钟通常以固定的频率发出脉冲信号&#xff0c;这个频率称为时钟频率。时钟频率决定了计算机系统的运行速度。CPU、内…

Python脚本之操作Elasticsearch【二】

本文为博主原创&#xff0c;未经授权&#xff0c;严禁转载及使用。 本文链接&#xff1a;https://blog.csdn.net/zyooooxie/article/details/124640467 之前分享过 使用elasticsearch库【一】https://blog.csdn.net/zyooooxie/article/details/109588072 &#xff0c; 继续分享…

查询每张表占用磁盘空间大小(达梦数据库)

查询每张表占用磁盘空间大小 环境介绍 环境介绍 在迁移准备工作中,为了更好评估迁移时间,可以统计大表数量与大表的实际大小,为迁移规划做准备 --查看用户下面每张表占用的磁盘空间SELECT T.OWNER,T.SEGMENT_NAME,T.SEGMENT_TYPE,T.TABLESPACE_NAME,T.BYTES,T.BYTES/1024 BYT…

OpenHarmony开源鸿蒙开发之旅

文章目录 一、op系统架构二、op系统构建1. op源代码目录2. op系统构建3. op开发环境搭建 三、op系统的子系统四、op系统芯片移植五、op系统启动流程六、op系统组件七、驱动框架 一、op系统架构 二、op系统构建 1. op源代码目录 2. op系统构建 3. op开发环境搭建 三、op系统…

4、安全开发-Python-蓝队项目流量攻击分析文件动态监控图片隐写技术

用途&#xff1a;个人学习笔记&#xff0c;有所借鉴&#xff0c;欢迎指正&#xff01; 总结&#xff1a; &#xff08;1&#xff09;使用python脚本Scapy库实现指定网卡的流量抓包分析 &#xff08;2&#xff09;使用python脚本Watchdog实现指定目录文件行为监控 &#xff08;…

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代码的编写。 比如下面这个页…

SpringBoot2-Jwt

1.官网 jwt.io/libraries 2.选jose4j pom <dependency><groupId>org.bitbucket.b_c</groupId><artifactId>jose4j</artifactId><version>0.9.4</version> </dependency> 3.创建jwt工具 public class JwtUtil {private stat…

力扣:78. 子集

回溯解法思路&#xff1a; 1.跟前面的组合题目有相同的点&#xff0c;主要区别在于&#xff1a;组合题目是遍历到符合条件的组合时加入li1集合中&#xff0c;子集题目是每递归一次就要把结果加入到li1集合中&#xff0c;并遍历但nums数组的最后。其他点和组合问题一样。 clas…

PyTorch的10个基本张量操作

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

记录关于 LLVM C/C++ 适用 libc++ 的一些注意事项

可以看看这个&#xff1a; https://releases.llvm.org/12.0.1/projects/libcxx/docs/UsingLibcxx.html 1、std::function<void()> 在 libc 之中不是线程安全的&#xff0c;在GCC/VC上面可以多线程上操作&#xff0c;在LLVM提供的LIBC标准库之中不行&#xff0c;要牢记&a…

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

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

UC++常用语句示例

Actor操作 移动 FVector CurrentLocation GetActorLocation(); // 在X轴上增加移动 CurrentLocation.X MoveSpeed * DeltaTime; // 应用新的位置 SetActorLocation(CurrentLocation); AddActorLocalOffset(FVector(MoveSpeed * DeltaTime, 0.0f, 0.0f)); // 获取当前相对位…

mysql清空表数据后如何让自增ID仍从1开始

有2种方法&#xff1a; 1、清空表时使用truncate命令&#xff0c;而不用delete命令 truncate test; 使用truncate命令的好处&#xff1a; 1&#xff09;、速度快 2&#xff09;、可以对自增ID进行重排&#xff0c;使自增ID仍从1开始计算 2、清空表数据后&#xff0c;使用alter…

Android 11 访问 Android/data/或者getExternalCacheDir() root方式

前言&#xff1a; 需求要求安装三方应用ExternalCacheDir()下载下来的apk文件。 getExternalCacheDir() : /storage/emulated/0/Android/data/com../cache/ 获取访问权限 如果手机安卓版本为Android10的时候,可以在AndroidManifest.xml中添加下列代码 android:requestLegacyExt…