ThreadLocal功能实现
模拟ThreadLocal功能实现
当前线程任意方法内操作连接对象
一个栈对应一个线程 , 一个方法调用另一个方法都是在一个线程内 , 只有执行了线程的start方法才会创建一个线程
定义一个Map集合 , key是当前线程(Thread.currentThread) , value是要绑定的数据(Connection对象)
- 以后获取,绑定,移除数据操作的key就是当前线程 , 当前线程是动态的 , 张三发起请求当前线程是t1线程 , 李四发送请求,当前线程是t2线程

ThreadLocal本质
自定义ThreadLocal类 , 将所有需要和当前线程绑定的数据要放到这个容器当中
public class MyThreadLocal<T> {private Map<Thread, T> map = new HashMap<>();//向ThreadLocal中当前线程绑定数据public void set(T obj){map.put(Thread.currentThread(), obj);}//从ThreadLocal中获取当前线程对应的数据public T get(){return map.get(Thread.currentThread());}//移除ThreadLocal当中当前线程对应的数据public void remove(){map.remove(Thread.currentThread());}
}
DBUtil 工具类获取当前线程绑定的Connection对象
public class DBUtil {// 静态变量特点:类加载时执行,并且只执行一次// 全局的大Map集合private static MyThreadLocal<Connection> local = new MyThreadLocal<>();//每一次都调用这个方法来获取Connection对象public static Connection getConnection(){//获取当前线程对应的Connection对象Connection connection = local.get();if (connection == null) {// 第一次调用:getConnection()方法的时候,connection一定是空的。空的就new一次。connection = new Connection();// 将new的Connection对象绑定到大Map集合中。local.set(connection);}return connection;}
}
//自定义Connection对象
public class Connection {
}
测试从Map集合中获取当前线程绑定的Connection对象
public class Test {public static void main(String[] args) {// 调用serviceUserService userService = new UserService();userService.save();}
}
//UserService
public class UserService {private UserDao userDao = new UserDao();public void save(){//这里获取的就是当前线程绑定的Connection对象Connection connection = DBUtil.getConnection();System.out.println(connection);userDao.insert();}
}
//UserDao
public class UserDao {public void insert(){//这里获取的就是当前线程绑定的Connection对象Connection connection = DBUtil.getConnection();System.out.println(connection);System.out.println("User DAO insert");}
}
使用java.lang.ThreadLocal类优化事务
java.lang.ThreadLocal类中里面有个Map集合 , 这个集合中的key是当前线程 , value是我们想要存储的对象(如存储Connection对象)
- 这个Map集合中的每个线程都有自己的Connection对象 , 需要的时候根据当前正在执行的线程获取对应的Connection对象
- 每次获取的Connection对象是从ThreadLocal中的Map集合中拿的 , 第一次获取的时候需要我们手动创建并添加到Map集合中
Connection对象关闭之后,要从大Map集合中移除
- Tomcat服务器是支持线程池的 , 线程池中有很多提前创建好的线程对象如t1 , t2 , t3 ,它们存在重复使用的问题
- 就是说一个人用过了t1线程,t1线程还有可能被其他用户使用 , 这时如果你不关闭 , 别人拿到的就是你已经关闭的Connection对象
ThreadLocal的常用方法
| 方法名 | 功能 |
|---|---|
| public Object get() | 获取Map集合中当前线程对应的对象 (如Connection对象) |
| public void set(Object obj) | 把创建的对象存入Map集合中(如Connection对象) |
| public void remove() | 删除Map集合中当前线程对应的对象(如Connection对象) |
使用ThreadLocal类优化事务
DBUtil⼯具类:将Connection对象存放到ThreadLocal里面的Map集合中, 保证service和dao中使⽤的Connection对象是同⼀个
public class DBUtil {private static ResourceBundle bundle = ResourceBundle.getBundle("resources/jdbc");private static String driver = bundle.getString("driver");private static String url = bundle.getString("url");private static String user = bundle.getString("user");private static String password = bundle.getString("password");// 工具类中的方法都是静态的,为了防止创建对象,故将构造方法私有化private DBUtil(){}// DBUtil类加载时注册驱动static {try {Class.forName(driver);} catch (ClassNotFoundException e) {e.printStackTrace();}}// 这个Map集合是全局的,在服务器中只有一个private static ThreadLocal<Connection> local = new ThreadLocal<>();//这里没有使用数据库连接池,直接创建连接对象public static Connection getConnection() throws SQLException {//获取当前线程对应的Connection对象,如果没有就创建并把它存入ThreadLocal类中的Map集合中Connection conn = local.get();if (conn == null) {conn = DriverManager.getConnection(url, user, password);local.set(conn);}return conn;}/*** 关闭资源* @param conn 连接对象* @param stmt 数据库操作对象* @param rs 结果集对象*/public static void close(Connection conn, Statement stmt, ResultSet rs){if (rs != null) {try {rs.close();} catch (SQLException e) {throw new RuntimeException(e);}}if (stmt != null) {try {stmt.close();} catch (SQLException e) {throw new RuntimeException(e);}}if (conn != null) {try {// 根本原因是:Tomcat服务器是支持线程池的,也就是说一个人用过了t1线程,t1线程还有可能被其他用户使用conn.close();local.remove();} catch (SQLException e) {throw new RuntimeException(e);}}}
}
不再接收service传过来的Connection对象 , 直接在AccountDao中获取当前线程对应的一个Connection对象
public class AccountDao {//插入账户信息public int insert(Account act) {PreparedStatement ps = null;int count = 0;try {//这里获取的Connection对象是从ThreadLocal中的Map集合中拿的(除了第一次是自己创建的)Connection conn = DBUtil.getConnection();//执行sql....} catch (SQLException e) {throw new RuntimeException(e);} finally {DBUtil.close(null, ps, null);}return count;}//根据主键删除账户public int deleteById(Long id){//执行sql...}//更新账户public int update(Account act) {//执行sql...}//根据账号查询账户public Account selectByActno(String actno){//执行sql...}//获取所有的账户public List<Account> selectAll() {//执行sql...}
}
相关文章:
ThreadLocal功能实现
模拟ThreadLocal功能实现 当前线程任意方法内操作连接对象 一个栈对应一个线程 , 一个方法调用另一个方法都是在一个线程内 , 只有执行了线程的start方法才会创建一个线程 定义一个Map集合 , key是当前线程(Thread.currentThread) , value是要绑定的数据(Connection对象) 以…...
Linux编辑器-vim使用
文章目录 前言一、vim编辑器1、vim的基本概念2、vim的基本操作2.1 命令模式切换至插入模式2.2 插入模式切换至命令模式2.3 命令模式切换至底行模式 3、vim命令模式命令集3.1 移动光标3.2 删除文字3.3 复制与粘贴3.4 替换3.5 撤销上一次操作3.6 更改3.7 跳至指定的行 4、vim末行…...
自助式数据分析平台:JVS智能BI功能介绍(二)数据集管理
数据集是JVS-智能BI中承载数据、使用数据、管理数据的基础,同样也是构建数据分析的基础。可以通俗地将其理解为数据库中的普通的表,他来源于智能的ETL数据加工工具,可以将数据集进行分析图表、统计报表、数字大屏、数据服务等制作。 在整体的…...
《5G技术引领教育信息化新革命》
5G技术引领教育信息化新革命 随着5G技术的快速发展,教育领域也迎来了全新的信息化时代。5G技术为教育行业提供了更高速、更稳定、更智能的网络连接,使得教育信息化不再局限于传统的课堂教学,而是延伸到了线上、线下的全时空教育。本文将详细介…...
cmake学习过程记录
目录 基础命令学习配置opencvcmake (Windows版本) 基础命令学习 //设置最低版本号 cmake_minimum_required(VERSION 3.5)//设置项目名称 project (hello_headers)//递归遍历文件夹src中的cpp文件放到变量SOURCES中 file(GLOB_RECURSE SOURCES src/*.cpp)//设置目标exe名称…...
Vue3、Vite使用 html2canvas 把Html生成canvas转成图片并保存,以及填坑记录
这两天接到新需求就是生成海报分享,生成的格式虽然是一样的但是自己一点点画显然是不符合我摸鱼人的性格,就找到了html2canvas插件,开始动工。 安装 npm install html2canvas --save文档 options 的参数都在里面按照自己需求使用 https://a…...
centos yum源配置(CentOS7 原生 yum 源修改为阿里 yum 源)
文章目录 centos yum源配置centos搭建内网yum源内网centos的yum软件源配置CentOS7 原生 yum 源修改为阿里 yum 源 centos yum源配置 centos搭建内网yum源 您好,在CentOS系统上搭建本地内网YUM仓库的方法如下: 安装httpd和createrepo工具 yum install httpd createrepo -y创…...
linux————ansible
一、认识自动化运维 自动化运维: 将日常IT运维中大量的重复性工作,小到简单的日常检查、配置变更和软件安装,大到整个变更流程的组织调度,由过去的手工执行转为自动化操作,从而减少乃至消除运维中的延迟,实现“零延时”…...
初识Java 8-1 接口和抽象类
目录 抽象类和抽象方法 接口定义 默认方法 多重继承 接口中的静态方法 作为接口的Instrument 本笔记参考自: 《On Java 中文版》 接口和抽象类提供了一种更加结构化的方式分离接口和实现。 抽象类和抽象方法 抽象类,其介于普通类和接口之间。在构…...
微信小程序音频后台播放功能
微信小程序在手机息屏后依旧能播放音频,需要使用 wx.getBackgroundAudioManager() 方法创建后台音乐播放器,并将音乐播放任务交给这个后台播放器。 具体实现步骤如下: 小程序页面中,使用 wx.getBackgroundAudioManager() 方法创…...
NotePad——xml格式化插件xml tools在线安装+离线安装
在使用NotePad时,在某些情形下,需要格式化Xml格式内容,可以使用Xml Tools插件。 一、在线安装 1. 打开Notepad 软件 2. 选择插件,选择“插件管理” 3. 搜索 XML Tools,找到该插件后,勾选该文件ÿ…...
图书管理系统 数据结构先导课暨C语言大作业复习 | JorbanS
问题描述 读取给定的图书文件book.txt中的信息(book.txt中部分图书信息如下图所示),完成一个图书信息管理系统,该系统的各个功能模块要求利用菜单选项进行选择。 系统功能要求 图书浏览 读取book.txt中的文件信息并依次输出所…...
python 爬虫的开发环境配置
1、新建一个python项目 2、在控制台中分别安装下面三个包 pip install requests pip install beautifulsoup4 pip install selenium/ 如果安装时报以下错误: raise ReadTimeoutError(self._pool, None, "Read timed out.") pip._vendor.urllib3.exceptio…...
技术架构图是什么?和业务架构图的区别是什么?
技术架构图是什么? 技术架构图是一种图形化工具,用于呈现软件、系统或应用程序的技术层面设计和结构。它展示了系统的各种技术组件、模块、服务以及它们之间的关系和交互方式。技术架构图关注系统内部的技术实现细节,以及各个技术组件之…...
数据增强
一、数据增强 当你训练一个机器学习模型时,你实际做工作的是调参,以便将特定的输入(一副图像)映像到输出(标签)。我们优化的目标是使模型的损失最小化, 以正确的方式调节优化参数即可实现这一目…...
【Unity】2D 对话模块的实现
对话模块主要参考 【Unity教程】剧情对话系统 实现。 在这次模块的构建将基于 unity ui 组件 和 C#代码实现一个从excel 文件中按照相应规则读取数据并展示的逻辑。这套代码不仅能实现正常的对话,也实现了对话中可以通过选择不同选项达到不同效果的分支对话功能。 …...
laravel安装初步使用学习 composer安装
一、什么是laravel框架 Laravel框架可以开发各种不同类型的项目,内容管理系统(Content Management System,CMS)是一种比较典型的项目,常见的网站类型(如门户、新闻、博客、文章等)都可以利用CM…...
【VS插件】VS code上的Remote - SSH
【VS插件】VS code上的Remote - SSH 目录 【VS插件】VS code上的Remote - SSH获得Linux服务器或者Linux系统的IP地址下载插件远程登录注意如果Linux虚拟机系统无法连接成功可能是没有开启ssh服务优势 作者:爱写代码的刚子 时间:2023.9.12 前言࿱…...
TensorFlow 02(张量)
一、张量 张量Tensor 张量是一个多维数组。与NumPy ndarray对象类似,tf.Tensor对象也具有数据类型和形状。如下图所示: 此外,tf.Tensors可以保留在GPU中。TensorFlow提供了丰富的操作库 (tf.add,tf.matmul,tf.linalg.inv等),它们…...
513. 找树左下角的值
代码链接: 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 思路: 万金油层次遍历,保存每一层的第一个元素返回就行了 我的代码: /*** Definition for a binary tree node.* struct TreeNode {* …...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
