【unity之IMGUI实践】单例模式管理数据存储【二】

在这里插入图片描述


👨‍💻个人主页:@元宇宙-秩沅

👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍💻 本文由 秩沅 原创

👨‍💻 收录于专栏unityUI专题篇
在这里插入图片描述


单例模式管理面板对象


文章目录

    • 单例模式管理面板对象
    • 🎶前言
    • 🎶(==A==)常用关键API
    • 🎶(==B==)需求分析
    • 🎶(==C==)逻辑封装——游戏音乐数据存储
      • 😶‍🌫️:步骤实现
        • 实现音乐数据的同步更新——最终代码
    • 🎶(==D==)逻辑封装——游戏排行榜数据存储
      • 😶‍🌫️:**步骤实现**
        • 总UML图
    • 👌结论:


🎶前言


🅰️


🎶(A常用关键API


在这里插入图片描述
在这里插入图片描述


🎶(B需求分析


在这里插入图片描述


🎶(C逻辑封装——游戏音乐数据存储


在这里插入图片描述
在这里插入图片描述


😶‍🌫️:步骤实现

1.首先将音乐数据封装在类中,不采用单例模式
2. 而后封装一个游戏数据类为单例模式:功能:利用Playerfabs进行数据存储音乐数据
3.读取存盘中的数据更新游戏数据


1.首先将音乐数据封装在类中,不采用单例模式

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________脚本名:   音乐相关数据存储类      
//___________功能:    记录音乐相关的数据 
//___________创建者:秩沅_______________
//_____________________________________
//-------------------------------------
public class MusicData 
{
    
    //记录音乐,音效的开关状态和拖动条
    public bool  musicSwitch;
    public bool  soundSwitch;
    public float musicRoll;
    public float soundRoll;
    public bool isFirst;
}

2. 而后封装一个游戏数据类为单例模式:功能:利用Playerfabs进行数据存储音乐数据

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________脚本名:   游戏数据类   
//___________功能:    记录游戏的数据并用PlayerFabs存储
//___________创建者:秩沅_______________
//_____________________________________
//-------------------------------------

public class GameData         
{
    static private GameData dataContorl = new GameData ();
    static public  GameData DataContorl => dataContorl ;
    public MusicData musicData ;

    private GameData()
    {
        musicData = new MusicData();
        musicData = PlayerfabsClass.Chats.GetDataMess(typeof(MusicData), "Music") as MusicData ;
        if ( !musicData.isFirst ) //如果是第一次进入游戏
        {
            musicData.musicSwitch = true;
            musicData.soundSwitch = true;
            musicData.musicRoll = 0.5f;
            musicData.soundRoll = 0.5f;
            PlayerfabsClass.Chats.SaveDataMess(musicData, "Music");   //设置为自定义的默认值后进行存储             
        }
    }
    
}

3.读取存盘中的数据更新游戏数据

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________项目:       ______________
//___________功能:  设置面板功能
//___________创建者:秩沅_______________
//_____________________________________
//-------------------------------------
public class SetPlane : BeginFather<SetPlane>
{
  //将功能控件拖拽对应的成员变量中
    public Button closeButt;
    public Slider sliderMusic;
    public Slider sliderSound;
    public ToggleM toggleMusic;
    public ToggleM toggleSound;

    private float toggle1;
    private float toggle2;

    private void Start()
    {
        
        //按钮中事件的添加
        closeButt.triggerEvent += () => {
            this.gameObject.SetActive(false);
            BeginPlane.SingleInstance.Show();
        };
        //滑条中事件的添加
   
        sliderMusic.triggerEvent += (value) =>
        {
            
        };
        sliderSound.triggerEvent += (value) =>
        {

        };
        //多选框中事件的添加

        toggleMusic.triggerEvent += (value) =>
        {

        };
        toggleSound .triggerEvent += (value) =>
        {

        };
        this.Hidden();
    }

    private void MusicDataUpdate()
    {
        MusicData data = GameData.DataContorl.musicData;
        sliderMusic.NowValue = data.musicRoll;
        sliderSound.NowValue = data.soundRoll;
        toggleMusic.IsSwitch = data.musicSwitch;
        toggleSound.IsSwitch = data.soundSwitch;
    }

    public override void Show()
    {
        base.Show();  //保留父类的封装逻辑
        MusicDataUpdate();
    }
}


实现音乐数据的同步更新——最终代码


目的: 将游戏游戏数据保存至硬盘,下次开启游戏实现数据同步

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________脚本名:   游戏数据类   
//___________功能:    记录游戏的数据并用PlayerFabs存储
//___________创建者:秩沅_______________
//_____________________________________
//-------------------------------------

public class GameData         
{
    static private GameData dataContorl = new GameData ();
    static public  GameData DataContorl => dataContorl ;
    public MusicData musicData ;

    private GameData()
    {
       
        musicData = PlayerPrefsDataMgr.Instance.LoadData(typeof(MusicData), "Music") as MusicData ;

        if ( !musicData.isFirst ) //如果是第一次进入游戏(表示注册表中第一次存该类型数据时)
        {
            musicData.isFirst = true;
            musicData.musicSwitch = true;
            musicData.soundSwitch = true;
            musicData.musicRoll = 1f;
            musicData.soundRoll = 1f;
            PlayerPrefsDataMgr.Instance.SaveData(musicData, "Music");                
        }
    }
    
    //音乐开关数据的更新存储

    public void ChangeMusicS( bool value)
    {
        musicData.musicSwitch = value;
        PlayerPrefsDataMgr.Instance.SaveData(musicData,"Music");
    }

    //音效开关数据的更新存储

    public void ChangeSoundS(bool value)
    {
        musicData.soundSwitch  = value;
        PlayerPrefsDataMgr.Instance.SaveData(musicData, "Music");
    }

    //音乐滑条数据的更新存储

    public void ChangeMusicR(float value)
    {
        musicData.musicRoll  = value;
        PlayerPrefsDataMgr.Instance.SaveData(musicData, "Music");
    }

    //音效滑条数据的更新存储

    public void ChangeSoundR(float value)
    {
        musicData.soundRoll  = value;
        PlayerPrefsDataMgr.Instance.SaveData(musicData, "Music");
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________项目:       ______________
//___________功能:  设置面板功能
//___________创建者:秩沅_______________
//_____________________________________
//-------------------------------------
public class SetPlane : BeginFather<SetPlane>
{
  //将功能控件拖拽对应的成员变量中
    public Button closeButt;
    public Slider sliderMusic;
    public Slider sliderSound;
    public ToggleM toggleMusic;
    public ToggleM toggleSound;

    private float toggle1;
    private float toggle2;
    private MusicData musicData;

    private void Start()
    {
        
        //按钮中事件的添加
        closeButt.triggerEvent += () => {
            Hidden();
            BeginPlane.SingleInstance.Show();
        };
        //多选框中事件的添加

        toggleMusic.triggerEvent += (value) => GameData.DataContorl.ChangeMusicS(value);

        toggleSound.triggerEvent += (value) => GameData.DataContorl.ChangeSoundS(value);
        //滑条中事件的添加

        sliderMusic.triggerEvent += (value) => GameData.DataContorl.ChangeMusicR(value);

        sliderSound.triggerEvent += (value) => GameData.DataContorl.ChangeSoundR(value);
      
        Hidden();
    }


    private void MusicDataUpdate() //将已存盘的数据读取后更新
    {
        MusicData data = GameData.DataContorl.musicData;

        toggleMusic.IsSwitch = data.musicSwitch;
        toggleSound.IsSwitch = data.soundSwitch;
        sliderMusic.NowValue = data.musicRoll;
        sliderSound.NowValue = data.soundRoll;
    
    }

    
    public override void Show()
    {
        base.Show();        //保留父类的封装逻辑
        MusicDataUpdate();  //在展示时更新
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
//-------------------------------------
//—————————————————————————————————————
//___________项目:       ______________
//___________功能: 开始面板类
//___________创建者:秩沅_______________
//_____________________________________
//-------------------------------------
public class BeginPlane : BeginFather<BeginPlane>
{
    // 获取开始面板中的各个按钮控件

    public Button but1;
    public Button but2;
    public Button but3;
    public Button but4;
   
    private void Start()
    {
        but1.triggerEvent += () => { SceneManager.LoadScene("Start"); };                 //点击“开始游戏”
        but2.triggerEvent += () => { Hidden(); SetPlane.SingleInstance.Show();   };      //点击“游戏设置”
        but3.triggerEvent += () => { Application.Quit(); };                              //点击“退出游戏”
        but4.triggerEvent += () => { Hidden();  };                                       //点击“排行榜”
    }


}


🎶(D逻辑封装——游戏排行榜数据存储


界面设计

在这里插入图片描述

  • 效果演示:在这里插入图片描述

😶‍🌫️:步骤实现

  • 1.封装排行榜数据类(无参构造做new ,有参构造做一键赋值)

  • 2.以数据管理类为载体进行更新API封装——只存储排行榜中的数据到盘(注册表)中

  • 3.封装排行榜面板类进行实时显示


在这里插入图片描述-----在这里插入图片描述

封装排行榜数据类(无参构造做new ,有参构造做一键赋值)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________项目:   
//___________功能: 排行榜数据的载体    
//___________创建者:秩沅_______________
//_____________________________________
//-------------------------------------
public class RankData
{ 
    public string name;
    public int score;
    public int time;
    public RankData() //用来new
    {

    }
    public RankData(string name, int score, int time ) //用来一键赋值
    {
        this.name = name ;
        this.score = score ;
        this.time = time;
    }
}

在这里插入图片描述 ----------------------在这里插入图片描述
以数据管理类为载体进行更新API封装

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________脚本名:   游戏数据管理类   
//___________功能:    记录和更新游戏的数据并用PlayerFabs存储
//___________创建者:秩沅_______________
//_____________________________________
//-------------------------------------

public class GameData         
{
    static private GameData dataContorl = new GameData ();
    static public  GameData DataContorl => dataContorl ;
    public MusicData musicData ;
    public List<RankData> rankTopData;//固定承载前六名的数据信息

    private GameData()
    {
       
        //初始化读取音乐数据
        musicData = PlayerPrefsDataMgr.Instance.LoadData(typeof(MusicData), "Music") as MusicData ;
        //初始化读取排行榜数据
        rankTopData = PlayerPrefsDataMgr.Instance.LoadData(typeof(List<RankData>), "Rank") as List<RankData>;

        if ( !musicData.isFirst ) //如果是第一次进入游戏(表示注册表中第一次存该类型数据时)
        {
            musicData.isFirst = true;
            musicData.musicSwitch = true;
            musicData.soundSwitch = true;
            musicData.musicRoll = 1f;
            musicData.soundRoll = 1f;
            PlayerPrefsDataMgr.Instance.SaveData(musicData, "Music");                
        }
      
          }       
    //------------------------排行榜数据的更新封装-------------------------------

        
    //在排行榜中添加数据

    public void SaveRankData(string name, int score, int time)
    {
        rankTopData.Add(new RankData(name, score, time));
        Debug.Log(rankTopData);
        rankTopData.Sort((a, b) => { return a.score > b.score ? -1 : 1; }); //添加排序规则

        //但list大于6时
        for (int i = rankTopData.Count - 1 ; i > 5; i--)
        {
            rankTopData.RemoveAt(i); //删除
        }
        
        PlayerPrefsDataMgr.Instance.SaveData(rankTopData, "Rank" );
    }


    //------------------------音乐数据的更新封装------------------------------

    //音乐开关数据的更新存储

    public void ChangeMusicS( bool value)
    {
        musicData.musicSwitch = value;
        PlayerPrefsDataMgr.Instance.SaveData(musicData,"Music");
    }

    //音效开关数据的更新存储

    public void ChangeSoundS(bool value)
    {
        musicData.soundSwitch  = value;
        PlayerPrefsDataMgr.Instance.SaveData(musicData, "Music");
    }

    //音乐滑条数据的更新存储

    public void ChangeMusicR(float value)
    {
        musicData.musicRoll  = value;
        PlayerPrefsDataMgr.Instance.SaveData(musicData, "Music");
    }

    //音效滑条数据的更新存储

    public void ChangeSoundR(float value)
    {
        musicData.soundRoll  = value;
        PlayerPrefsDataMgr.Instance.SaveData(musicData, "Music");
    }
}


在这里插入图片描述-----------在这里插入图片描述
3.封装排行榜面板类进行实时显示

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//-------------------------------------
//—————————————————————————————————————
//___________脚本名:  排行榜面板
//___________功能:   掌控排行榜面板相关控件
//___________创建者: 秩沅_______________
//_____________________________________
//-------------------------------------


public class RankPlane : BeginFather<RankPlane >
{

    public Button closeButton;

    //采用列表的方式进行排行数据的暂时存储

    private List<Label> RK_Name = new List<Label>();
    private List<Label> RK_Score = new List<Label>();
    private List<Label> RK_Time = new List<Label>();
  
    private void Start()
    {
        //通过API获取排行榜中的标签
        for (int i = 1; i <= 6; i++)
        {        
            RK_Name.Add(this.transform.Find("RKName/player" + i ).GetComponent<Label>());
            RK_Score.Add(this.transform.Find("RKScore/Score" + i ).GetComponent<Label>());
            RK_Time.Add(this.transform.Find("RKTime/time" + i ).GetComponent<Label>());       
        } 

        //为按钮中的事件添加方法
        closeButton .triggerEvent += ()=>{
            Hidden(); BeginPlane.SingleInstance.Show();
        };
        Hidden();    
    }

    public override void Show()
    {
        base.Show();
        ShowRankData();
    }

    public void ShowRankData()  //读盘排行榜数据并显示
    {
        GameData.DataContorl .SaveRankData("nibb", 100, 342);
        List<RankData> data = GameData.DataContorl.rankTopData;
        
        for (int i = 0; i < data.Count; i++)
        {
            string showTime = "";
            int hour, min, second;
            print(data[i].name);
            RK_Name[i].ContorlContent.text = data[i].name;
            RK_Score[i].ContorlContent.text = data[i].score.ToString();
            RK_Time[i].ContorlContent.text = "";
            //时间格式转化
            hour = data[i].time / 3600;
            min = data[i].time / 60 % 60;
            second = data[i].time % 60;
            showTime = $"{hour}小时{min}分钟{second}秒";

            RK_Time[i].ContorlContent.text = showTime;
        }
    }
}

总UML图

在这里插入图片描述


在这里插入图片描述


👌结论:

1.进行模块化处理,数据管理就是数据管理,面板显示就是面板显示,各司其职,员工不得乱工作
2.抽象行为,分配行为,你就是掌控者


相关文章


⭐【2023unity游戏制作-mango的冒险】-6.关卡设计

⭐【2023unity游戏制作-mango的冒险】-5.攻击系统的简单实现

⭐【2023unity游戏制作-mango的冒险】-4.场景二的镜头和法球特效跟随

⭐【2023unity游戏制作-mango的冒险】-3.基础动作和动画API实现

⭐【2023unity游戏制作-mango的冒险】-2.始画面API制作

⭐【2023unity游戏制作-mango的冒险】-1.场景搭建

⭐“狂飙”游戏制作—游戏分类图鉴(网易游学)

⭐本站最全-unity常用API大全(万字详解),不信你不收藏



你们的点赞👍 收藏⭐ 留言📝 关注✅是我持续创作,输出优质内容的最大动力!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安卓UI:SearchView

目录 一、SearchView介绍 二、常用方法 &#xff08;一&#xff09;、监听器&#xff1a; (二)、常用方法&#xff1a; (三)、其他常用方法 三、例子&#xff1a; MainActivity2 &#xff1a; ChatListAdapter &#xff1a; item_people_view: activity_main2: 运行结果…

Java支付SDK接口远程调试 - 支付宝沙箱环境【公网地址调试】

文章目录 1.测试环境2.本地配置3. 内网穿透3.1 下载安装cpolar内网穿透3.2 创建隧道 4. 测试公网访问5. 配置固定二级子域名5.1 保留一个二级子域名5.2 配置二级子域名 6. 使用固定二级子域名进行访问 转载自cpolar极点云文章&#xff1a;Java支付宝沙箱环境支付&#xff0c;SD…

详解 ➾【FTP服务工作原理及连接模式】

详解 ➾【FTP服务工作原理及连接模式】 &#x1f53b; 前言&#x1f53b; 一、FTP服务简介&#x1f6a5; 1.1 FTP工作原理&#x1f6a5; 1.2 匿名用户访问的产生&#x1f6a5; 1.3 FTP服务的连接模式&#x1f6a5; 1.4 几种流行的FTP服务器软件 &#x1f53b; 总结—温故知新 &…

QTranslator语言转换

//appname的格式 例如通常为&#xff08;QQ为应用的名称&#xff09; QQ_en.ts或QQ_zh_CN.ts QString qmName"zh_CN"; QTranslator trans ; QString qm QString(":/translatoin/qt/appname_%1.qm").arg(qmName); auto ret trans.load(qm); Q_UNUSED(ret)…

WebSocket理解

WebSocket理解 WebSocket定义与HTTP关系相同点:不同点&#xff1a;联系总体过程 HTTP问题长轮询Ajax轮询 WebSocket特点 WebSocket 定义 本质上是TCP的协议 持久化的协议 实现了浏览器和服务器的全双工通信&#xff0c;能更好的节省服务器资源和带宽 与HTTP关系 相同点: 基于…

小白到运维工程师自学之路 第五十三集 (rsync+inotify备份)

一、概述 Rsync是一个用于在不同计算机之间同步文件和文件夹的工具。它可以在本地计算机和远程服务器之间复制、更新和备份文件。rsync通过比较源和目标文件的差异来最小化传输的数据量&#xff0c;从而提供高效的文件同步功能。 Inotify是Linux内核提供的一种机制&#xff0…

web中引入live2d的moc3模型

文章目录 前言下载官方sdk文件使用ide编译项目&#xff08;vsCode&#xff09;项目初始化使用vsCode项目树介绍使用live server运行index页面 演示导入自己的模型并显示modelDir文件resources文件夾案例模型修改modelDir然後重新打包項目運行 前言 先跟着官方sdk调试一遍&…

【状态估计】基于卡尔曼滤波器和扩展卡尔曼滤波器用于 INS/GNSS 导航、目标跟踪和地形参考导航研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Windows VScode如何配置与使用git?

当我们在VScode中编写代码后&#xff0c;需要提交到git仓库时&#xff0c;但是我们又不想切换到git的命令行窗口&#xff0c;我们可以在VScode中配置git&#xff0c;然后就可以很方便快捷的把代码提交到仓库中。 1. 官网下载安装Git命令行工具 根据自己的电脑系统&#xff0c…

尚硅谷Docker实战教程-笔记12【高级篇,Docker-compose容器编排】

尚硅谷大数据技术-教程-学习路线-笔记汇总表【课程资料下载】视频地址&#xff1a;尚硅谷Docker实战教程&#xff08;docker教程天花板&#xff09;_哔哩哔哩_bilibili 尚硅谷Docker实战教程-笔记01【基础篇&#xff0c;Docker理念简介、官网介绍、平台入门图解、平台架构图解】…

3.2.17 什么是数组及应用

【分享成果&#xff0c;随喜正能量】人这一生&#xff0c;好不好都得自己走&#xff0c;累不累都得自己承受。每个人都有难言之苦&#xff0c;每个人都有无声的泪&#xff0c;岁月可曾放过谁&#xff1f;再风光的人&#xff0c;背后都有寒凉凄楚&#xff0c;再幸福的人&#xf…

[每周一更]-(第54期):Go的多版本管理工具

参考 https://zhuanlan.zhihu.com/p/611253641https://learnku.com/articles/78326 前文概要 Go语言从开始使用从1.13起步&#xff0c;随着泛型的支持&#xff0c;带领团队在转型Go的时候&#xff0c;做基础组件架构选型使用1.18&#xff0c;但是Go版本不断迭代想使用最新版本…

C++类相关概念

1. 函数形参默认值 &#xff08;1&#xff09; 建议函数&#xff08;不仅仅是构造函数&#xff09;形参默认值只在函数声明中指定&#xff1b; &#xff08;函数声明和定义写在同一个文件中&#xff0c;则函数声明、定义两者之一或两者都可指定形参默认值&#xff0c;两者都指…

中国移动光猫设置桥接

网上教程五花八门&#xff0c;有些坑有些行&#xff0c;我试成功了&#xff0c;记录一下方法。 一、流程简述 1. 使用超级管理员账号登录中国移动光猫&#xff0c;设置桥接&#xff0c;并重启 2. 用网线连接路由器和光猫&#xff0c;登录路由器&#xff0c;设置宽带拨号&…

数据分析——AB测试应用与实战

摘要 某电商公司非常注重自己的落地页设计&#xff0c;希望通过改进设计来提高转化率。以往该公司全年转化率平均在13%左右&#xff0c;现在希望设计的新页面能够带来更高的转化率&#xff0c;希望新页面的转化率能有2%的提升&#xff0c;达到15%。在正式推出新页面之前&#…

【Distributed】分布式ELK日志文件分析系统(二)

文章目录 一、FilebeatELK 部署1. 环境部署2. 在 Filebeat 节点上操作2.1 安装 Filebeat2.2 设置 filebeat 的主配置文件 3. 在 Apache 节点上操作3.1 在 Logstash 组件所在节点上新建一个 Logstash 配置文件 3. 启动3.1 在Logstash 组件所在节点启动3.2 在 Filebeat 节点 启动…

Python调用ImageMagick生成PDF文件缩略图

使用Python调用ImageMagick生成PDF文件缩略图 Imagemagick使用Ghostscript作为其依赖项之一&#xff0c;以便能够处理和转换PDF相关的图像。 准备 安装Ghostscript&#xff0c;网站安装ImageMagick&#xff0c;网站 安装完毕后&#xff0c;需要自行配置环境路径 脚本 使用示…

【USRP X310】如何将你的X310转化为USRP RIO 可以用于FPGA编程

X310 转化为USRP RIO X310产品X310和NI-USRP对应关系 简介第一步原理解释打开工具运行 Initialize Flash.vi可以去选择设备类型Hardware Current Version 如何选择 第二步创建工程运行校准程序 附录&#xff1a;射频子板的IDWBXSBXCBXUBXTwinRX X310产品 X310和NI-USRP对应关系…

jvm新生代调优

5-4 新生代调优 只有排除了自己代码的问题后&#xff0c;再进行内存调优&#xff0c;内存调优都是从新生代开始&#xff0c;因为新生代优化空间更大一些 新生代的特点 所有的new操作分配内存都是非常廉价的&#xff0c;非常快 TLAB&#xff1a;thread-local allocation buf…

Redis——基础篇(包含redis在云服务上的docker化安装和连接以及常用命令)

初识Redis Redis为键值型数据库&#xff0c;数据以键值形式存储。没有表&#xff0c;没有约束。 认识NoSQL mysql就是典型的关系型数据库(SQL)。 目的都是数据的增删改查&#xff0c;但数据存储方式不一样。 关系型和非关系型在结构上有差异 关系型的结构一般定好后就很少修…
最新文章