SpringBoot灵活集成多数据源(定制版)

如来说世界,非世界,是名世界

如来说目录,非目录,是名目录

  • 前言
  • 前期准备
  • 代码实现
  • 演示
  • 扩展

前言

本篇博客基于SpringBoot整合MyBatis-plus,如果有不懂这个的,
可以查看我的这篇博客:快速CRUD的秘诀之SpringBoot整合MyBatis-Plus

MyBatis-Plus官方推荐的简单切换数据源,可以参考上期博客:SpringBoot快速集成多数据源(自动版)

那么问题来了?我上期博客已经实现过一次多数据源切换了,并且非常简单,为什么还要出一期定制版呢?

是这样的,在上一期博客中,通过@DS注解在不同的方法上,然后再通过调用不同的方法来实现调用不同的数据源:
在这里插入图片描述
那么,如果有8个数据源呢?是不是要写8个方法,8个判断呢?

那,如果再有8个业务需要切换数据源呢?想想头就大了
在这里插入图片描述

所以,到底有没有方法能够简化代码呢?反正切换大概都是一样的逻辑。
在这里插入图片描述

本博主灵光一现,这篇博客也就应运而生了!

当然,如果已经规定好了哪些业务用哪些数据源,不存在同一个业务要根据不同的用户来切换的烦恼,您就用官方推荐的方式吧,甭折腾了!

前期准备

跟上期同样,为了实现效果,先在本地的mysql库里面创建两个数据库:
在这里插入图片描述
然后在两个数据库里面,分别创建同样的users表,但是插入不同的数据,
mydb的数据:
在这里插入图片描述
mydb2的数据:
在这里插入图片描述

代码实现

1.在pom.xml文件中引入AOP所需的依赖aspectjweaver

<!-- 使用AOP来增强对象 -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.7</version>
</dependency>

2.在application.yml中进行配置:

server:port: 8080# 配置数据源
spring:datasource:master:# 数据库路径jdbc:mysql://localhost:3306/mydb 的缩写,并配置时区jdbc-url: jdbc:mysql:///mydb?serverTimezone=GMT%2B8username: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置slave:jdbc-url: jdbc:mysql:///mydb2?serverTimezone=GMT%2B8username: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver# 打印MyBatis SQL 日志
logging:level:com.guqueyue.dynamicdatasourcetest.dao: debug # 写接口的包名

这里需要注意的是数据源的路径名不能用url,要用jdbc-url!!!

3.编写DataSourceType类,用以设置数据源:

package com.guqueyue.dynamicdatasourcetest.config;import lombok.extern.slf4j.Slf4j;/*** @Author: guqueyue* @Description: 用以设置数据源* @Date: 2023/12/25**/
@Slf4j
public class DataSourceType {// 内部枚举类,用以选择特定的数据源public enum DataBaseType {master,slave}// 使用ThreadLocal保证线程安全private static final ThreadLocal<DataBaseType> TYPE = new ThreadLocal<>();// 往当前线程中设置数据源类型public static void setDataBaseType(DataBaseType dataBaseType) {if (dataBaseType == null) {throw new NullPointerException();}TYPE.set(dataBaseType);log.info("\033[31;0;42;30;1;2;3;4;41m" + "线程:[" + Thread.currentThread().getName() +"],取了[" + getDataBaseType() + "]=>这个数据源");}// 获取数据源类型public static DataBaseType getDataBaseType() {return TYPE.get() == null ? DataBaseType.master : TYPE.get();}// 清空数据源类型public static void clearDataBaseType() {TYPE.remove();}
}

4.扩展determineCurrentLookupKey()方法来实现数据源的切换:

package com.guqueyue.dynamicdatasourcetest.config;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/*** @Author: guqueyue* @Description: 通过扩展determineCurrentLookupKey()方法来实现数据源的切换* @Date: 2023/12/25**/
public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceType.getDataBaseType();}
}

5.重头戏,编写多数据源配置类DynamicDataSourceConfig:

package com.guqueyue.dynamicdatasourcetest.config;import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.incrementer.OracleKeyGenerator;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
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.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;/*** @Author: guqueyue* @Description: 多数据源配置类* @Date: 2023/12/25**/
@Configuration
@MapperScan(basePackages = "com.guqueyue.dynamicdatasourcetest.dao", sqlSessionFactoryRef = "SqlSessionFactory") // basePackages为接口地址
public class DynamicDataSourceConfig {// 将这个对象放入Spring容器中@Bean(name = "masterDataSource")// 表示这个数据源为默认数据源@Primary// 读取 application.yml 中的配置参数映射成为一个对象// prefix表示配置文件中参数的前缀@ConfigurationProperties(prefix = "spring.datasource.master")public DataSource getMasterDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "slaveDataSource")@ConfigurationProperties(prefix = "spring.datasource.slave")public DataSource getSlaveDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "dynamicDataSource")public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("slaveDataSource") DataSource slaveDataSource) {// 核心点: targetDataSource为 数据源和注入的Bean 之间的映射Map<Object, Object> targetDataSource = new HashMap<>();targetDataSource.put(DataSourceType.DataBaseType.master, masterDataSource);targetDataSource.put(DataSourceType.DataBaseType.slave, slaveDataSource);DynamicDataSource dataSource = new DynamicDataSource();dataSource.setTargetDataSources(targetDataSource);dataSource.setDefaultTargetDataSource(masterDataSource); // 设置默认数据源return dataSource;}@Bean(name = "SqlSessionFactory")@DependsOn("globalConfig") // 明确调用顺序,在调用本方法前先调用 globalConfig() 方法public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) throws Exception {//        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();bean.setDataSource(dynamicDataSource);// 设置xml文件路径
//        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml"));bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:com/guqueyue/dynamicdatasourcetest/dao/*.xml"));// 设置别名的扫描 - 实体类的包名引用bean.setTypeAliasesPackage("com.guqueyue.dynamicdatasourcetest.entity");bean.setGlobalConfig(globalConfig());return bean.getObject();}/*** @Description 解决Oracle数据库下,用 @KeySequence注解 实现主键序列自增失效 问题解决* @Param []* @return com.baomidou.mybatisplus.core.config.GlobalConfig**/@Beanpublic GlobalConfig globalConfig() {GlobalConfig globalConfig = new GlobalConfig();globalConfig.setDbConfig(new GlobalConfig.DbConfig().setKeyGenerator(new OracleKeyGenerator()));return globalConfig;}@Bean(name = "sqlSessionTemplate")@Primary // 首选public SqlSessionTemplate sqlSessionTemplate(@Qualifier("SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory);}/*** @Description 事务管理* @Param [dataSource]* @return org.springframework.jdbc.datasource.DataSourceTransactionManager**/@Bean(name = "dataSourceTransactionManager")@Primary // 首选public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("dynamicDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}

6.编写自定义注解

关于自定义注解的了解,可以参考我的这篇博客:框架的灵魂之注解基础篇

package com.guqueyue.dynamicdatasourcetest.annotation;import java.lang.annotation.*;/*** @Author: guqueyue* @Description: 自定义注解,用以切换数据源* @Date: 2023/12/25**/
@Target({ElementType.METHOD}) // 注解使用范围为:方法
@Retention(RetentionPolicy.RUNTIME) // 注解的生命周期为运行时
@Documented
public @interface MyDataSource {//    DataSourceType.DataBaseType value() default DataSourceType.DataBaseType.master; // 默认使用master库
}

7.进行自定义注解拦截,使用AOP来增强对象:
这里有一个核心逻辑,我们根据@MyDataSource 自定义注解拦截方法,然后根据方法所传的第一个参数值来判断使用哪个数据源。
这样我们就不用编写很多方法了。当然,如果没找到,就默认为主数据源。

package com.guqueyue.dynamicdatasourcetest.aop;import com.guqueyue.dynamicdatasourcetest.annotation.MyDataSource;
import com.guqueyue.dynamicdatasourcetest.config.DataSourceType;
import lombok.extern.slf4j.Slf4j;
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.springframework.stereotype.Component;/*** @Author: guqueyue* @Description: 自定义注解拦截,使用AOP来增强对象* @Date: 2023/12/25**/
@Slf4j
@Aspect
@Component
public class DynamicDataSourceAspect {// 拦截自定义注解, @annotation()里面是注解的路径,需要根据你自己的替换@Before("@annotation(com.guqueyue.dynamicdatasourcetest.annotation.MyDataSource)")public void changeDataSource(JoinPoint point) {//        // 获取增强方法
//        MethodSignature methodSignature = (MethodSignature) point.getSignature();
//        // 获取增强方法的反射对象
//        Method method = methodSignature.getMethod();
//        // 获取@MyDataSource注解
//        MyDataSource myDataSource = method.getAnnotation(MyDataSource.class);String dataSourceType = "master";// 获取方法的第一个参数Object[] args = point.getArgs();if (args != null && args.length > 0) {dataSourceType = args[0].toString();}// 选择数据源switch (dataSourceType) {case "slave":DataSourceType.setDataBaseType(DataSourceType.DataBaseType.slave);break;default: // 默认为主数据源DataSourceType.setDataBaseType(DataSourceType.DataBaseType.master);break;}}// 在方法执行完之后清除特定数据源的配置,使用默认数据源@After("@annotation(myDataSource)")public void restoreDataSource(JoinPoint point, MyDataSource myDataSource) {DataSourceType.clearDataBaseType();}
}

总体实现下来的项目结构为:
在这里插入图片描述

演示

1.控制层代码

package com.guqueyue.dynamicdatasourcetest.controller;import com.guqueyue.dynamicdatasourcetest.entity.User;
import com.guqueyue.dynamicdatasourcetest.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** @Author: guqueyue* @Description: 用户控制层* @Date: 2023/12/25**/
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate IUserService userService;/*** 查询用户列表* @return*/@RequestMapping("/list")public List<User> userList(String type) {return userService.selectUserList(type);}
}

2.service接口

package com.guqueyue.dynamicdatasourcetest.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.guqueyue.dynamicdatasourcetest.entity.User;import java.util.List;/*** @Author: guqueyue* @Description: 用户service接口* @Date: 2023/12/25**/
public interface IUserService extends IService<User> {List<User> selectUserList(String type);
}

3.service实现类

package com.guqueyue.dynamicdatasourcetest.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.guqueyue.dynamicdatasourcetest.annotation.MyDataSource;
import com.guqueyue.dynamicdatasourcetest.dao.UserMapper;
import com.guqueyue.dynamicdatasourcetest.entity.User;
import com.guqueyue.dynamicdatasourcetest.service.IUserService;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.List;/*** @Author: guqueyue* @Description: 用户实现类* @Date: 2023/12/25**/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {@Resourceprivate UserMapper userMapper;@Overridepublic List<User> selectUserList(String type) {// do something: 此处可根据实际情况进行业务选择,如根据当前登录的用户信息来选择不同的数据库// 此处为了方便演示,直接用前端传入的type来判断return userMapper.selectUserList(type);}
}

4.dao层

package com.guqueyue.dynamicdatasourcetest.dao;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.guqueyue.dynamicdatasourcetest.annotation.MyDataSource;
import com.guqueyue.dynamicdatasourcetest.entity.User;
import org.apache.ibatis.annotations.Select;import java.util.List;/*** @Author: guqueyue* @Description: 映射接口UserMapper* @Date: 2023/12/25**/
public interface UserMapper extends BaseMapper<User> {@MyDataSource@Select("SELECT id,password,username FROM users")List<User> selectUserList(String type);
}

5.启动项目,看效果

根据之前自定义注解拦截时编写的逻辑,我们会根据selectUserList()方法中的第一个参数type来决定取哪个数据源。

话不多说,项目,启动!
在这里插入图片描述

在控制台看到tomcat在你配置的端口号上启动了,说明项目启动成功了!

Tomcat started on port(s): 8080 (http) with context path ''

在浏览器输入:http://localhost:8080/user/list?type=master
可以看到控制台打印:
在这里插入图片描述
浏览器返回:
在这里插入图片描述
再在浏览器输入:http://localhost:8080/user/list?type=slave
可以看到控制台打印:
在这里插入图片描述
浏览器返回:
在这里插入图片描述
说明成功切换了不同的数据源!

扩展

本文在演示的时候,在dao层使用的是@Select注解来执行SQL语句,并没有使用xml文件。

如需使用xml文件执行SQL语句的话,

可以参照我的这篇博客:快速CRUD的秘诀之SpringBoot整合MyBatis-Plus 的扩展部分。

但不同的是,需要在多数据源配置类DynamicDataSourceConfigsqlSessionFactory()方法中进行配置,而不是applicaton.yml配置文件中:

 @Bean(name = "SqlSessionFactory")@DependsOn("globalConfig") // 明确调用顺序,在调用本方法前先调用 globalConfig() 方法public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) throws Exception {//        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();bean.setDataSource(dynamicDataSource);// 设置xml文件路径
//        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml"));bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:com/guqueyue/dynamicdatasourcetest/dao/*.xml"));// 设置别名的扫描 - 实体类的包名引用bean.setTypeAliasesPackage("com.guqueyue.dynamicdatasourcetest.entity");bean.setGlobalConfig(globalConfig());return bean.getObject();}

将这两行代码根据你的实际情况修改即可:

 // 设置xml文件路径
//        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml"));bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:com/guqueyue/dynamicdatasourcetest/dao/*.xml"));// 设置别名的扫描 - 实体类的包名引用bean.setTypeAliasesPackage("com.guqueyue.dynamicdatasourcetest.entity");

我们下期博客再见!

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

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

相关文章

信息化和数字化的本质区别是什么?

信息化和数字化是两个概念的区别 它们有什么区别和联系呢&#xff1f;信息化&#xff1a;“业务数据化”&#xff0c;先让业务流程能被数据记录下来。信息化“业务数据化”。数字化&#xff1a;“数据业务化”&#xff0c;用已累积的业务数据去反哺优化业务流程。数字化“数据…

C++:继承(这一篇就够了)

C&#xff1a;继承&#xff08;这一篇就够了&#xff09; 一、继承的概念及定义1.1 继承的概念1.2 继承定义1.2.1定义格式1.2.2 继承关系和访问限定符1.2.3 继承基类成员访问方式的变化 二、基类和派生类对象赋值转换三、继承中的作用域四、派生类的默认成员函数五、继承与静态…

可穿戴智能设备应用领域以及使用意义分别有哪些?

可穿戴智能设备有哪些&#xff1f; 可穿戴智能设备是指可以佩戴在身上&#xff0c;具有智能功能和交互能力的电子设备。以下是一些常见的可穿戴智能设备&#xff1a; 智能手表&#xff1a;智能手表结合了传统手表的功能和智能设备的特性&#xff0c;可以显示时间、接收通知、监…

Linux下一切皆文件

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 你是否听过Linux下一切皆文件&#xff1f; 在哪里我们体悟到了Linux下一切皆文件&#xff1f; 文件是什么&#xff1f; 在哪里体悟到的&#xff1f; 常见疑惑 怎么办到的Linux下一切皆文件&#xff1f; 我们抛出…

LED显示屏常用驱动芯片一览表

LED显示屏驱动芯片是专门用于驱动LED显示屏的核心芯片&#xff0c;它能够将输入的电信号转化为驱动能力&#xff0c;以控制LED灯的亮度和颜色。LED显示屏驱动芯片具有高可靠性、低功耗、长寿命等优点&#xff0c;是LED显示屏产业的核心零部件之一。 SM16306SJ LED显示屏驱动芯…

《MySQL系列-InnoDB引擎02》InnoDB存储引擎介绍

文章目录 第二章 InnoDB存储引擎1 InnoDB存储引擎概述2 InnoDB存储引擎的版本3 InnoDB体系架构3.1 后台线程3.2 内存 4 Checkpoint技术5 Master Thread 工作方式5.1 InnoDB 1.0.x版本之前的Master Thread5.2 InnoDB 1.2.x版本之前的Master Thread5.3 InnoDB 1.2.x版本的Master …

python写入csv文件总是多出一行空行(windows)

问题代码 import csv from os import pathfull_path path.abspath(__file__) path_dir path.dirname(full_path)data [[Name, Age, City],[John, 25, New York],[Alice, 30, Los Angeles],[Bob, 35, Chicago] ] # 代码使用都是正常的&#xff0c;但是总是多出一行空格 with…

Unity游戏资源更新(AB包)

目录 前言&#xff1a; 一、什么是AssetBundle 二、AssetBudle的基本使用 1.AssetBundle打包 2.BuildAssetBundle BuildAssetBundleOptions BuildTarget 示例 3.AssetBundle的加载 LoadFromFile LoadFromMemory LoadFromMemoryAsync UnityWebRequestAsssetBundle 前…

nginx+rsyslog+kafka+clickhouse+grafana 实现nginx 网关监控

需求 我想做一个类似腾讯云网关日志最终以仪表方式呈现&#xff0c;比如说qps、p99、p95的请求响应时间等等 流程图 数据流转就像标题 nginx ----> rsyslog ----> kafka —> clickhouse —> grafana 部署 kafka kafka 相关部署这里不做赘述&#xff0c;只要创…

跨境电商代采是什么?怎么做代采网站?

跨境电商独立站就是跨境电商自行搭建的销售网站&#xff0c;服务器、域名都是自主购买的&#xff0c;并由跨境电商独立运营与营销推广。 近些年来&#xff0c;各类第三方电商平台虽然流量大&#xff0c;但是随着进驻电商数量的增加&#xff0c;流量竞争也愈发激烈&#xff0c;…

雷达遮挡检测综述

1 概述 雷达&#xff08;毫米波、激光&#xff09;的遮挡是实际项目中比较常见的现象&#xff0c;优秀的算法应当能够及时、准确地检测出雷达是否被遮挡&#xff0c;以及遮挡的严重程度&#xff0c;然后将故障信息发送给诊断系统&#xff0c;并在仪表盘上显示&#xff0c;如…

win系统微软输入法踩坑之输入法

例如&#xff1a;字母间距变宽 或者打字总是繁体等等 字母变宽是因为快捷键误触切换成了全角字符。。 立马打开输入法设置界面进行相关设置&#xff08;你要解决的输入法问题都可以在这里得到解决&#xff09;&#xff1a;

LED恒流驱动芯片:700V高压线性恒流选型一览表

LED恒流驱动芯片是一种专门用于LED照明产品的电子元件&#xff0c;它能够实现LED的恒流驱动&#xff0c;从而保证LED灯具在工作过程中稳定的亮度和电流输出。其中&#xff0c;700V高压线性恒流是LED恒流驱动芯片的一个重要特性&#xff0c;下面就让我们来详细了解一下。 SM2253…

Apple Unity Plugins 接入GameCenter 崩溃解决方案

目录 问题问题原因解决方案可直接使用的UnityPlugins 问题 调用 GKLocalPlayer.Local.FetchItems() 程序崩溃&#xff0c;报错&#xff1a;Thread 1: EXC_BAD_ACCESS (code257, address0x8000000000000002) 启动崩溃&#xff0c;报错&#xff1a;Library not loaded: rpath/Ap…

新年新计划,羊大师教你如何实现个人目标与成长

新年新计划&#xff0c;羊大师教你如何实现个人目标与成长 新的一年已经到来&#xff0c;这是一个神奇的时刻&#xff0c;一个全新的开始&#xff0c;也是实现自己目标与成长的最佳时机。在这个瞬息万变的世界中&#xff0c;我们总是被忙碌的生活所迷失&#xff0c;然而我们需…

2023年度回顾:怿星科技的转型与创新

岁月不居&#xff0c;时节如流。随着2023年的落幕&#xff0c;怿星科技在这一年中不仅实现了自身的转型&#xff0c;还在技术创新、产品研发、行业合作和人才培养等方面取得了显著的成就。这一年&#xff0c;怿星科技正式完成了从服务型公司向产品型公司的战略转变&#xff0c;…

为什么选择 IBM LSF?

IBM Spectrum Computing 推出了全面的软件定义基础架构解 决方案产品组合&#xff0c;从而优化资源利用率以缩短成果实现时间并 降低成本&#xff0c;以高效地交付 IT 服务。IBM Spectrum Computing 解决方案非常适合技术和 HPC 应用&#xff0c;旨在简化和加速高性能 仿真和分…

Windows本地如何部署Apache服务器搭配内网穿透实现无公网IP远程访问?

文章目录 前言1.Apache服务安装配置1.1 进入官网下载安装包1.2 Apache服务配置 2.安装cpolar内网穿透2.1 注册cpolar账号2.2 下载cpolar客户端 3. 获取远程桌面公网地址3.1 登录cpolar web ui管理界面3.2 创建公网地址 4. 固定公网地址 前言 Apache作为全球使用较高的Web服务器…

深度学习|3.6 激活函数 3.7 为什么需要非线性激活函数

激活函数 主要有sigmoid函数、tanh函数、relu函数和leaky relu函数 tanh函数相比sigmoid函数是具有优势的&#xff0c;因为tanh函数使得输出值的平均值为0&#xff0c;而sigmoid函数使得输出值的平均值为1/2&#xff0c;对下一层来说tanh输出的0更好进行处理。 激活函数tanh…

DIA数皆智能客户体验管理CEM获伊利“健康+AI”生态创新大奖

DIA数皆智能客户体验管理CEM获伊利“健康AI”生态创新大奖 数皆智能再获殊荣&#xff01; 北京&#xff0c;2023年12月26日 — 在全球瞩目的伊利集团“健康AI”生态创新大赛中&#xff0c;上海数皆智能技术有限公司大放异彩&#xff0c;其创新领先的“智能化客户体验管理CEM&a…