MyBatis——在WEB中使用MyBatis(MVC架構模式)

一、在 Web 應用中使用 MyBatis

項目目錄結構

pojo ?

package org.qiu.bank.pojo;/*** 賬戶類,封裝賬戶數據* @author 秋玄* @version 1.0* @package org.qiu.bank.pojo* @date 2022-09-27-20:31* @since 1.0*/
public class Account {private Long id;private String actno;private Double balance;@Overridepublic String toString() {return "Account{" +"id=" + id +", actno='" + actno + '\'' +", balance=" + balance +'}';}public Account(Long id, String actno, Double balance) {this.id = id;this.actno = actno;this.balance = balance;}public Account() {}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getActno() {return actno;}public void setActno(String actno) {this.actno = actno;}public Double getBalance() {return balance;}public void setBalance(Double balance) {this.balance = balance;}
}

dao

package org.qiu.bank.dao;import org.qiu.bank.pojo.Account;/*** @author 秋玄* @version 1.0* @package org.qiu.bank.dao* @date 2022-09-28-10:11* @since 1.0*/
public interface AccountDao {Account select(String actno);int update(Account account);
}
package org.qiu.bank.dao.impl;import org.apache.ibatis.session.SqlSession;
import org.qiu.bank.dao.AccountDao;
import org.qiu.bank.pojo.Account;
import org.qiu.bank.utils.SqlSessionUtil;/*** @author 秋玄* @version 1.0* @package org.qiu.bank.dao.impl* @date 2022-09-28-10:13* @since 1.0*/
public class AccountDaoImpl implements AccountDao {@Overridepublic Account select(String actno) {SqlSession sqlSession = SqlSessionUtil.openSession();Account account = sqlSession.selectOne("account.selectById", actno);sqlSession.close();return account;}@Overridepublic int update(Account account) {SqlSession sqlSession = SqlSessionUtil.openSession();int count = sqlSession.update("account.updateByActno", account);sqlSession.commit();sqlSession.close();return count;}
}

mybatis 的 SQL 映射文件 ?

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="account"><select id="selectById" resultType="org.qiu.bank.pojo.Account">select * from t_act where actno = #{actno};</select><update id="updateByActno">update t_act set balance = #{balance} where actno = #{actno}</update>
</mapper>

service

package org.qiu.bank.service;import org.qiu.bank.exceptions.MoneyNotEnoughException;
import org.qiu.bank.exceptions.TransferException;/*** @author 秋玄* @version 1.0* @package org.qiu.bank.service* @date 2022-09-28-10:06* @since 1.0*/
public interface AccountService {void transfer(String fromActno,String toActno,Double money) throws MoneyNotEnoughException, TransferException;
}
package org.qiu.bank.service.impl;import org.qiu.bank.dao.AccountDao;
import org.qiu.bank.dao.impl.AccountDaoImpl;
import org.qiu.bank.exceptions.MoneyNotEnoughException;
import org.qiu.bank.exceptions.TransferException;
import org.qiu.bank.pojo.Account;
import org.qiu.bank.service.AccountService;/*** @author 秋玄* @version 1.0* @package org.qiu.bank.service.impl* @date 2022-09-28-10:08* @since 1.0*/
public class AccountServiceImpl implements AccountService {AccountDao accountDao = new AccountDaoImpl();@Overridepublic void transfer(String fromActno, String toActno, Double money) throws MoneyNotEnoughException, TransferException {Account fromAct = accountDao.select(fromActno);if (fromAct.getBalance() < money) {// 余額不足throw new MoneyNotEnoughException("對不起,余額不足");}Account toAct = accountDao.select(toActno);fromAct.setBalance(fromAct.getBalance() - money);toAct.setBalance(toAct.getBalance() + money);int count = accountDao.update(fromAct);count += accountDao.update(toAct);if (count != 2) {throw new TransferException("轉賬異常");}}
}

異常處理類 ?

package org.qiu.bank.exceptions;/*** @author 秋玄* @version 1.0* @package org.qiu.bank.exceptions* @date 2022-09-28-10:22* @since 1.0*/
public class MoneyNotEnoughException extends Exception{public MoneyNotEnoughException(){}public MoneyNotEnoughException(String message) {super(message);}
}
package org.qiu.bank.exceptions;/*** @author 秋玄* @version 1.0* @package org.qiu.bank.exceptions* @date 2022-09-28-10:35* @since 1.0*/
public class TransferException extends Exception{public TransferException() {}public TransferException(String message) {super(message);}
}

controller ?

package org.qiu.bank.web;import org.qiu.bank.exceptions.MoneyNotEnoughException;
import org.qiu.bank.exceptions.TransferException;
import org.qiu.bank.service.AccountService;
import org.qiu.bank.service.impl.AccountServiceImpl;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** @author 秋玄* @version 1.0* @package org.qiu.bank.web* @date 2022-09-28-09:59* @since 1.0*/@WebServlet("/transfer")
public class AccountServlet extends HttpServlet {AccountService accountService = new AccountServiceImpl();@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 獲取表單數據String fromActno = request.getParameter("fromActno");String toActno = request.getParameter("toActno");Double money = Double.parseDouble(request.getParameter("money"));try {// 調用 service 的轉賬方法完成轉賬accountService.transfer(fromActno,toActno,money);// 調用 View 展示結果response.sendRedirect(request.getContextPath() + "/success.html");} catch (MoneyNotEnoughException e) {response.sendRedirect(request.getContextPath() + "/err1.html");} catch (TransferException e) {response.sendRedirect(request.getContextPath() + "/err2.html");}}
}

測試:瀏覽器訪問 http://localhost:8080/bank/ ?

存在的問題:

當用戶進行轉賬時,需要更新兩個賬號的余額信息,若兩次更新操作之間,程序出現了異常,此時對于收款賬號的更新操作不會執行,但是轉賬賬號的余額更新操作已經完成,所以會造成數據丟失問題。

解決思路:

首先考慮的肯定是給更新操作添加事務,使得程序對兩個賬號余額的更新操作同時成功或者同時失敗。在 transfer 方法開始執行時開啟事務,直到兩個更新都成功之后,再提交事務

?

存在的問題:

在給兩次更新操作添加事務后發現,上述的問題并未得到解決。原因是 service 和 dao 里使用的 SqlSession 對象不是同一個。

解決思路:

為了保證 service 和 dao 中使用的 SqlSession 對象是同一個,可以將 SqlSession 對象存放到 ThreadLocal 當中

?

改造工具類 ?

package org.qiu.bank.utils;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;/*** MyBatis工具類** @author 秋玄* @version 1.0.0* @since 1.0.0*/
public class SqlSessionUtil {private static SqlSessionFactory sqlSessionFactory;private static ThreadLocal<SqlSession> local = new ThreadLocal<>();/*** 類加載時初始化sqlSessionFactory對象*/static {try {SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));} catch (Exception e) {e.printStackTrace();}}/*** 每調用一次openSession()可獲取一個新的會話,該會話支持自動提交。* @return 新的會話對象*/public static SqlSession openSession() {SqlSession sqlSession = local.get();if (sqlSession == null) {sqlSession = sqlSessionFactory.openSession();local.set(sqlSession);}return sqlSessionFactory.openSession();}/*** 關閉 SqlSession 對象* @param sqlSession*/public static void close(SqlSession sqlSession){if (sqlSession != null) {sqlSession.close();// tomcat 支持線程池,所以關閉 SqlSession 需要將其從當前線程中移除local.remove();}}
}

改造 transfer 方法 ?

@Override
public void transfer(String fromActno, String toActno, Double money) throws MoneyNotEnoughException, TransferException {SqlSession sqlSession = SqlSessionUtil.openSession();Account fromAct = accountDao.select(fromActno);if (fromAct.getBalance() < money) {// 余額不足throw new MoneyNotEnoughException("對不起,余額不足");}Account toAct = accountDao.select(toActno);fromAct.setBalance(fromAct.getBalance() - money);toAct.setBalance(toAct.getBalance() + money);int count = accountDao.update(fromAct);// 模擬異常String s = null;s.toString();count += accountDao.update(toAct);if (count != 2) {throw new TransferException("轉賬異常");}sqlSession.commit();SqlSessionUtil.close(sqlSession);
}

改造 DaoImpl ?

public class AccountDaoImpl implements AccountDao {@Overridepublic Account select(String actno) {SqlSession sqlSession = SqlSessionUtil.openSession();Account account = sqlSession.selectOne("account.selectById", actno);return account;}@Overridepublic int update(Account account) {SqlSession sqlSession = SqlSessionUtil.openSession();int count = sqlSession.update("account.updateByActno", account);return count;}
}

?

二、MyBatis 對象作用域

SqlSessionFactoryBuilder

這個類可以被實例化、使用和丟棄,一旦創建了 SqlSessionFactory,就不再需要它了。

因此 SqlSessionFactoryBuilder 實例的最佳作用域是方法作用域(也就是局部方法變量)。

可以重用 SqlSessionFactoryBuilder 來創建多個 SqlSessionFactory 實例,但最好還是不要一直保留著它,以保證所有的 XML 解析資源可以被釋放給更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被創建就應該在應用的運行期間一直存在,沒有任何理由丟棄它或重新創建另一個實例。

使用 SqlSessionFactory 的最佳實踐是在應用運行期間不要重復創建多次,多次重建 SqlSessionFactory 被視為一種代碼“壞習慣”。

因此 SqlSessionFactory 的最佳作用域是應用作用域

有很多方法可以做到,最簡單的就是使用單例模式或者靜態單例模式。

SqlSession

每個線程都應該有它自己的 SqlSession 實例。

SqlSession 的實例不是線程安全的,因此是不能被共享的,所以它的最佳的作用域是請求或方法作用域

絕對不能將 SqlSession 實例的引用放在一個類的靜態域,甚至一個類的實例變量也不行。

也絕不能將 SqlSession 實例的引用放在任何類型的托管作用域中,比如 Servlet 框架中的 HttpSession。

如果現在正在使用一種 Web 框架,考慮將 SqlSession 放在一個和 HTTP 請求相似的作用域中。

換句話說,每次收到 HTTP 請求,就可以打開一個 SqlSession,返回一個響應后,就關閉它。

這個關閉操作很重要,為了確保每次都能執行關閉操作,應該把這個關閉操作放到 finally 塊中。

下面的示例就是一個確保 SqlSession 關閉的標準模式:

try (SqlSession session = sqlSessionFactory.openSession()) {// 應用邏輯代碼
}

?

一? 葉? 知? 秋,奧? 妙? 玄? 心

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

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

相關文章

Logit Standardization in Knowledge Distillation 知識蒸餾中的logit標準化

摘要 知識蒸餾涉及使用基于共享溫度的softmax函數將軟標簽從教師轉移到學生。然而&#xff0c;教師和學生之間共享溫度的假設意味著他們的logits在logit范圍和方差方面必須精確匹配。這種副作用限制了學生的表現&#xff0c;考慮到他們之間的能力差異&#xff0c;以及教師天生…

TypeScript學習筆記:入門指南

介紹 TypeScript 是一個由微軟開發的開源編程語言&#xff0c;它是 JavaScript 的超集&#xff0c;添加了靜態類型和面向對象的特性&#xff0c;使得 JavaScript 更加適合大型項目的開發。本文將介紹 TypeScript 的基本概念、特點以及其在實際項目中的作用。 特點 靜態類型系…

農業生產中,土壤墑情的監測方法有哪些?

農業是人類的生命之源&#xff0c;而土壤墑情則是農業生產的基礎。我們應該倍加珍惜土地資源&#xff0c;合理利用水資源&#xff0c;努力創造出更加宜人的生長環境。讓每一滴水都能為農作物帶來生機&#xff0c;讓每一寸土地都能孕育豐收。這樣才能實現農業可持續發展的目標&a…

存內計算加速大模型——REM-CiM的RGB-事件融合多模態類比計算內存(CiM)技術

本文為大模型&存內計算融合專題的首篇文章&#xff0c;我們將以這篇名為《REM-CiM: Attentional RGB-Event Fusion Multi-modal Analog CiM for Area/Energy-efficient Edge Object Detection during both Day and Night》為例[1]&#xff0c;探討其在文中提到的多模態大模…

python dict賦值時有逗號自動變成元組

webpack 查找n.m時用的加載器是頁面上調用的&#xff0c;因為賦值了s等于加載器 s(‘8536’) s.m[‘8536’] headers[Cookie] f_m_h5_tk{cookie_list[0]}; _m_h5_tk_enc{cookie_list[1]}{accept: */*, accept-language: zh-CN,zh;q0.9, cache-control: no-cache, pragma: no-…

護眼臺燈和普通臺燈差別很大嗎?專業護眼燈品牌有哪些?

隨著科技的不斷演進&#xff0c;臺燈的設計也日益脫胎換骨&#xff0c;從曾經的笨重造型轉變為如今輕盈雅致的外觀。它們的功能同樣經歷了多樣化的革新&#xff0c;變得更加人性化和便捷。作為學習、閱讀和辦公環境中不可或缺的照明工具&#xff0c;臺燈所提供的光線舒適度至關…

小紅書java社招一二三面面經

面試前&#xff0c;先找面經哥&#xff0c;點擊此處查看更多面經 面試公司&#xff1a;小紅書 面試職位&#xff1a;后端開發工程師 整體評價&#xff1a;已拿offer &#x1f4dd;面試題&#xff1a; 【一面】 講一下MySQL優化 1、索引優化的細節 2、前綴索引原理 3、MySQ…

LazyDiffusion:革新交互式圖像編輯的擴散模型

Adobe Research和特拉維夫大學的研究人員聯合開發了一種名為LazyDiffusion的新型擴散變換器&#xff0c;它能夠高效地生成部分圖像更新&#xff0c;特別適用于交互式圖像編輯。該模型通過創新的編碼器-解碼器架構&#xff0c;顯著提升了圖像編輯的效率&#xff0c;同時保持了與…

QML 本地存儲(Setting,sqlite)

Qt hello - 專注于Qt的技術分享平臺 QML 原生的儲存方有兩種&#xff1a; 1&#xff0c;Settings 跟QWidget 中的QSettings 一樣&#xff0c;可以簡單的存儲一些配置。 2&#xff0c;Sqlite sqlite數據庫。可以存儲一些復雜的數據。 一&#xff0c;Settings 我們以一個按鈕的位…

鴻蒙DevEco Studio 4.1 Release-模擬器啟動方式錯誤

軟件版本&#xff1a;DevEco Studio 4.1 Release 報錯提示&#xff1a; 沒有權限查看處理指導 Size on Disk 顯示1.0MB 嘗試方案&#xff08;統統無效&#xff09;&#xff1a; 1、“windows虛擬機監控程序平臺”、"虛擬機平臺"已開啟 啟用CPU虛擬化 2、C…

DIY可視化軟件環境準備

DIY官網可視化工具做好的可視化拖拽開發工具無須編程、零代碼基礎、所見即所得設計工具支持輕松在線可視化導出微信小程序、支付寶小程序、頭條小程序、H5、WebApp、UNIAPP等源碼 支持組件庫,高顏值,卡片,列表,輪播圖,導航欄,按鈕,標簽,表單,單選,復選,下拉選擇,多層選擇,級聯選…

【大華可見光攝像頭】ffmpeg獲取視頻流并下載mp4 報錯‘subtype‘ 不是內部或外部命令,也不是可運行的程序

我現在要通過ffmpeg獲取大華攝像頭視頻流并下載成mp4&#xff0c;但我在cmd窗口運行下面命令的時候&#xff0c;發現報錯&#xff1a; D:\Java\ffmpeg\ffmpeg-master-latest-win64-gpl\bin\ffmpeg.exe -y -i rtsp://admin:123xxx.xxx.xxx.xxx/cam/realmonitor?channel1&s…

springboot 連接hive的坑

本地運行時倒是沒啥問題&#xff0c;一上線啟動接連報錯。網上各種找答案&#xff0c;本質上還是依賴沖突報錯&#xff0c;不知道使用哪個具體類 Caused by: java.lang.NoSuchMethodError: javax.servlet.ServletContext.getVirtualServerName()Ljava/lang/String;The followi…

代碼隨想錄-算法訓練營day36【貪心算法06:單調遞增的數字、監控二叉樹、總結】

代碼隨想錄-035期-算法訓練營【博客筆記匯總表】-CSDN博客 第八章 貪心算法 part06● 738.單調遞增的數字 ● 968.監控二叉樹 ● 總結 詳細布置 738.單調遞增的數字 https://programmercarl.com/0738.%E5%8D%95%E8%B0%83%E9%80%92%E5%A2%9E%E7%9A%84%E6%95%B0%E5%AD%97.html…

Qt Tab鍵切換焦點順序:setTabOrder()

使用這個方法setTabOrder()&#xff0c;設置使得焦點的順序從前到后依次是&#xff1a; ui->lineEdit》 ui->lineEdit_2》ui->lineEdit_3 》ui->lineEdit_4 焦點先在ui->lineEdit上&#xff0c;當按下Tab鍵時&#xff0c;焦點跑到ui->lineEdit_2上。。。按…

同步假設 - 同步方法對實時控制系統的抽象

同步假設是如SCADE、Lustre等同步語言所基于的基礎。這些假設是對實時系統環境的一種抽象。對本文討論涉及到的內容&#xff0c;可進一步參考《Representation and Analysis of Reactive Behaviors: A Synchronous Approach》(SyncCharts, 1996)。 同步方法采用了一種理想化的抽…

通過顏色學習css

文章目錄 1.生成html2.添加css鏈接3.將h1標簽text-align元素4.添加div標簽4.1、為類marker添加元素4.2、添加兩個新的div標簽4.3、修改div標簽的類型并修改css元素4.4、為類container添加元素4.5、以數字形式添加顏色4.5、container添加padding屬性4.6、組合css中的顏色屬性4.7…

【Matlab】Matlab之美,抓緊來膜拜大神的創星之作(附2024Matlab教程+代碼)

軟件介紹 MATLAB是一款商業數學軟件&#xff0c;用于算法開發、數據可視化、數據分析以及數值計算的高級技術計算語言和交互式環境&#xff0c;主要包括MATLAB和Simulink兩大部分&#xff0c;可以進行矩陣運算、繪制函數和數據、實現算法、創建用戶界面、連接其他編程語言的程序…

自回歸模型的優缺點及改進方向

在學術界和人工智能產業中&#xff0c;關于自回歸模型的演進與應用一直是一個引發深入討論和多方觀點交鋒的熱門議題。尤其是Yann LeCun&#xff0c;這位享譽全球的AI領域學者、圖靈獎的獲得者&#xff0c;以及被譽為人工智能領域的三大巨擘之一&#xff0c;他對于自回歸模型持…

Rust:函數封裝,struct 還是 mod?

在Rust中&#xff0c;是否將一組功能相關的靜態函數組織到一個結構體&#xff08;struct&#xff09;中&#xff0c;或者直接利用模塊&#xff08;mod&#xff09;機制來組織&#xff0c;主要取決于你的具體需求和設計考慮。以下是一些指導原則&#xff1a; 使用結構體封裝靜態…