SignalR——聊天室实践

news2024/9/23 8:55:10

SignalR 是一个为 ASP.NET 开发者设计的库,它简化了在 Web 应用程序中添加实时功能的过程。实时功能指的是服务器能够在客户端没有发起请求的情况下主动向客户端推送内容的能力。这种技术使得服务器和客户端之间的通信更加动态和即时,非常适合需要实时更新数据的应用场景,如聊天应用、实时数据分析、多人协作编辑工具等。


SignalR 的特点:
双向通信:SignalR 允许服务器和客户端之间进行双向通信,即服务器可以主动向客户端发送数据,而不仅仅限于传统的客户端请求-服务器响应模式。


自动处理连接状态:SignalR 自动处理客户端的连接状态,包括连接、断开连接以及重新连接等操作。


多种传输方式:SignalR 支持多种传输方式,如 WebSockets、Server-Sent Events (SSE)、Long Polling 等,以确保在不同的浏览器和网络环境下都能实现最佳的通信效果。


易于使用的 API:SignalR 提供了一个简单易用的 API,使得开发者可以轻松地在服务器端实现远程过程调用 (RPC),即在服务器端调用客户端的 JavaScript 函数,反之亦然。
 

客户端支持:除了 JavaScript 客户端之外,SignalR 还支持其他客户端平台,如 iOS、Android 和 .NET 客户端。


分组和过滤:SignalR 允许你将连接到同一个 Hub 的客户端分组,并对特定组发送消息。

使用场景:
实时聊天应用:实现即时消息传送。


在线协作编辑:允许多个用户同时编辑同一个文档。


股票市场或体育赛事直播:实时更新数据到用户的界面。


在线游戏:实现玩家之间的实时互动。


SignalR 适用于 ASP.NET 和 ASP.NET Core 应用程序,并且是开源的,这意味着它可以免费使用,并且有一个活跃的社区支持。如果你正在使用 ASP.NET 或 ASP.NET Core 构建 Web 应用程序,并且需要实现实时功能,那么 SignalR 将是一个很好的选择。

下面使用ASP.NET Core应用程序跟做一个项目:使用VS

参考视频:011.SqlSugar介绍和安装_哔哩哔哩_bilibili

项目初始化

不要选错喽~ 

新建完成后的目录结构:

运行截图:

绘制聊天界面

修改Index.cshtml页面

@{
    ViewData["Title"] = "Home Page";
}

<div class="container">
    <p> 当前登录用户:@ViewBag.UserName [<a href="/Home/LogOut"> 退出</a>]</p>
    <div id="content"></div>
    <div contenteditable="true" id="messageInput"></div>
    <div class="row">
        <div class="col-6">
            <input type="button" id="sendButton" value="Send Message"/>
            <input type="button" id="findButton" value="Find Message" />

        </div>
    </div>
    <div id="historyMessage"></div>
</div>
<style>
    .container{
        width:800px;
        margin:0px auto;

    }
    #content{
        width:100%;
        height:300px;
       /*  溢出隐藏  有滚轮 */
        overflow-x:hidden;
        border:1px solid #ccc;
    }
    #messageInput{
        width:100%;
        min-height:100px;
        border:1px solid #bbb;
    }
    #historyMessage{
        display:none;
        width:100%;
        height:300px;
        overflow:hidden;
        border:1px solid #ccc;
    }
</style>

其中@ViewBag.UserName 需要在HomeController中设置一个默认值,如Rise,如图

运行结果:

新增登录页面

在HomeController中新增控制器

 public IActionResult Login()
 {
     return View();
 }

右键Login新增视图或者在View爆红处Alt+Enter提示添加视图

会新增一个Login.cshtml文件

添加代码

<div id="login">
    <h1 class="title"> 登录聊天室</h1>
    <form action="/Home/Submit">
        <table>
            <tr>
                <td>
                    用户名:
                </td>
                <td> <input placeholder="请输入用户名" name="name"/></td>


            </tr>
            <tr>
                <td>密码:</td>
                <td> <input placeholder="请输入密码" name="password" type="password"/></td>

            </tr>
            <tr>
                <td colspan="2">
                    <div class="operation">
                        <button id="submit" type="submit"> 登录</button>
                        <button id="cancel" > 取消</button>

                    </div>
                </td>
            </tr>
        </table>
    </form>
</div>
<style>
    table{
        margin :200px auto;
        border-collapse:separate;
        border-spacing:10px;

    }

    .operation{
        display:flex;
        justify-content:space-evenly;
    }
    button{
        width:80px;
    }
    .title{
        justify-content: space-evenly;
    }
</style>

/Home/Login 查看实现样式

介绍SignalR

‌SignalR是一个继承的客户端与服务器库‌,它基于浏览器的客户端和ASP.NET的服务器组件,允许进行双向多步对话。这种对话不受限制,可以进行单个无状态请求/响应数据交换,直到明确关闭。对话通过永久连接进行,使得客户端和服务器能够发送多个消息,并允许服务器做出相应答复。特别的是,SignalR还允许服务器向服务端发送异步消息,这与Ajax技术相似,都是基于现有的技术实现的。在实现客户端和服务端通信时,SignalR通常会使用JS的长轮询(long polling)。此外,随着WebSockets的出现,SignalR也支持WebSockets通信,从而提供了更高效的实时通信解决方案。

SignalR的应用场景非常广泛,例如实现实时聊天、服务器广播高频率实时功能。通过SignalR,开发人员可以轻松地构建实时Web应用程序,实现服务器与客户端之间的实时数据同步,从而提高用户体验和应用程序的交互性。此外,SignalR还提供了丰富的文档和示例,帮助开发人员快速入门和使用。无论是通过Visual Studio的不同版本进行开发,还是利用SignalR实现单页应用程序的实时更新,SignalR都为Web开发提供了强大的支持‌

官方介绍:SignalR 简介 | Microsoft Learn

添加SignalR客户端库

右键项目-点击添加-点击客户端库,如图

提供程序选择unpkg,输入库(不要输错,输入完成回车),点击选择特定文件就自动带出来了,勾选两个js,修改目标位置即可,如图,点击安装。

等待几秒看到解决方案管理器中的相对路径中是否存在两个js文件

存在即安装好了

创建SignalR中心

中心是一个类,用于处理客户端和服务器通信的高级管道,在SignalRWebApp项目文件夹中,创建Hubs文件夹。在Hubs文件夹中,使用以下代码创建ChatHub类.

项目右键,新建文件夹Hubs

新建的文件夹下,右键新建一个类ChartHub

ChatHub.cs中添加代码

using Microsoft.AspNetCore.SignalR;

namespace SignalRWebWebApp.Hubs
{
    /// <summary>
    ///
    ///创建SignalR中心
    /// </summary>
    public class ChatHub:Hub
    {
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="user">用户名</param>
        /// <param name="message">密码</param>
        /// <returns></returns>
        public async Task SendMessage(String user, String message)
        {
            await Clients.All.SendAsync("ReceiveMessage",user,message);
        }
    }
}

配置SignalR

必须将SignalR服务器配置为将SignalR请求传递给SignalR。

将一下突出显示的代码添加到Program.cs文件中

builder.Services.AddSignalR();
app.MapHub<ChatHub>("/chatHub");

program.cs

using SignalRWebWebApp.Hubs;

var builder = WebApplication.CreateBuilder(args);
//添加signalR服务
builder.Services.AddSignalR();
// Add services to the container.
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

//配置
app.MapHub<ChatHub>("/chatHub");


app.Run();

添加SignalR客户端代码

wwwroot下的js文件夹,右键新建项

新增chat.js(javaScript文件)

在chat.js中添加打印代码

console.log("执行客户端代码");

在Views-Home-Index.cshtml中引入js文件

<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="js/signalr/dist/browser/signalr.min.js"></script>
<script src="js/chat.js"></script>

运行检查是否引入成功

F12查看,说明引入成功

修改chat.js代码

"use strict";

//const { signalR } = require("./signalr/dist/browser/signalr");
//连接服务
var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();

//禁止发送按钮,直到建立连接
$("#sendButton").hide();
//建立连接
connection.start().then(function () {
    //连接成功,则显示发送按钮
    $("#sendButton").show();
      console.log("连接成功!");

}).catch(function (err) {
    //连接失败则返回错误信息
    return console.error(err.toString());
});

运行,存在SendMessage按钮说明连接成功

chat.js中添加代码,如下所示,已经可以互通了

"use strict";

//const { signalR } = require("./signalr/dist/browser/signalr");
//连接服务
var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();

//禁止发送按钮,直到建立连接
$("#sendButton").hide();
//建立连接
connection.start().then(function () {
    //连接成功,则显示发送按钮
    $("#sendButton").show();
    console.log("连接成功!");

}).catch(function (err) {
    //连接失败则返回错误信息
    return console.error(err.toString());
});
//发送消息
$("#sendButton").click(function () {
    var user = $("#userInput").val();
    var message = $("#messageInput").text();
    connection.invoke("SendMessage", user, message).catch(function (err) {
        return console.error(err.toString);
    })
});

//接收消息
connection.on("ReceiveMessage", function (user, message, time) {
    $("#content").append(`<p>${user} ${time}</p><p>${message}</p><br>`);
    $("#content").animate({ scrollTop: 100000 });
})

sqlSugar介绍和安装

官网:SqlSugar .Net ORM 5.X 官网 、文档、教程 - SqlSugar 5x - .NET果糖网 (donet5.com)

ISqlSugarClient

在依赖项中右键管理NuGet程序包,搜索sqlSugarCore安装

依赖项中出现包说明安装成功

appsettings.json文件中添加连接数据库的字符串

在Program.cs中添加注入SqlSugar服务的


builder.Services.AddTransient<ISqlSugarClient>(provider =>
{
    SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
    {
        ConnectionString = builder.Configuration.GetSection("conn").Value,
        DbType = DbType.MySql,
        IsAutoCloseConnection = true
    });
    return db;
});

UserService

新增service文件夹并新增两个文件IUserService和UserService

program.cs中注册服务

//注册用户服务
builder.Services.AddTransient<IUserService, UserService>();

CodeFirst

添加

UserInfo和Usermessage

UserInfo代码

using SqlSugar;

namespace SignalRWebWebApp.Models
{
    public class UserInfo
    {
        [SugarColumn(IsPrimaryKey = true)]
        public int Id { get; set; }

        public string Name { get; set; }
        public string Password { get; set; }
    }
}

UserMessage代码

using SqlSugar;

namespace SignalRWebWebApp.Models
{
    public class Usermessage
    {
        [SugarColumn(IsPrimaryKey = true)]
        public int Id { get; set; }
        public string UserName { get; set; }
        public string Content { get; set; }
        public DateTime CreateDateTime { get; set; }
    }
}

修改UserService.cs(注意两个命名空间名字)

using System.Reflection;
using SqlSugar;

namespace SignalRWebWebApp.Service
{
    public class UserService : IUserService
    {
        private readonly ISqlSugarClient _db;
        public UserService(ISqlSugarClient db)
        {
            _db = db;
        }   

        public bool CodeFirst()
        {
            try
            {
                //创建数据库
                _db.DbMaintenance.CreateDatabase();
                string nspace = "SignalRWebWebApp.Models";
                Type[] ass = Assembly.LoadFrom(AppContext.BaseDirectory + "SignalRWebWebApp.dll").GetTypes()
                    .Where(p => p.Namespace == nspace).ToArray();
                _db.CodeFirst.SetStringDefaultLength(200).InitTables(ass);
            }
            catch (Exception e)
            {
                
                return false;
            }
            return true;
        }
    }
}

修改IUserSercice.cs

namespace SignalRWebWebApp.Service
{
    public interface IUserService
    {
        bool CodeFirst();
    }
}

修改HomeController

using Microsoft.AspNetCore.Mvc;
using SignalRWebWebApp.Models;
using System.Diagnostics;
using SignalRWebWebApp.Service;

namespace SignalRWebWebApp.Controllers
{
    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;
        private readonly IUserService _user;

        public HomeController(ILogger<HomeController> logger,IUserService user)
        {
            _logger = logger;
            _user = user;
        }

        public bool CodeFirst()
        {
            return _user.CodeFirst();
        }

        public IActionResult Index()
        {
            ViewBag.UserName = "Rise";
            return View();
        }


        public IActionResult Login()
        {
            return View();
        }

        public IActionResult Privacy()
        {
            return View();
        }


    }
}

运行访问/Home/CodeFirst 如果是true则数据库和表新建成功

如果是false则排查问题

获取注册用户信息接口

在UserService和IUserService中添加相关代码

IUserService

using SignalRWebWebApp.Models;

namespace SignalRWebWebApp.Service
{
    public interface IUserService
    {
        bool CodeFirst();
        UserInfo GetUser(string name, string password);
    }
}

UserService

  public UserInfo GetUser(string name, string password)
  {
      UserInfo userInfo = _db.Queryable<UserInfo>().First(n=>n.Name==name);
      if (userInfo == null)
      {
          UserInfo newInfo = new UserInfo()
          {
              Id = Convert.ToInt32(Guid.NewGuid().ToString()),
              Name = name,
              Password = password
          };
          return _db.Insertable(newInfo).ExecuteReturnEntity();
      }
      else if (userInfo.Password == password)
      {
          return new UserInfo();
      }

      return userInfo;
  }

获取消息记录接口

UserService、IUserService和HomeController中新增内容

IUserService

List<UserMessage> GetMessages(int pageIndex,int pageSize);

UserService


        public List<UserMessage> GetMessages(int pageIndex, int pageSize)
        {
            return _db.Queryable<UserMessage>().ToOffsetPage(pageIndex, pageSize);
        }

HomeController

  public JsonResult GetMessages(int pageIndex,int pageSize )
  {
      return Json(_user.GetMessages(pageIndex, pageSize));
  }

首页重定向

program.cs添加

//添加Session服务
builder.Services.AddSession();
//使用
app.UseSession();

修改HomeController

    public IActionResult Index()
    {
        var userName = HttpContext.Session.GetString("userName");
        if (string.IsNullOrEmpty(userName))
        {
            return Redirect("/Home/Login");
        }
        

        ViewBag.UserName = userName;
        return View();
    }

登录逻辑

在HomeController中添加代码

    public IActionResult Submit(string name, string password)
    {
        UserInfo userInfo = _user.GetUser(name, password);
        if (string.IsNullOrEmpty(userInfo.Id))
        {
            return Redirect("/Home/Error");
        }
        HttpContext.Session.SetString("userName",userInfo.Name);
        Response.Cookies.Append("userName",userInfo.Name);
        return Redirect("/");
    }

退出逻辑

在HomeController中添加代码

 public IActionResult LogOut()
 {
     HttpContext.Session.Remove("userName");
     Response.Cookies.Delete("userName");
    return  Redirect("/Home/Login");
 }

补充SignalR中心逻辑

ChatHub中新增

using Microsoft.AspNetCore.SignalR;
using SignalRWebWebApp.Models;
using SqlSugar;

namespace SignalRWebWebApp.Hubs
{
    /// <summary>
    ///
    ///创建SignalR中心
    /// </summary>
    public class ChatHub:Hub
    {
        private ISqlSugarClient _db;
        public ChatHub(ISqlSugarClient db)
        {
            _db = db;
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="user">用户名</param>
        /// <param name="message">密码</param>
        /// <returns></returns>
        public async Task SendMessage(String user, String message)
        {
            DateTime time= DateTime.Now;
            UserMessage userMessage = new UserMessage()
            {
                Id = Guid.NewGuid().ToString(),
                UserName = user,
                Content = message,
                CreateDateTime = time,
            };
            _db.Insertable(userMessage).ExecuteCommand();
            await Clients.All.SendAsync("ReceiveMessage",user,message,time.ToString());
        }
    }
}

查看历史聊天记录

在chat.js中新增


//查看聊天记录
var pageIndex = 1;
$("#findMessage").click(function () {
    $("#historyMessage").fadeIn();
    $.post("/Home/GetMessages", { pageIndex: pageIndex, pageSize: 10 }, function (data) {
        $.each(data, function (i, e) {
            $("#historyMessage").append(`<p>${e.userName} ${e.createDateTime}</p><p>${e.content}</p><br>`);

        });
    })

})

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

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

相关文章

iOS P8证书推送测试

最近在配合服务端人员调试相关的 APNS auth key 推送的问题&#xff0c;相比于苹果的P12证书的推送&#xff0c;P8证书的推送显得方便很多&#xff0c;P8的优势在于简单&#xff0c;安全 容易生成 最重要的是不会过期。 现在我们来看下测试具体流程&#xff1a; 方法一 地址…

Hive服务部署及Datagrip工具使用

目录 Hive服务部署 Hiveserver2服务 1&#xff09;用户说明 2&#xff09;Hiveserver2部署 &#xff08;1&#xff09;Hadoop端配置 &#xff08;2&#xff09;Hive端配置 3&#xff09;测试 &#xff08;1&#xff09;启动Hiveserver2 &#xff08;2&#xff09;使用命…

GoFly企业版里的阿里图标如何增加自定义图标到后台

1.在使用的vue页面引入图标组件 <script lang"ts" setup>import {Icon} from /components/Icon;</script> 2.在具体位置使用 <template><Icon icon"svgfont-icon7" class"iconbtn" :size"18" color"#ed6…

如何进行 AWS 云监控

什么是 AWS&#xff1f; Amazon Web Services&#xff08;AWS&#xff09;是 Amazon 提供的一个全面、广泛使用的云计算平台。它提供广泛的云服务&#xff0c;包括计算能力、存储选项、网络功能、数据库、分析、机器学习、人工智能、物联网和安全。 使用 AWS 有哪些好处&…

华为云全栈可观测平台(APM)8月新功能特性

华为云应用性能管理服务&#xff08;Application Performance Management&#xff0c;简称APM&#xff09;帮助运维人员快速发现应用的性能瓶颈&#xff0c;以及故障根源的快速定位&#xff0c;为用户体验保驾护航。 您无需修改代码&#xff0c;只需为应用安装一个APM Agent&a…

Linux/Ubuntu服务器 screen 安装与使用

一、screen简单介绍 在Linux系统中&#xff0c;screen是一个非常强大的终端仿真器&#xff0c;它允许用户在一个终端窗口中创建多个子窗口&#xff0c;每个子窗口都可以运行一个独立的会话。screen的主要特点包括&#xff1a; 会话分离&#xff1a;screen允许用户在终端会话中运…

lottie-web动画库实战详解

安装 npm install lottie-web pnpm install lottie-web yarn add lottie-web <divid"animation"style"width: 700px; height: 440px; margin-top: 80px"></div>import lottie from "lottie-web"; import loginJson from ".…

大零售时代:开源 AI 智能名片、2+1 链动与 O2O 商城小程序引领融合新趋势

摘要&#xff1a;本文深入探讨了当今零售业态的发展趋势&#xff0c;指出在数据匹配的时代&#xff0c;人依然在零售中发挥着重要作用。通过对大零售理念的阐述&#xff0c;分析了跨行业跨业态融合的必然性&#xff0c;强调了业态融合的指导思想以及实现方式。同时&#xff0c;…

管理非人类身份的隐形风险

在网络安全的动态世界中&#xff0c;身份和访问管理 (IAM) 是关键的基础。确保只有授权的个人和系统才能访问公司资源至关重要。 不幸的是&#xff0c;虽然许多组织擅长管理人类身份&#xff0c;但他们通常需要更多地关注不断增长且可能更具危险的数字参与者类别&#xff0c;即…

LIN总线CAPL函数—— LIN报文响应空间长度测试

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…

社交媒体必备,2024年免费视频编辑软件助力内容创作

平常生活放松的时候你是不是通过一些短视频来放松情绪。我身边很多人都是看着看着也想分享自己的生活。这次我们来聊一聊抖音剪辑可以用到哪些工具。 1.福昕视频剪辑 连接直达>>https://www.pdf365.cn/foxit-clip/ 这款视频剪辑软件凭借其低门槛的设计理念&#xff0c…

div3 970

Problem - D - Codeforces 关键在于如果是环的话&#xff0c;环中的每一个的值都是一样的 #include<bits/stdc.h> #define int long long using namespace std; signed main(){int nn;cin>>nn;while(nn--){int n;cin>>n;int a[n1],i0;while(i<n)cin>…

电路分析 ---- 电平移位电路

1 电平移位电路 如图所示的电平移位电路&#xff0c;用于ADC的前级驱动&#xff0c;它将一个变化范围为-10V ~ 10V的输入信号&#xff0c;线性变化成0.048V ~ 4.048V的信号&#xff0c;以满足ADC的输入范围要求。 2 电路说明 V R E F V_{REF} VREF​为电压基准源&#xff0c…

假期学习----iOS多线程

iOS多线程 https://juejin.cn/post/6844903566398717960 什么是GCD Grand Central Dispatch&#xff08;GCD&#xff09; 是 Apple 开发的一个多核编程的较新的解决方法。它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统。 GCD的用处&#xff1a; GCD 可用…

mac安装spark

参考&#xff1a;在Mac上安装Spark apache-spark-3.5.1_mac安装spark-CSDN博客 几个需要用到的路径&#xff1a; hadoop的bin目录&#xff1a;/opt/homebrew/Cellar/hadoop/3.4.0/bin spark的conf目录/opt/homebrew/Cellar/apache-spark/3.5.2/libexec/conf spark的bin目录&am…

一般位置下的3D齐次旋转矩阵

下面的矩阵虽然复杂&#xff0c;但它的逆矩阵求起来非常简单&#xff0c;只需要在 sin ⁡ θ \sin\theta sinθ 前面加个负号就是原来矩阵的逆矩阵。 如果编程序是可以直接拿来用的&#xff0c;相比其它获取一般旋转轴不经过原点的三维旋转矩阵的途径或算法&#xff0c;应该能…

ArmSoM CM5 RK3576核心板推出,强势替代树莓派CM4

ArmSoM团队隆重推出全新的CM5 RK3576核心板&#xff0c;这款模块专为嵌入式开发者设计&#xff0c;凭借其强大的性能与丰富的扩展性&#xff0c;完美替代树莓派CM4&#xff0c;成为开发者们的理想选择。 CM5核心板采用了先进的RK3576 SoC&#xff0c;凭借卓越的计算能力和出色…

Java使用Selenium进行Web项目的UI自动化测试

目录 配置Selenium 1.使用Maven管理依赖 将三个依赖放到java的pom文件中 2.这里使用Edge进行简单的UI操作 3.提醒 FireFox和Chrome启动失败 Firefoxdriver启动失败 Chromedriver启动失败 java如何使用Selenium进行web的UI自动化测试 对一个项目进行测试目录详情…

Python作为客户端连接websocket

缘起 因为需要将MQTT中的数据推送给前端,但是前端不会直接连接MQTT,所以服务端做了一个中间层,通过websocket推送,但是在开发的过程中前端总是认为推送的数据不及时,所以这里又实用Python单独做了一个客户端做时间记录验证。开始吧 安装三方包 Python的生态很方便,这里…

oracle数据块内部结构详解

文章目录 Oracle数据块详解概述Oracle块具有以下特点&#xff1a;① 最小的I/O单元&#xff1b;② 包含一个或多个OS块&#xff1b;③ 大小由参数DB_BLOCK_SIZE决定&#xff1b;④ 数据库创建时设置&#xff0c;数据库创建后不能更改 Oracle数据块详解 概述 操作系统块是…