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.mzph.cn/web/10163.shtml

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

相关文章

Logit Standardization in Knowledge Distillation 知识蒸馏中的logit标准化

摘要 知识蒸馏涉及使用基于共享温度的softmax函数将软标签从教师转移到学生。然而&#xff0c;教师和学生之间共享温度的假设意味着他们的logits在logit范围和方差方面必须精确匹配。这种副作用限制了学生的表现&#xff0c;考虑到他们之间的能力差异&#xff0c;以及教师天生…

农业生产中,土壤墒情的监测方法有哪些?

农业是人类的生命之源&#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;探讨其在文中提到的多模态大模…

护眼台灯和普通台灯差别很大吗?专业护眼灯品牌有哪些?

随着科技的不断演进&#xff0c;台灯的设计也日益脱胎换骨&#xff0c;从曾经的笨重造型转变为如今轻盈雅致的外观。它们的功能同样经历了多样化的革新&#xff0c;变得更加人性化和便捷。作为学习、阅读和办公环境中不可或缺的照明工具&#xff0c;台灯所提供的光线舒适度至关…

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…

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上。。。按…

通过颜色学习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;他对于自回归模型持…

华为与达梦数据签署全面合作协议

4月26日&#xff0c;武汉达梦数据库股份有限公司&#xff08;简称“达梦数据”&#xff09;与华为技术有限公司&#xff08;简称“华为”&#xff09;在达梦数据武汉总部签署全面合作协议。 达梦数据总经理皮宇、华为湖北政企业务总经理吕晓龙出席并见证签约&#xff1b;华为湖…

geotrust dv通配符证书800

Geotrust是成立时间较久的正规CA认证机构&#xff0c;在过去的几十年间颁发了无数的SSL证书&#xff0c;这些SSL证书被各个开发者使用&#xff0c;受到大多数浏览器的信任。而Geotrust旗下的DV通配符证书因其广泛的应用范围受到了用户的青睐。今天就随SSL盾小编了解Geotrust旗下…

Ardupilot Rpanion iperf网络性能测试

Ardupilot Rpanion iperf网络性能测试 1. 源由2. 分析3. 安装4. 测试4.1 第一次测试4.1.1 iperf测试参数A4.1.1.1 测试链路14.1.1.2 测试链路24.1.1.3 测试链路3 4.1.2 iperf测试参数B - 测试链路34.1.2.1 测试数据4.1.2.2 数据简单分析4.1.2.3 数据深入分析4.1.2.4 模拟测试网…

【初始类和对象】(实例讲解!超级详细!)

【初始类和对象】 前言1. 面向对象的初步认知1.1什么是面向对象1.2 面向对象与面向过程 2. 类的定义和使用2.1 简单认识类2.2 类的定义格式 3. 知识的代码举例讲解3.1 创建类、实例化类3.2 构造方法初始化类、this 3. 总结 前言 由于类和对象是我们在学习过程中需要接受的概念…

AI赋能未来教育:中国教学科研新蓝图

设“人啊 前言 回顾过去&#xff0c;传统的教育模式以知识灌输和应试为主&#xff0c;虽培养出大量人才&#xff0c;但也存在着学生创新能力不足、实践经验缺乏等问题。随着时代的进步和科技的发展&#xff0c;传统教育模式已难以满足当今社会对人才的需求。然而&#xff0c;当…

中国现代十大杰出人物颜廷利:好的司机不如好的同机

找好‘同机’者, 要比找好‘司机’者, 原因就是, ‘司机’虽好, 但不是‘同路人’, 再多努力的攀附都是徒劳, 至于‘同机’者, 即便是对方在自己的眼里心中都一无是处, 只不过, 他/她才是您旅途之中, 真真正正、风雨同舟的人…(升命学说) 21世纪东方哲学家思想家、科学家、当代…

TODESK远控快捷键在哪里

在当今高度数字化的世界中&#xff0c;远程工作和协作已经成为日常生活和业务运营的重要组成部分。Todesk作为一款出色的远程协作软件&#xff0c;为用户提供了诸多功能&#xff0c;以确保流畅、高效的远程连接体验。其中&#xff0c;快捷键功能极大地提升了用户的操作便捷性。…