【高阶数据结构】哈希的应用 {位图;std::bitset;位图的应用;布隆过滤器;布隆过滤器的应用}

news2024/12/29 10:04:47

一、位图

1.1 位图概念

  1. 面试题
    给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。【腾讯】

  2. 遍历查找:内存中无法存放40亿个整数(约占内存15-16G);时间复杂度O(N);

  3. 先排序O(NlogN),再利用二分查找O(logN):数据太大,只能存放在磁盘文件中,数据读取速度慢。

  4. 位图
    数据是否在给定的集合中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。利用位图解决该问题,无符号整数的取值范围是0~2^32,一个位代表一个整数,只需要2^32bit = 512MB内存空间即可。
    在这里插入图片描述

  5. 位图概念
    所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的。数据的键值通过直接定址法与位图中的位建立联系。

提示:位图在STL中的实现为bitset,在头文件<bitse>中声明


1.2 位图的实现

关于位运算的相关知识请阅读:

【C语言进阶】位运算 {位运算符;位运算符的优先级;位运算的应用 :关闭位,判断位,打开位,转置位;位域}

#include <vector>                
#include <math.h>     
using namespace std;    
                
namespace zty{         
  template <size_t N>    
  class bitset{        
    vector<char> _bt;    
    size_t _count;    
           
  public:     
    bitset()                    
      :_bt(ceil((double)N/8)), //ceil向上取整   
      _count(0)    
    {}    
    //打开位                     
    void set(size_t x){    
      if(x>N) return;    
      size_t i = x/8; //计算在第几个char类型    
      size_t j = x%8; //计算在char类型的第几位   
      _bt[i] |= (1<<j);    
      ++_count;    
    }  
    //关闭位
    void reset(size_t x)
    {
      if(x>N) return;
      size_t i = x/8;
      size_t j = x%8;
      _bt[i] &= ~(1<<j);
      --_count;
    }
    //判断位        
    bool test(size_t x)
    {
      if(x>N) return false;
      size_t i = x/8;
      size_t j = x%8;
      return _bt[i] & (1<<j);
    }
    //返回bitset中被置为1的比特位数
    size_t count(){
      return _count;
    }
	//返回bitset中的比特位总数
    size_t size(){
      return N;
    }
  };
}

1.3 位图应用

  1. 快速查找某个数据是否在一个集合中
  2. 排序 + 去重
  3. 求两个集合的交集、并集等
  4. 操作系统中磁盘块标记

相关面试题

  1. 给定100亿个整数,设计算法找到只出现一次的整数?

思路:

  • 每个整数有3种状态:出现0次;出现1次;出现2次及以上
  • 需要两个位图解决
  template <size_t N>
  class twobitset1{
    bitset<N> bs1;
    bitset<N> bs2;
  public:
    void set(size_t x){
      if(!bs1.test(x) && !bs2.test(x)) //出现0次(00)-->出现1次(01)
      {
        bs2.set(x);
      }
      else if(!bs1.test(x) && bs2.test(x)) //出现1次(01)-->出现2次(10)
      {
        bs1.set(x);
        bs2.reset(x);
      }
    }
    void print_once_num(){
      for(size_t i = 0; i<N; ++i)
      {
        //找到只出现一次的整数(01)
        if(!bs1.test(i) && bs2.test(i))
        {
          cout << i << " ";
        }
      }
      cout << endl;
    }
  };

void test1(){
  int arr[] = {6,99,1,1,2,4,3,5,6,7,1,3,2,4,7,9,8,5,4,3,21,8,9,4,2,3,1,4,3,57};
  zty::twobitset1<100> tbs;
  for(int e : arr){
    tbs.set(e);
  }
  tbs.print_once_num();
}
  1. 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?

    思路:每个文件对应一个位图,两位图的对应位都为1就是交集。

      template <size_t N>
        class twobitset2{
          bitset<N> bs1; //文件1对应的位图
          bitset<N> bs2; //文件2对应的位图
        public:
          void setbs1(size_t x){
            bs1.set(x);
          } 
          void setbs2(size_t x){
            bs2.set(x);
          } 
          void print_intersection_set(){
            for(size_t i = 0; i<N; ++i)
            {
              //找出两个文件中数据的交集(11)
              if(bs1.test(i) && bs2.test(i))
              {
                cout << i << " ";
              }
            }
            cout << endl;
          }
        };
    
    void test2(){
      int file1[] = {6,99,1,1,2,4,3,5,6,7,1,3,2,4,7,9,8,5,4,3,21,8,9,4,2,3,1,4,3,57};
      int file2[] = {5,3,1,5,12,23,45,6,78,9,12,13,15,57,3,4,9};
      zty::twobitset2<100> tbs;
      for(int e : file1){
        tbs.setbs1(e);
      }
      for(int e : file2){
        tbs.setbs2(e);
      }
      tbs.print_intersection_set();
    }
    
  2. 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数

思路:

  • 每个整数有4种状态:出现0次;出现1次;出现2次;出现3次及以上
  • 需要两个位图解决
  template <size_t N>
  class twobitset3{
    bitset<N> bs1;
    bitset<N> bs2;
  public:
    void set(size_t x){
      if(!bs1.test(x) && !bs2.test(x)) //出现0次(00)-->出现1次(01)
      {
        bs2.set(x);
      }
      else if(!bs1.test(x) && bs2.test(x)) //出现1次(01)-->出现2次(10)
      {
        bs1.set(x);
        bs2.reset(x);
      }
      else if(bs1.test(x) && !bs2.test(x)) //出现2次(10)-->出现3次(11)
      {
        bs2.set(x);
      }
    }
    void print_atmost_twice(){
      //找到出现次数不超过2次的所有整数
      for(size_t i = 0; i<N; ++i)
      {
        if(!bs1.test(i) && bs2.test(i)) //出现1次(01)
        {
          cout << i << " ";
        }
        else if(bs1.test(i) && !bs2.test(i)) //出现2次(10)
        {
          cout << i << " ";
        }
      }
      cout << endl;
    }
  };

void test3(){
  int arr[] = {1,1,1,2,2,2,3,4,4,4,4,4,5,5,6};
  zty::twobitset3<100> tbs;
  for(int e : arr){
    tbs.set(e);
  }
  tbs.print_atmost_twice();
}

二、布隆过滤器

2.1 布隆过滤器概念

  • 位图一般只能解决整形数据在或不在的问题,如果数据是字符串或者其他类型,可以先将其转换为无符号整型再插入位图。但这样的处理方式存在哈希冲突的概率比较大。

  • 哈希表需要将数据全部加载到内存中还要开辟额外的指针(链表指针)和数组空间(负载因子),面对海量数据会占用大量的内存,甚至可能出现内存空间不够用的情况。

  • 于是诞生了新的容器——布隆过滤器。布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的 一种紧凑型的、比较巧妙的概率型数据结构,特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中的多个位上,以此来降低哈希冲突的概率。此种方式不仅可以提升查询效率,也可以节省大量的内存空间。

  • 布隆过滤器虽然可以降低哈希冲突的概率但不可完全避免。因此布隆过滤器可能发生误判:**不存在一定是准确的,但存在则可能发生误判。**误判率可以通过增加哈希函数(映射位数)来进一步降低。理论而言,一个值映射的位越多,误判率越低,但同时空间消耗也就越多

提示:STL没有实现布隆过滤器,如有需要请自行实现。


2.2 布隆过滤器的结构

布隆过滤器的结构实际就是一个位图:

在这里插入图片描述

2.2.1 插入

如果我们要映射一个值到布隆过滤器中,我们需要使用多个不同的哈希函数生成**多个哈希值,**并对每个生成的哈希值指向的 bit 位置 1,例如针对值 “baidu” 和三个不同的哈希函数分别生成了哈希值 1、4、7,则上图转变为:

在这里插入图片描述

2.2.2 查找

  • 布隆过滤器的思想是将一个元素用多个哈希函数映射到一个位图中,因此被映射到的位置的比特位一定为1。所以可以按照以下方式进行查找:分别计算每个哈希值对应的比特位置存储的是否为零,只要有一个为零,代表该元素一定不在哈希表中,否则可能在哈希表中。

  • 比如:在布隆过滤器中查找:“tencent”

    在这里插入图片描述

    假设3个哈希函数计算的哈希值为:3、4、8,虽然"baidu"和"tencent"两者通过Hash2计算的哈希值(4)相同,造成哈希冲突。但Hash1和Hash3的计算结果不同,只要三个哈希值中有一个位为0就能确定该字符串不存在。

  • 再比如:在布隆过滤器中查找:“alibaba”

在这里插入图片描述

假设3个哈希函数计算的哈希值为:1、4、7,刚好和"baidu"的比特位全部重叠。此时布隆过滤器返回该元素存在,但实际该元素是不存在的,发生误判。

  • 综上所述:布隆过滤器如果说某个元素不存在时,该元素一定不存在,如果该元素存在时,该元素可能存在,因为有些哈希函数存在一定的误判。

2.2.3 删除

布隆过滤器不能直接支持删除工作,原因有二:

  • 在删除一个元素时,如果直接将该元素所对应的二进制比特位置0,而该元素恰好与其他元素有重叠的位,就会导致这些重叠元素也被删除。

  • 不能确定待删除元素本身是存在于布隆过滤器的,可能会导致误删。


2.3 如何选择哈希函数个数和布隆过滤器长度

很显然,过小的布隆过滤器很快所有的 bit 位均为 1,那么查询任何值都会返回“可能存在”,起不到过滤的目的了。布隆过滤器的长度会直接影响误报率,布隆过滤器越长其误报率越小。

另外,哈希函数的个数也需要权衡,个数越多则布隆过滤器 bit 位置位 1 的速度越快,且布隆过滤器的效率越低;但是如果太少的话,那我们的误报率会变高。

在这里插入图片描述

如何选择适合业务的 k 和 m 值呢,这里直接贴一个公式:

在这里插入图片描述

例如:当k为3时,m≈4.2n,我们向上取整为5。即布隆过滤器的长度是插入元素个数的5倍。


2.4 布隆过滤器的实现

  //三种字符串哈希算法
  struct BKDRHash
  {
    size_t operator()(const string& s)
    {
      // BKDR
      size_t value = 0;
      for (auto ch : s)
      {
        value += ch;
        value *= 31;
      }
      return value;
    }
  };

  struct APHash
  {
    size_t operator()(const string& s)
    {
      size_t hash = 0;
      for (size_t i = 0; i < s.size(); i++)
      {
        if ((i & 1) == 0)
        {
          hash ^= ((hash << 7) ^ s[i] ^ (hash >> 3));
        }
        else
        {
          hash ^= (~((hash << 11) ^ s[i] ^ (hash >> 5)));
        }
      }
      return hash;
    }
  };

  struct DJBHash
  {
    size_t operator()(const string& s)
    {
      size_t hash = 5381;
      for (auto ch : s)
      {
        hash += (hash << 5) + ch;
      }
      return hash;
    }
  };

	//布隆过滤器
	//N是要插入的元素个数
	//布隆过滤器默认处理字符串
    template <size_t N, class K = string,
      class Hash1 = BKDRHash,
      class Hash2 = APHash,
      class Hash3 = DJBHash>
    class BloomFilter{
      std::bitset<N*5> _bs; //当哈希函数的个数为3时,布隆过滤器的长度是插入元素个数的5倍

    public:
      void set(const K& key){
        //将三个哈希函数计算得到映射位置置1
        size_t hashi1 = Hash1()(key) % _bs.size(); //_bs.size()-->N*5
        _bs.set(hashi1);
        size_t hashi2 = Hash2()(key) % _bs.size();
        _bs.set(hashi2);
        size_t hashi3 = Hash3()(key) % _bs.size();
        _bs.set(hashi3);
      }

      bool test(const K& key){
        //只要三个哈希函数计算得到映射位置中有一个位为0就返回false
        size_t hashi1 = Hash1()(key) % _bs.size();
        if(!_bs.test(hashi1)) return false; //准确的
        size_t hashi2 = Hash2()(key) % _bs.size();
        if(!_bs.test(hashi2)) return false; //准确的
        size_t hashi3 = Hash3()(key) % _bs.size();
        if(!_bs.test(hashi3)) return false; //准确的
        return true; //可能存在误判
      }
    };

测试代码:

//简单测试
void TestBloomFilter1()
{
  zty::BloomFilter<11> bf;
	string arr1[] = { "苹果", "西瓜", "阿里", "美团", "苹果", "字节", "西瓜", "苹果", "香蕉", "苹果", "腾讯" };

	for (auto& str : arr1)
	{
		bf.set(str);
	}

	for (auto& str : arr1)
	{
		cout << bf.test(str) << endl;
	}
	cout << endl << endl;

	string arr2[] = { "苹果111", "西瓜", "阿里2222", "美团", "苹果dadcaddxadx", "字节", "西瓜sSSSX", "苹果", "香蕉", "苹果$", "腾讯" };

	for (auto& str : arr2)
	{
		cout <<str<<":"<<bf.test(str) << endl;
	}
}

//误判率测试
void TestBloomFilter2()
{
	srand(time(0));
	const size_t N = 100000;
  zty::BloomFilter<N> bf;
  cout << "sizeof BloomFilter: " << sizeof(bf) << endl; 
	std::vector<std::string> v1;
	std::string url = "https://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html";

	for (size_t i = 0; i < N; ++i)
	{
		v1.push_back(url + std::to_string(1234 + i));
	}

	for (auto& str : v1)
	{
		bf.set(str);
	}

	//测试相似字符串误判率:
	std::vector<std::string> v2;
	for (size_t i = 0; i < N; ++i)
	{
		std::string url = "http://www.cnblogs.com/-clq/archive/2021/05/31/2528153.html";
		url += std::to_string(rand() + i);
		v2.push_back(url);
	}

	size_t n2 = 0;
	for (auto& str : v2)
	{
		if (bf.test(str))
		{
			++n2;
		}
	}
	cout << "相似字符串误判率:" << (double)n2 / (double)N << endl;

    //测试不相似字符串误判率:
	std::vector<std::string> v3;
	for (size_t i = 0; i < N; ++i)
	{
		string url = "zhihu.com";
		url += std::to_string(rand()+i);
		v3.push_back(url);
	}

	size_t n3 = 0;
	for (auto& str : v3)
	{
		if (bf.test(str))
		{
			++n3;
		}
	}
	cout << "不相似字符串误判率:" << (double)n3 / (double)N << endl;
}

2.5 布隆过滤器的应用

提高查找效率:利用布隆过滤器减少磁盘 IO 或者网络请求,因为一旦一个值必定不存在的话,我们可以不用进行后续昂贵的查询请求。

在这里插入图片描述

海量数据处理:

给两个文件,分别有100亿个query(字符串),我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法

  • 近似算法:将其中一个文件中的query插入到布隆过滤器中,再在布隆过滤器中遍历查找另一个文件的query。如果找到就是交集。近似算法的问题有:1.可能存在误判 2.没有进行去重

  • 精确算法:哈希切分

    在这里插入图片描述

哈希切分:

给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址?如何找到top K的IP?

在这里插入图片描述

拓展:一致性哈希


2.6 布隆过滤器的优缺点

  • 优点

    • 插入和查询元素的时间复杂度为:O(K), (K为哈希函数的个数,一般比较小),与数据量大小无关

    • 哈希函数相互之间没有关系,方便硬件并行运算

    • 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势

    • 在能够承受一定的误判时,布隆过滤器相比其他数据结构有很大的空间优势

    • 数据量很大时,布隆过滤器可以表示全集,其他数据结构不能

    • 使用同一组散列函数的布隆过滤器可以进行交、并、差运算

  • 缺点

    • 有误判率,即存在假阳性(False Position),即不能准确判断元素在集合中(补救方法:再建立一个白名单,存储可能会误判的数据)
    • 不能获取元素本身
    • 一般情况下不能从布隆过滤器中删除元素

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

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

相关文章

项目经理工具箱

新项目经理误区 要解决的关键点 事&#xff1a;范围&#xff0c;进度&#xff0c;成本&#xff0c;质量 人&#xff1a;项目干系人&#xff0c;团队&#xff0c;外包成员&#xff1b; 干系人管理计划&#xff0c;沟通管理计划 技术和管理区别和联系 非暴力沟通 结构思考力 重…

正点原子lwIP学习笔记——NTP实时时间实验

1. NTP简介 NTP&#xff08;Network Time Protocol&#xff09;网络时间协议基于UDP&#xff0c;用于网络时间同步的协议&#xff0c;使网 络中的计算机时钟同步到UTC&#xff0c;再配合各个时区的偏移调整就能实现精准同步对时功能。 NTP 服务器&#xff08;Network Time Pr…

ERROR in docs.42140ac.js from UglifyJs webpack打包报错

ERROR in docs.42140ac.js from UglifyJs 原因是UglifyJs 针对js压缩 不支持es6语法&#xff08;或者引入的第三方插件存在es6语法&#xff09; ERROR in docs.42140ac.js from UglifyJs 使用的 uglifyjs-webpack-plugin 解决方法 降低uglifyjs-webpack-plugin的版本 “ugl…

系统化思考,从初级到高级书单推荐

用思考工具进行系统思考&#xff0c;解决复杂问题&#xff0c;成为某个领域的高手&#xff0c;下面这几本书就是补充你脑海的系统思考的工具&#xff0c;一定要保存。 《简单的逻辑学》 作者&#xff1a;麦克伦尼 一切的系统源自于逻辑&#xff0c;如果你没有逻辑分析的能力&…

[谷粒商城笔记]07、Linux环境-虚拟机网络设置

1.本机cmd,输入命令ipconfig,查看本地ip 192.168.56.1是虚拟机的ip 2.自定义虚拟机ip 修改这个文件下的 这里&#xff0c;把ip换成 192.168.56.‘10’ 引号内数字自定义 3.在本机和虚拟机命令行&#xff0c;互相ping IP 查看是否设置成功

静态NAT,动态NAT,NAPT(实验配置+原理讲解)

目录 静态NAT,动态NAT&#xff0c;NAPT 实验一&#xff1a;静态NAT地址转换 实验二&#xff1a;动态NAT配置 实验三&#xff1a;NAPT配置 静态NAT,动态NAT&#xff0c;NAPT 静态地址转换&#xff1a;只能实现一个私网与一个公网的一对一映射 动态地址转换&#xff1a;创建…

Python 编程基础 | 第一章-预备知识 | 1.5、开发工具

一、开发工具 - VSCode VSCode是一个相当优秀的IDE&#xff0c;具备开源、跨平台、模块化、插件丰富、轻量化、启动时间快、颜值高的特质。 1、下载VSCode VSCode下载地址&#xff1a;https://code.visualstudio.com/ 2、安装VSCode 载软件包&#xff0c;一步步安装即可&#x…

CSS笔记——基本语法及相关知识

CSS层叠样式表是用于定义 HTML 或 XML 文档的样式和布局的语言。它可以让开发者更加灵活地控制页面元素的样式和排版&#xff0c;从而提高页面的可读性和用户体验 一、css样式书写顺序和规范 CSS样式的书写顺序和规范是为了让代码更易读、易维护和易扩展。下面是一些常见的规…

嵌入式Linux应用开发-Makefile 的使用

嵌入式Linux应用开发-Makefile 的使用 第三章 Makefile 的使用3.1 配套视频内容大纲3.1.1 Makefile 规则与示例3.1.2 通用 Makefile 的使用3.1.3 通用 Makefile 的解析 3.2 Makefile 规则3.3 Makefile 文件里的赋值方法3.4.1 字符串替换和分析函数3.4.2 文件名函数3.4.3 其他函…

NeRF中的位置编码

朴素NeRF中直接采用频率变换来做位置编码&#xff0c;为的是避免空间相邻采样点在MLP表示中的过平滑问题。比如位置(237, 332, 198)和位置(237,332,199)这两个点作为MLP的输入&#xff0c;MLP可能对个位不够敏感&#xff0c;导致输出过平滑的问题。例如&#xff1a; 由于缺乏位…

华为云云耀云服务器L实例评测 | 实例使用教学之软件安装:华为云云耀云服务器环境下安装 Docker

华为云云耀云服务器L实例评测 &#xff5c; 实例使用教学之软件安装&#xff1a;华为云云耀云服务器环境下安装 Docker 介绍华为云云耀云服务器 华为云云耀云服务器 &#xff08;目前已经全新升级为 华为云云耀云服务器L实例&#xff09; 华为云云耀云服务器是什么华为云云耀云…

特种设备安全监测终端,降低安全隐患风险!

特种设备运行关系到人民生命财产安全&#xff0c;关系到经济健康发展&#xff0c;关系到社会的稳定。有关特种设备的事故基本都发生在使用过程中&#xff0c;因此&#xff0c;使用过程的安全管理是特种设备的管理重点。针对国内特种设备本身存在事故隐患及安装、维修、操作、指…

基于微信小程序的快递配送管理平台系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

亚马逊投资Anthropic; OpenAI将推出新版ChatGPT

&#x1f989; AI新闻 &#x1f680; 亚马逊投资Anthropic获得可靠AI基础模型开发合作 摘要&#xff1a;亚马逊投资Anthropic至多40亿美元&#xff0c;将共同开发可靠高性能的基础模型&#xff0c;并能提前使用Anthropic技术。Anthropic将主要依赖亚马逊的云服务来训练未来的…

cJSON.c 在mfc中编译失败报 lnk2005错误

问题一、在MFC工程中导入cJson.c 编译时报以下错误&#xff1a; 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 C1853 “x64\Release\xxx.pch”预编译头文件来自编译器的早期版本&#xff0c;或者预编译头为 C 而在 C 中使用它(或相反) xxx …

机器学习与数据挖掘第三、四周

为什么第二周没有呢……因为刚换老师&#xff0c;自学要适应一段时间。 本课程作者之后的学习目标是&#xff1a;实操代码&#xff0c;至少要将作者参加数学建模中用到的数据处理方法都做一遍。 首先&#xff0c;作者复习一下李宏毅老师的两节课程。 机器学习概述 机器学习就…

前言技术 VScode + 其他插件-1

一、VScode 提升编程效率&#xff0c;免费 IDE&#xff08;Integrated Development Environment&#xff0c;集成开发环境&#xff09;是含代码编辑器、关键词高亮、智能感应、智能纠错、格式美化、版本管理等功能于一身的 "高级代码编辑器" 每个 IT 工程师都要有自…

【专升本】1. 英语考试介绍

一、考试方式 基础题&#xff1a;80% 难题&#xff1a;20% 二、试卷结构 1. 语音 级别&#xff1a;不重要原因&#xff1a;1分/题 2. 语法与词 级别&#xff1a;基础&#xff0c;一般 原因&#xff1a;1分/题 3. 汇完形填空 级别&#xff1a;比较重要原因&#xff1a;…

PyTorch 深度学习之逻辑斯蒂回归Logistic Regression(五)

Revision-Linear Regression Classfication The MNIST dataset train: 训练集还是测试集 The CIFAR-10 dataset 1. Regression VS Classfication 输出概率 1.1 How to map [0,1] 导数: 正态分布 1.2 Sigmoid functions 2. Logistic Regression model loss function for Bin…

Spring事务this自调用的理解误区?真的会让事务失效吗?

文章目录 前言this调用是什么this调用事务失效案例this调用事务仍然生效案例&#xff1f;总结 如何解决this调用事务失效 前言 我们经常谈到Spring事务失效会有多种场景导致&#xff1a;可参考我另外一篇文章 一文清晰讲解Transactional 注解失效场景 Transactional 应用在非…