Springboot仿抖音app開發之用短視頻務模塊后端復盤及相關業務知識總結

Springboot仿抖音app開發之用戶業務模塊后端復盤及相關業務知識總結

?

?

BO類和VO類的區別

BO (Business Object) - 業務對象

  • 定義: 業務對象是包含業務邏輯的領域模型
  • 用途: 主要用于封裝業務邏輯相關的數據,在業務層(Service層)之間傳遞
  • 特點:
    • 與業務處理密切相關
    • 通常包含業務處理所需的數據
    • 在服務層之間或與DAO層之間傳輸數據
    • 可能包含一些業務計算方法

VO (View Object) - 視圖對象

  • 定義: 視圖對象是專門用于展示層的數據載體
  • 用途: 主要用于封裝視圖展示所需的數據,在控制層(Controller)和視圖層(前端)之間傳遞
  • 特點:
    • 與界面展示密切相關
    • 通常只包含頁面顯示所需的數據
    • 可能是對多個實體的組合,以適應頁面展示需求
    • 通常不包含業務邏輯方法

從您提供的代碼示例來看:

  1. VlogBO - 業務對象:

    public class VlogBO {private String id;private String vlogerId;private String url;private String cover;private String title;private Integer width;private Integer height;private Integer likeCounts;private Integer commentsCounts;
    }
    
    • 包含視頻博客的核心業務數據,如ID、URL、尺寸、點贊數等
    • 可能用于視頻上傳、處理等業務操作
  2. VlogerVO - 視圖對象:

    public class VlogerVO {private String vlogerId;private String nickname;private String face;private boolean isFollowed = true;
    }
    
    • 專注于前端展示需要的數據,如視頻創作者ID、昵稱、頭像和關注狀態
    • 簡化了數據結構,只包含UI層需要的信息
    • 添加了UI特定的字段,如isFollowed,這與前端交互相關

在實際應用中的區別

  1. 使用場景:

    • BO: 主要在service層使用,封裝業務邏輯所需的數據
    • VO: 主要在controller層使用,向前端返回數據
  2. 轉換關系:

    • 通常會有DO(Data Object) → BO → VO的轉換過程
    • DO是與數據庫表結構一一對應的對象
    • BO可能組合多個DO,添加業務處理
    • VO進一步調整BO,使其適合前端展示
  3. 職責分離:

    • 使用這些不同類型的對象有助于實現關注點分離
    • 每一層專注于自己的職責,使代碼更易于維護

保存視頻信息入庫

1. 控制層接收請求 (VlogController)

首先,前端向 /vlog/publish 端點發送 POST 請求,攜帶視頻信息:

@PostMapping("publish")
public GraceJSONResult publish(@RequestBody VlogBO vlogBO) {vlogService.createVlog(vlogBO);return GraceJSONResult.ok();
}

這個控制器方法:

  • 使用?@RequestBody?注解接收 JSON 格式的請求體,并自動反序列化為?VlogBO?對象
  • 調用?vlogService.createVlog(vlogBO)?處理業務邏輯
  • 返回成功響應給前端

2. 服務層處理業務邏輯 (VlogServiceImpl)

接下來,控制器調用服務層的 createVlog 方法:

@Transactional
@Override
public void createVlog(VlogBO vlogBO) {String vid = sid.nextShort();Vlog vlog = new Vlog();BeanUtils.copyProperties(vlogBO, vlog);vlog.setId(vid);vlog.setLikeCounts(0);vlog.setCommentsCounts(0);vlog.setIsPrivate(YesOrNo.NO.type);vlog.setCreatedTime(new Date());vlog.setUpdatedTime(new Date());vlogMapper.insert(vlog);
}

在這個方法中執行了以下操作:

  1. 事務管理

    • 使用?@Transactional?注解確保整個操作在一個事務中完成
  2. ID生成

    • 使用?sid.nextShort()?生成唯一的視頻ID
    • Sid?是一個分布式ID生成器,確保生成的ID在分布式環境中唯一
  3. 對象轉換

    • 創建數據庫實體對象?Vlog
    • 使用?BeanUtils.copyProperties()?將?VlogBO?的屬性復制到?Vlog?實體
  4. 設置默認值

    • 設置視頻ID:vlog.setId(vid)
    • 初始化點贊數和評論數為0
    • 設置視頻為公開狀態:vlog.setIsPrivate(YesOrNo.NO.type)
    • 設置創建時間和更新時間為當前時間
  5. 數據庫插入

    • 調用?vlogMapper.insert(vlog)?將視頻信息插入數據庫

3. 數據訪問層執行SQL (VlogMapper)

最后,vlogMapper 執行數據庫插入操作:

vlogMapper.insert(vlog);

這里的 VlogMapper 是一個 MyBatis 接口,會將 Vlog 對象映射為 SQL 插入語句并執行。

實現數據層mybatis自定義mapper與sql

實現查詢短視頻列表與分頁功能

1. 前端請求入口

前端通過HTTP GET請求訪問/indexList接口,傳入以下參數:

  • userId:當前用戶ID(可選)
  • search:搜索關鍵詞(可選)
  • page:頁碼
  • pageSize:每頁顯示條數
@GetMapping("indexList")
public GraceJSONResult indexList(@RequestParam(defaultValue = "") String userId,@RequestParam(defaultValue = "") String search,@RequestParam Integer page,@RequestParam Integer pageSize) {if (page == null) {page = COMMON_START_PAGE;}if (pageSize == null) {pageSize = COMMON_PAGE_SIZE;}PagedGridResult list = vlogService.queryIndexVlogList(userId, search, page, pageSize);return GraceJSONResult.ok(list);
}

2. 服務層處理

服務層實現分頁查詢邏輯:

@Override
public PagedGridResult queryIndexVlogList(String userId,String search,Integer page,Integer pageSize) {PageHelper.startPage(page, pageSize);Map<String, Object> map = new HashMap<>();if (StringUtils.isNotBlank(search)) {map.put("search", search);}List<IndexVlogVO> list = vlogMapperCustom.getIndexVlogList(map);// 注釋掉的代碼處理關注和點贊信息return setterPagedGrid(list, page);
}

這里有幾個關鍵點:

  • 使用PageHelper.startPage(page, pageSize)啟動分頁功能
  • 將查詢參數封裝到Map中
  • 調用自定義Mapper執行查詢
  • 使用setterPagedGrid方法封裝分頁結果

3. 數據訪問層查詢

自定義Mapper接口定義查詢方法:

public List<IndexVlogVO> getIndexVlogList(@Param("paramMap") Map<String, Object> map);

對應的XML映射文件:

xml

<select id="getIndexVlogList" resultType="com.imooc.vo.IndexVlogVO" parameterType="map">SELECTv.id as vlogId,v.vloger_id as vlogerId,u.face as vlogerFace,u.nickname as vlogerName,v.title as content,v.url as url,v.cover as cover,v.width as width,v.height as height,v.like_counts as likeCounts,v.comments_counts as commentsCounts,v.is_private as isPrivateFROMvlog vLEFT JOINusers uONv.vloger_id = u.idWHEREv.is_private = 0<if test="paramMap.search != null and paramMap.search != ''">and v.title LIKE '%${paramMap.search}%'</if>ORDER BYv.created_timeDESC</select>

這里的SQL實現了:

  • 聯表查詢視頻和用戶信息
  • 只查詢公開視頻(is_private = 0
  • 條件性添加搜索條件(模糊查詢標題)
  • 按創建時間降序排序

分析

  1. 參數注解

    • @Param("paramMap")?是MyBatis的參數注解
    • 它將傳入的Map參數在MyBatis中命名為"paramMap"
    • 這個命名使得在XML映射文件中可以通過paramMap來引用這個Map
  2. Map參數

    • 方法接受一個Map<String, Object>類型的參數
    • 這個Map可以包含多個鍵值對,用于傳遞不同的查詢條件
    • search是這個Map中的一個鍵,對應的值是搜索關鍵詞
  3. 關聯用戶信息(通過LEFT JOIN users u)能夠在一次查詢中同時獲取視頻創作者的頭像(u.face)和昵稱(u.nickname),這樣可以:

    在視頻列表中直接顯示創作者頭像和名稱

? ? ? ? ?減少前端需要發起的額外請求

? ? ? ? ?提升用戶體驗,用戶可以一眼看到視頻來源

4. 分頁結果封裝

將查詢結果封裝為統一的分頁響應格式:

public PagedGridResult setterPagedGrid(List<?> list, Integer page) {PageInfo<?> pageList = new PageInfo<>(list);PagedGridResult gridResult = new PagedGridResult();gridResult.setRows(list);gridResult.setPage(page);gridResult.setRecords(pageList.getTotal());gridResult.setTotal(pageList.getPages());return gridResult;
}

這個方法利用PageInfo類(PageHelper提供)獲取分頁元數據,并封裝到自定義的PagedGridResult對象中。

5. PageHelper工作原理

PageHelper通過ThreadLocal變量和攔截器實現分頁功能:

  • 當調用PageHelper.startPage(page, pageSize)時,在ThreadLocal中記錄分頁參數
  • 在執行SQL前,PageHelper攔截器會修改SQL,添加分頁語句(如MySQL的LIMIT)
  • 執行完SQL后,PageHelper會將查詢結果封裝到Page對象中
  • PageInfo構造函數會自動識別Page對象并提取分頁信息

${}#{}占位符的區別?

and v.title LIKE '%${paramMap.search}%'

特點

  • 直接替換:${}字符串直接替換,會將參數值直接替換到SQL語句中
  • 無類型處理:不會添加任何類型處理或轉義
  • 無預編譯:不使用預編譯占位符,而是在SQL字符串中直接替換

例子: 如果paramMap.search = "旅行",生成的SQL將是:

and v.title LIKE '%旅行%'

2.?#{}占位符 - 參數綁定

WHERE v.id = #{paramMap.vlogId}

特點

  • 參數綁定:#{}參數綁定,會被替換為?預編譯占位符
  • 自動類型處理:會根據參數類型進行適當的類型處理
  • 預編譯:使用預編譯語句,參數會作為PreparedStatement的參數傳遞
  • 自動轉義:會自動處理特殊字符,防止SQL注入

例子: 如果paramMap.vlogId = "1001",實際執行時的SQL會先被處理為:

WHERE v.id = ?

然后值"1001"作為參數綁定到這個位置。

兩者的主要區別

特性${}#{}
執行方式字符串替換參數綁定
SQL注入風險
類型處理自動
預編譯支持不支持支持
性能對于重復查詢較低支持語句緩存,性能更好
使用場景動態表名、列名、排序字段等一般的參數傳遞

為什么在這兩種情況下使用不同的占位符

1. 使用${}的場景 (模糊查詢)

and v.title LIKE '%${paramMap.search}%'

這里使用${}是因為:

  • LIKE語句中的百分號%需要與搜索詞直接拼接
  • 使用#{}會將整個值(包括%)當作一個參數,無法實現通配符功能

注意:這種用法存在SQL注入風險,更安全的方式是:

and v.title LIKE CONCAT('%', #{paramMap.search}, '%')

2. 使用#{}的場景 (精確匹配)

WHERE v.id = #{paramMap.vlogId}

這里使用#{}是因為:

  • 是精確匹配查詢,不需要字符串拼接
  • 需要防止SQL注入,提高安全性
  • 可以利用預編譯提升性能

視頻詳情頁展示的實現?

1. 控制層處理

@GetMapping("detail")
public GraceJSONResult detail(@RequestParam(defaultValue = "") String userId,@RequestParam String vlogId) {return GraceJSONResult.ok(vlogService.getVlogDetailById(userId, vlogId));
}

控制層接收兩個關鍵參數:

  • vlogId:要查詢的視頻ID(必傳)
  • userId:當前訪問用戶的ID(可選,默認為空)

這里直接調用服務層方法,并使用GraceJSONResult.ok()包裝結果,提供統一的響應格式。

2. 服務層處理

@Override
public IndexVlogVO getVlogDetailById(String userId, String vlogId) {Map<String, Object> map = new HashMap<>();map.put("vlogId", vlogId);List<IndexVlogVO> list = vlogMapperCustom.getVlogDetailById(map);if (list != null && list.size() > 0 && !list.isEmpty()) {IndexVlogVO vlogVO = list.get(0);// return setterVO(vlogVO, userId);return vlogVO;}// 這里應該有返回null的邏輯
}

服務層主要邏輯:

  • 創建參數Map,將視頻ID存入
  • 調用自定義Mapper執行數據庫查詢
  • 從查詢結果列表中獲取第一個元素作為結果
  • 注釋掉的代碼setterVO(vlogVO, userId)可能原本用于設置用戶相關狀態,如是否已點贊、是否已關注視頻創作者等

3. 數據訪問層查詢

Mapper接口定義:

public List<IndexVlogVO> getVlogDetailById(@Param("paramMap") Map<String, Object> map);

XML映射文件中的SQL查詢:

<select id="getVlogDetailById" parameterType="map" resultType="com.imooc.vo.IndexVlogVO">SELECTv.id as vlogId,v.vloger_id as vlogerId,u.face as vlogerFace,u.nickname as vlogerName,v.title as content,v.url as url,v.cover as cover,v.width as width,v.height as height,v.like_counts as likeCounts,v.comments_counts as commentsCounts,v.is_private as isPrivateFROMvlog vLEFT JOINusers uONv.vloger_id = u.idWHEREv.id = #{paramMap.vlogId}</select>

這個SQL查詢:

  • 聯合查詢視頻表(vlog)和用戶表(users)
  • 通過LEFT JOIN關聯視頻創作者信息
  • 使用vlogId作為查詢條件
  • 查詢結果包含視頻基本信息和創作者信息
  • 結果字段別名與VO對象屬性名對應,實現自動映射

4. 數據結構設計

從SQL查詢中可以看出,IndexVlogVO對象包含以下信息:

  • 視頻信息

    • vlogId:視頻ID
    • content:視頻標題/內容
    • url:視頻地址
    • cover:視頻封面
    • width/height:視頻尺寸
    • likeCounts:點贊數
    • commentsCounts:評論數
    • isPrivate:是否私有
  • 創作者信息

    • vlogerId:創作者ID
    • vlogerFace:創作者頭像
    • vlogerName:創作者昵稱

5. 業務處理特點

  1. 單一職責:各層次職責明確,控制層處理請求,服務層處理業務,數據訪問層執行查詢
  2. 數據封裝:使用VO對象封裝前端展示所需數據
  3. 關聯查詢:一次查詢獲取視頻和創作者信息,減少數據庫交互
  4. 參數傳遞:使用Map傳遞查詢參數,靈活性高
  5. 狀態設計:預留了設置用戶與視頻交互狀態的邏輯(被注釋掉的setterVO方法)

6. 實現特點與優勢

  1. 代碼復用:與首頁視頻列表使用類似的數據結構和查詢邏輯
  2. 查詢效率:通過ID直接查詢,高效精準
  3. 結構清晰:各層次分工明確,易于維護
  4. 擴展性好:預留了添加用戶交互狀態的擴展點
  5. 統一響應:使用GraceJSONResult統一API響應格式

實現轉為私密或公開視頻

1. 控制層處理請求

應用提供了兩個端點,分別用于將視頻設為私密或公開:

@PostMapping("changeToPrivate")
public GraceJSONResult changeToPrivate(@RequestParam String vlogerId,@RequestParam String Id) {vlogService.changeToPrivateOrPublic(vlogerId,Id,YesOrNo.YES.type);return GraceJSONResult.ok();
}@PostMapping("changeToPublic")
public GraceJSONResult changeToPublic(@RequestParam String vlogerId,@RequestParam String Id) {vlogService.changeToPrivateOrPublic(vlogerId,Id,YesOrNo.NO.type);return GraceJSONResult.ok();
}

這兩個方法的特點:

  • 都使用HTTP POST請求
  • 接收相同的參數:vlogerId(創作者ID)和Id(視頻ID)
  • 調用同一個服務方法,但傳入不同的狀態值
  • 使用枚舉YesOrNo來表示狀態(YES表示私密,NO表示公開)
  • 返回統一的成功響應

2. 服務層實現業務邏輯

服務層實現了統一的方法來處理狀態變更:

@Transactional
@Override
public void changeToPrivateOrPublic(String userId, String vlogId, Integer yesOrNo) {Example example = new Example(Vlog.class);Example.Criteria criteria = example.createCriteria();criteria.andEqualTo("id", vlogId);criteria.andEqualTo("vlogerId", userId);Vlog pendingVlog = new Vlog();pendingVlog.setIsPrivate(yesOrNo);vlogMapper.updateByExampleSelective(pendingVlog, example);
}

展示我的公開和私密視頻?

1. 控制層處理請求

應用提供了兩個端點,分別用于獲取用戶的公開和私密視頻列表:

@GetMapping("myPublicList")
public GraceJSONResult myPublicList(@RequestParam String userId,@RequestParam Integer page,@RequestParam Integer pageSize) {if (page == null) {page = COMMON_START_PAGE;}if (pageSize == null) {pageSize = COMMON_PAGE_SIZE;}PagedGridResult gridResult = vlogService.queryMyVlogList(userId,page,pageSize,YesOrNo.NO.type);return GraceJSONResult.ok(gridResult);
}@GetMapping("myPrivateList")
public GraceJSONResult myPrivateList(@RequestParam String vlogerId,@RequestParam Integer page,@RequestParam Integer pageSize) {if (page == null) {page = COMMON_START_PAGE;}if (pageSize == null) {pageSize = COMMON_PAGE_SIZE;}PagedGridResult gridResult = vlogService.queryMyVlogList(vlogerId,page,pageSize,YesOrNo.YES.type);return GraceJSONResult.ok(gridResult);
}

這兩個方法的特點:

  • 都使用HTTP GET請求
  • 接收相同的參數:用戶ID、頁碼和每頁大小
  • 對頁碼和每頁大小提供默認值
  • 調用同一個服務方法,但傳入不同的狀態值
  • 返回統一格式的分頁結果

2. 服務層實現業務邏輯

服務層實現了統一的方法來查詢不同狀態的視頻:

@Override
public PagedGridResult queryMyVlogList(String userId, Integer page, Integer pageSize, Integer yesOrNo) {Example example = new Example(Vlog.class);Example.Criteria criteria = example.createCriteria();criteria.andEqualTo("vlogerId", userId);criteria.andEqualTo("isPrivate", yesOrNo);PageHelper.startPage(page, pageSize);List<Vlog> list = vlogMapper.selectByExample(example);return setterPagedGrid(list, page);
}

這個方法的關鍵點:

  • 查詢條件:通過用戶ID和私密狀態篩選視頻
  • 分頁實現:使用PageHelper進行分頁
  • 通用Mapper:使用MyBatis通用Mapper執行查詢
  • 結果封裝:調用setterPagedGrid方法封裝分頁結果

3. 分頁結果封裝

前面代碼片段中有setterPagedGrid方法用于封裝分頁結果:

public PagedGridResult setterPagedGrid(List<?> list, Integer page) {PageInfo<?> pageList = new PageInfo<>(list);PagedGridResult gridResult = new PagedGridResult();gridResult.setRows(list);gridResult.setPage(page);gridResult.setRecords(pageList.getTotal());gridResult.setTotal(pageList.getPages());return gridResult;
}

該方法將原始列表和分頁信息封裝到PagedGridResult對象中,包括:

  • 數據行(rows)
  • 當前頁碼(page)
  • 總記錄數(records)
  • 總頁數(total)

4. 枚舉使用

代碼使用了YesOrNo枚舉來表示視頻狀態:

  • YesOrNo.NO.type:表示公開視頻(值可能為0)
  • YesOrNo.YES.type:表示私密視頻(值可能為1)

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/84400.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/84400.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/84400.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SQL-事務(2025.6.6-2025.6.7學習篇)

1、簡介 事務是一組操作的集合&#xff0c;它是一個不可分割的工作單位&#xff0c;事務會把所有的操作作為一個整體一起向系統提交或撤銷操作請求&#xff0c;即這些操作要么同時成功&#xff0c;要么同時失敗。 默認MySQL的事務是自動提交的&#xff0c;也就是說&#xff0…

《Ansys SIPI仿真技術筆記》 E-desk IBIS模型導入

技術筆記日期&#xff1a;20250611 00 背景和疑問 當在Circuit中準備載入IBIS時&#xff0c;工作界面會彈出如下界面&#xff1a; 那么具體Pin Import和Buffer Import有和區別&#xff1f; 何時該按哪個導入呢&#xff1f; 01 思考和記錄 1. Buffer Import VS Pin Import…

uniapp的請求封裝,如何避免重復提交請求

1、如何封裝uniapp&#xff0c;并且如何使用uniapp的封裝查看&#x1f449;uniapp請求封裝_uni-app-x 請求封裝-CSDN博客??????? 2、聲明一個請求記錄的緩存&#xff0c;代碼如下 // 存儲請求記錄 let requestRecords {}; // 重復請求攔截時間&#xff08;毫秒&#x…

【云原生】阿里云SLS日志自定義字段標簽實現日志告警

把業務日志接入到阿里云SLS日志服務后,我們想自定義字段做為標簽,在做日志告警的時候,可以做為查詢結果使用 自定義標簽 樣例: 一個典型的java log初始化日志格式 [ywgy-app-service:10.10.6.100:30000] 2025-06-10 08:40:53.444 INFO 1[TID: N/A][uId:][sId:][tId:][po…

Linux下制作Nginx綠色免安裝包

linux下安裝nginx比較繁瑣&#xff0c;遇到內網部署環境更是麻煩。根據經驗將nginx打包一個綠色版進行使用。 大體思路&#xff0c;在一臺正常的機器上面制造好安裝包&#xff0c;然后上傳到內網服務器&#xff0c;解壓使用 安裝包制作 安裝依賴 yum install gcc-c pcre per…

腦機新手指南(七):OpenBCI_GUI:從環境搭建到數據可視化(上)

一、OpenBCI_GUI 項目概述 &#xff08;一&#xff09;項目背景與目標 OpenBCI 是一個開源的腦電信號采集硬件平臺&#xff0c;其配套的 OpenBCI_GUI 則是專為該硬件設計的圖形化界面工具。對于研究人員、開發者和學生而言&#xff0c;首次接觸 OpenBCI 設備時&#xff0c;往…

【Zephyr 系列 18】分布式傳感網絡系統設計:從 BLE Mesh 到邊緣網關的數據閉環

??關鍵詞:Zephyr、BLE Mesh、邊緣網關、分布式網絡、狀態同步、組播、數據聚合、遠程控制 ??適合人群:希望實現 BLE Mesh 與網關聯合控制、多設備組網協作、數據閉環采集的開發者 ??預計字數:5500+ 字 ?? 背景與系統目標 在工業、農業、倉儲等場景中,我們常見以下…

【區塊鏈基礎】區塊鏈的 Fork(分叉)深度解析:原理、類型、歷史案例及共識機制的影響

區塊鏈的 Fork(分叉)全面解析:原理、類型、歷史案例及共識機制的影響 在區塊鏈技術的發展過程中,Fork(分叉)現象是不可避免且極具影響力的一個環節。理解區塊鏈分叉的形成原因、具體表現以及共識機制對分叉的作用,對于深入把握區塊鏈技術架構及其治理機制至關重要。 本…

開源 java android app 開發(十一)調試、發布

文章的目的為了記錄使用java 進行android app 開發學習的經歷。本職為嵌入式軟件開發&#xff0c;公司安排開發app&#xff0c;臨時學習&#xff0c;完成app的開發。開發流程和要點有些記憶模糊&#xff0c;趕緊記錄&#xff0c;防止忘記。 相關鏈接&#xff1a; 開源 java an…

數據的聚合

聚合可以實現對文檔數據的統計&#xff0c;分析&#xff0c;運算&#xff0c;聚合常見有三類&#xff08;聚合的值一定不能是text類型的&#xff09;&#xff1a; 桶&#xff08;Bucket&#xff09;聚合&#xff1a;用來對文檔做分組。 度量&#xff08;Metric&#xff09;聚合…

C++默認構造函數被隱式刪除

一、 看cppreference時&#xff0c;發現被隱式刪除的構造函數&#xff0c;查詢做如下記錄&#xff1a; struct F {int& ref; // reference memberconst int c; // const member// F::F() is implicitly defined as deleted };// user declared copy constructor (either …

6.ref創建對象類型的響應式數據

其實ref接收的數據可以是&#xff1a;基本類型、對象類型。若ref接收的是對象類型&#xff0c;內部其實也是調用了reactive函數。 <template><div class"person"><h2>汽車信息&#xff1a;一臺{{ car.brand }}汽車&#xff0c;價值{{ car.price }…

如何設計一個用于大規模生產任務的人工智能AI系統

部署一個SOTA模型&#xff0c;讓它服務數百萬用戶&#xff0c;處理TB級別的數據&#xff0c;并且7x24小時可靠運行是件非常有挑戰性的工作。我們將探討構建一個能夠創建LLM、多模態模型以及各種其他AI產品的大規模AI系統所需的每個開發階段。每個開發階段如何相互關聯&#xff…

國債與企業債:穩健與高收益的債券選擇

債券市場是投資者獲取穩定收益的重要渠道&#xff0c;而國債和企業債是最常見的兩種債券類型。它們雖然都屬于固定收益類產品&#xff0c;但在風險、收益和適用人群上有顯著區別。 1. 概念對比&#xff1a;國家信用 vs. 企業信用 &#xff08;1&#xff09;國債&#xff08;政…

MySQL提升

事務 事務&#xff1a;在多個操作合在一起視為一個整體。要么就不做、要么就做完。 事務應該滿足ACID A : 原子性。不可分割。C : 一致性。追求的目標&#xff0c;在開始到結束沒有發生預定外的情況。I : 隔離性。不同的事務是獨立的。D : 持久性。系統崩潰&#xff0c;數據依然…

MySQL用戶和授權

開放MySQL白名單 可以通過iptables-save命令確認對應客戶端ip是否可以訪問MySQL服務&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…

基礎篇:4. 頁面渲染流程與性能優化

頁面渲染流程與性能優化詳解&#xff08;完整版&#xff09; 一、現代瀏覽器渲染流程&#xff08;詳細說明&#xff09; 1. 構建DOM樹 瀏覽器接收到HTML文檔后&#xff0c;會逐步解析并構建DOM&#xff08;Document Object Model&#xff09;樹。具體過程如下&#xff1a; (…

vue3 vite.config.js 引入bem.scss文件報錯

[sass] Can’t find stylesheet to import. ? 1 │ use “/bem.scss” as *; │ ^^^^^^^^^^^^^^^^^^^^^^ ? src\App.vue 1:1 root stylesheet 分析 我們遇到了一個在Vue3項目中使用Vite時&#xff0c;在vite.config.js中引入bem.scss文件報錯的問題。錯誤信息指出在App.vue…

python打卡第50天

知識點回顧&#xff1a; resnet結構解析CBAM放置位置的思考針對預訓練模型的訓練策略 差異化學習率三階段微調 現在我們思考下&#xff0c;是否可以對于預訓練模型增加模塊來優化其效果&#xff0c;這里我們會遇到一個問題 預訓練模型的結構和權重是固定的&#xff0c;如果修…

MySQL 并發控制和日志

MySQL 是一個廣泛使用的關系數據庫管理系統&#xff0c;在高并發環境中&#xff0c;如何有效地控制并發和管理日志至關重要。本文將詳細介紹 MySQL 的并發控制機制和日志管理策略&#xff0c;以幫助開發人員和數據庫管理員更好地理解和優化數據庫性能。 一、并發控制 并發控制…