首页
关于本站
友情链接
全站统计
更多
访客留言
精美壁纸
推荐
小鹿云计算
Search
1
疫情实时数据
10,907 阅读
2
关于 BootLoader
10,347 阅读
3
Linux环境下简单搭建Minecraft服务器(java版)
9,181 阅读
4
申请了萌ICP备案
9,167 阅读
5
中华人民共和国网络安全法
6,489 阅读
博客
学习笔记
技术
每日一拍
登录
Search
标签搜索
golang
源码
jsdelivr
server
火烧云
萌ICP备案
MyBatis
Hibernate
博客更名
风景
root
BootLoader
疫情
实时
NestJS
Express
雪景
山景
操场
ddos
绎泽
累计撰写
42
篇文章
累计收到
88
条评论
今日撰写
0
篇文章
首页
栏目
博客
学习笔记
技术
每日一拍
页面
关于本站
友情链接
全站统计
访客留言
精美壁纸
推荐
小鹿云计算
04:57:42 AM
用户登录
登录
搜索到
42
篇与
绎泽
的结果
2022-05-17
为什么数据库连接池不采用 IO 多路复用?
今天我们聊一个不常见的 Java 面试题:为什么数据库连接池不采用 IO 多路复用?这是一个非常好的问题。IO多路复用被视为是非常好的性能助力器。但是一般我们在使用 DB 时,还是经常性采用c3p0`tomcat connection pool等技术来与 DB 连接,哪怕整个程序已经变成以Netty`为核心。这到底是为什么?首先纠正一个常见的误解。IO多路复用听上去好像是多个数据可以共享一个IO(socket连接),实际上并非如此。「IO多路复用不是指多个服务共享一个连接,而仅仅是指多个连接的管理可以在同一进程」。在网络服务中,IO多路复用起的作用是「一次性把多个连接的事件通知业务代码处理」。至于这些事件的处理方式,到底是业务代码循环着处理、丢到队列里,还是交给线程池处理,由业务代码决定。对于使用DB的程序来讲,不管使用多路复用,还是连接池,都要维护一组网络连接,支持并发的查询。为什么并发查询一定要使用多个连接才能完成呢?因为DB一般是使用连接作为Session管理的基本单元。在一个连接中,SQL语句的执行必须是串行、同步的。这是由于对于每一个Session,DB都要维护一组状态来支持查询,比如事务隔离级别,当前Session的变量等。只有单Session内串行执行,才能维护查询的正确性(试想一下一组sql在不断的增减变量,然后这组sql乱序执行会发生什么)。维护这些状态需要耗费内存,同时也会消耗CPU和磁盘IO。这样,限制对DB的连接数,就是在限制对DB资源的消耗。因此,对DB来说,关键是要限制连接的数目。这个要求无论是DB连接池还是NIO的连接管理都能做到。这样问题就绕回来了,为什么DB连接不能放到IO多路复用里一并执行吗?为啥大家都用连接池?答案是,可以用IO多路复用——但是「使用JDBC不行」。JDBC是一个出现了近20年的标准,它的设计核心是BIO(因为199X年时还没有别的IO可以用):调用者在通过JDBC时执行比如query这样的API,在没有执行完成之前,整个调用线程被卡住。而类似于Mysql Connector/J这样的driver完备的实现了这套语义。当然如果DB Client的协议的连接处理和解析稍微改一下:将IO模式调整为Non-Blocking,这样就可以挂到IO多路复用的内核上(select、epoll、kqueue……)在Non-Blocking实现的基础之上实现数据库协议的编码和解析就可以实现用IO多路复用来访问DB。实际上很多其他语言/框架里都是这么干的。比如 Nodejs,see https://github.com/sidorares/node-mysql2;或者 Vert.X 的 db 客户端https://github.com/mauricio/postgresql-async,不要在意这个名字,它实际上同时支持mysql和postgres)。只不过对于IO多路复用,数据库官方似乎都没做这种支持——他们只支持JDBC、ODBC等等这些标准协议。当然如果DB Client的协议的连接处理和解析稍微改一下:将IO模式调整为Non-Blocking,这样就可以挂到IO多路复用的内核上(select、epoll、kqueue……)在Non-Blocking实现的基础之上实现数据库协议的编码和解析就可以实现用IO多路复用来访问DB。实际上很多其他语言/框架里都是这么干的。比如 Nodejs,see https://github.com/sidorares/node-mysql2;或者 Vert.X 的 db 客户端https://github.com/mauricio/postgresql-async,不要在意这个名字,它实际上同时支持mysql和postgres)。只不过对于IO多路复用,数据库官方似乎都没做这种支持——他们只支持JDBC、ODBC等等这些标准协议。那么为什么基于 IO 多路复用的实现不能成为默认的,官方的,而要成为偏门呢?对于数据库开发者来说。这种用法在整体的用户里占有量非常小,所以也许不值当的花大力气。只需要把协议写清楚(比如https://dev.mysql.com/doc/internals/en/client-server-protocol.html),就可以做实现。那么社区的有兴趣的人自然就可以去做。另外一个原因是体系的支持。简单来讲,如果没有一个大的 Reactive 的运行环境,IO 多路复用的使用会非常受限。IO 多路复用之所以能成立,是需要「整个程序要有一个IO多路复用的驱动代码」——就是 select 那句调用——等待事件来临,一个 blocking 的 API。整个程序必须以这个驱动代码为核心。这样就对整个代码的结构产生重大的影响。这种影响是没法用简单的接口抽象的。Java Web 容器之所以可以使用 NIO 是因为 NIO 可以被封装到容器内部。Web 容器对外暴露的还是传统的多线程形式的Java EE接口。如果 DB 和 Web 容器同时使用 NIO,那么调用的DB连接库与必须与容器有一个约定描述「DB的连接管理如何接入Web容器的NIO的驱动代码」。在 Java 这个大环境下,不同人,不同的容器写的代码不同;又或者,不使用任何常见的容器,而是自己用 NIO 去封装一个。这样是无法形成代码上的约定的。那么多个独立的组件就不能很好的共享 NIO 的驱动代码。上面这个用法假设整个程序应该共享一个 NIO 驱动代码。那么 Web 和 DB 可不可以各用各的呢?也是可以的,但是为了保证这两个 NIO 驱动代码不会相互 block,最好要分开两个线程。这样一来就会打破一般 Web 服务一个请求处理用一个线程的一般做法,会让程序边的更复杂——你的业务代码和DB查询之间必须做跨线程数据交换。相反,连接池的实现就相对独立的多,也简单的多。外界只要配好 DB URL,用户名密码和连接池的容量参数,就可以做到自行管理连接。而Nodejs和Vert.X是完全不同的。他们本质就是Reactive的。他们的NIO的驱动方式是其运行时的基础——所有要在这个基础上开发的代码都必须遵守同样的NIO+异步开发规范,使用同一个NIO的驱动。这样DB与NIO的协作就不成问题了。最后,「有大量场景是需要BIO的DB查询支持的」。批处理数据分析代码都是这样的场景。这样的程序写成NIO就会得不偿失——代码不容易懂,也没有任何效率上的优势。类似于Nodejs这样的运行时在此场景下,反而要利用async或等价的语法来让代码看起来是同步的,这样才容易写。总结一下。DB 访问一般采用连接池这种现象是生态造成的。历史上的 BIO + 连接池的做法经过多年的发展,已经解决了主要的问题。在 Java 的大环境下,这个方案是非常靠谱的,成熟的。而基于 IO 多路复用的方式尽管在性能上可能有优势,但是其对整个程序的代码结构要求过多,过于复杂。当然,如果有特定的需要,希望使用 IO 多路复用管理 DB 连接,是完全可行的。
2022年05月17日
323 阅读
0 评论
6 点赞
2022-05-17
jsdelivr挂了
最近 jsdelivr 被墙了,导致博客静态资跟着挂了千辛万苦把博客需要的静态资源下载到本地,但是博客访问还是很慢就先这样吧,没啥办法了…(๑╯ﻌ╰๑)=3
2022年05月17日
453 阅读
2 评论
3 点赞
2022-04-19
简单使用ESbuild打包工具
ESbuild打包器基于Golang开发,优点在于可多线程打包,直接编译成机器码,ESbuild提供的api可在JavaScript和golang使用,连Vite在很多场景都依赖了ESbuild打包,支持TypeScript和jsx安装npm install esbuild或者yarn add esbuild打包.node_modules.binesbuild app.jsx --outfile=build/index.js --bundle或者package.json"build": "esbuild app.jsx --outfile=build/index.js --bundle"npm run build例子(app.jsx)import React from 'react' import ReactDOM from 'react-dom' const App = () => { return ( <div> <h1>Hallo, Esbuild!</h1> </div> ) } ReactDOM.render( <App />, document.getElementById("app") )index.html<div id="app"></div> <script src="./build/index.js"></script>我本地打包只花64ms就打包好了
2022年04月19日
578 阅读
0 评论
2 点赞
2022-04-19
browserslist的简单配置
browserslist是查询浏览器列表的工具,browserslisp的配置可写在package.json中,也可以单独写在.browserslistrc配置⽂件中browserslist的配置文件会被Autoprefixer,Babel,postcss-preset-env,eslint-plugin-compat,stylelint-no-unsupported-browser-features,postcss-normalize,obsolete-webpack-plugin工具读取,并且对配置的目标浏览器做适配工作npx browserslist可查看根据条件输出的浏览器列表查看全球用户份额大于0.2%的浏览器npx browserslist "> 0.2%"查询Chrome最新1个版本npx browserslist "last 1 Chrome versions"查看browserslist的默认配置npx browserslist "defaults"browserslist的默认配置为> 0.5% and last 2 versions adn Firefox ESR and not deadnot dead的意思是不输出官方不再维护的浏览器(例如ie10),dead是不维护,not是不输出and就是和,or是或者browserslist的配置package.json(browserslist官方推荐用这个)browserslist": [ '> 0.2%', 'last 1 Chrome versions' 'not dead' ]或者写成"browserslist": [ '> 0.2% and last 1 Chrome versions and not dead', ].browserslistrc> 0.2% and last 1 Chrome versions and not deadbrowserslist数据的优先级:当前项目的package.json的browserslist,当前项目的.browserslistrc,BROWSERSLIST环境变量,browserslist的defaults另外还可以设置development(开发环境),production(生产环境的配置),例如:"browserslist": [ 'development':[ 'last 1 Chrome versions', 'last 1 firefox versions', 'last 1 safari versions', '> 5%', ], 'production': [ 'not dead' ] ]
2022年04月19日
330 阅读
1 评论
4 点赞
2022-04-19
Flutter框架学习笔记
Flutter是谷歌开源的跨平台UI框架,可以快速在iOS和Android上构建高质量的原生用户界面,可在Windows,Linux,Android,Web,iOS,Mac等6大平台上开发应用闲鱼和Now直播,美团,快手都使用了Flutter获取Flutterhttps://storage.flutter-io.cn/flutter_infra_release/releases/stable/windows/flutter_windows_2.10.3-stable.zip添加path环境变量由于Flutter库是在google那,因此需要设置第三方可信镜像库设置PUB_HOSTED_URL和FLUTTER_STORAGE_BASE_URL环境变量PUB_HOSTED_URL设置为https://pub.flutter-io.cnFLUTTER_STORAGE_BASE_URL设置为https://storage.flutter-io.cn(flutter-io.cn所提供的镜像由中国的Flutter开发者社区提供和维护)其他可信第三方镜像库:腾讯云镜像PUB_HOSTED_URL(https://mirrors.cloud.tencent.com/dart-pub)FLUTTER_STORAGE_BASE_URL(https://mirrors.cloud.tencent.com/flutter)清华大学镜像PUB_HOSTED_URL(https://mirrors.tuna.tsinghua.edu.cn/dart-pub)FLUTTER_STORAGE_BASE_URL(https://mirrors.tuna.tsinghua.edu.cn/flutter)添加Flutter环境变量path,解压路径flutterbin执行where.exe flutter dart,如果有反应,说明path环境配置完成(如果要开发安卓的话,需要安装jdk,Android Studio,Android Jdk,可执行flutter doctor检查依赖(如果是X表示没依赖,需要安装))这里用Visual Studio Code的Flutter插件创建第一个demo(项目名必须全小写,可用_下划线)flutter create flutterdemo启动项目(编译执行)flutter runDart是静态类型语言,它会在定义时绑定数据类型(var)Dart允许一个类中有多个构造函数,在new初始化时,可选择类的某个构造函数Dart库管理(pub.dev),在pubspec.yaml添加库实质上Dart和JavaScript很相似,只是它有抽象和泛型(ts也有泛型,抽象类就是类似于golang的接口,只定义不实现)Dart也是单线程执行,主线程外也有宏任务队列和事件队列(可以理解为JavaScript中的宏任务)Dart执行过程:执行main()函数,判断是微任务还是事件队列,是微任务则插入微任务队列,是宏任务则插入宏任务队列,执行完成后(主线程),会执行微任务队列和事件队列,以及判断微任务队列和事件队列是否为空,当为空时程序执行结束flutter项目下的lib/main.dart,class MyApp类下修改为 home: const MyHomePage(title: 'Hallo word'), // 当前title信息在return Scaffold下的body: Center下的,修改为children: [const Text('Hallo word',),运行后可以看到一个title以及内容都为Hallo word的appflutter自带了可视化工具,Dart DevTools自己写一个main.dartvoid main() => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context){ return MaterialApp( title: "hallo word", // app的title theme: ThemeData( primarySwatch: Colors.orange, // 页面的主题颜色 ) home: Scaffold( appBar: AppBar( title: Text("hallo word"), // 当前页面的title ), body: Center( child: Text('hallo flutter'), // 当前页面的文本 ), ), ); } }flutter run(热更新,在执行中输入r或者R)(按p为显示网格,按q为退出,按o为切换android和ios的预览模式)这边用安卓实机调试(也可以用安卓模拟器,例如夜神模拟器)使用flutter devices命令检查是否寻找到该机,记得开启开发者模式,打开调试,允许调试,开启允许USB安装,数据线连接到电脑,并且安装和实机(虚拟机)中的安卓版本sdk,如果官网打不开,可去https://www.androiddevtools.cn/下载或者在Android Studio中安装,下载安装Google USB Driveer(也可以在Android Studio中安装)flutter生命周期flutter组件分为无状态组件和有状态组件,无状态组件就是单纯显示内容的,没有逻辑计算,因此只渲染一次,有状态组件就是具备逻辑交互功能的组件,会因为数据发生变化而多次渲染,这个概念和JavaScript是一样的无状态组件的生命周期只有一个,build有状态组件生命周期分别为createState:该钩子在StatefulWidget中创建State的方法,当StatefulWidget被调用时会立即执行 createStateinitState:该钩子为State初始化调用,一般用来初始化State变量的赋值,与服务端交互获取服务端数据以后调用setState来设置初始化State。didChangeDependencies:该钩子在该组件依赖的State发生变化时会被调用(这里的State发生变化指全局State变化,例如当InheritedWidget发送变化),build跟着触发build:返回需要渲染的Widget,一般有来返回Widget相关逻辑,build会被调用多次setState:当状态发送变化时触发,该钩子被执行后,必然会调用build钩子reassemble:该钩子在debug模式下,每次热重载都会执行该钩子,一般来用做一些debug操作didUpdateWidget:该钩子主要是在组件重新构建时调用,例如热重载,该钩子被执行后,必然会调用build钩子deactivate:该钩子在组件被移除节点后会被调用,如果没有插入到其他节点,会继续触发dispose钩子dispose:永久移除该组件,释放组件资源,一个组件的生命终点
2022年04月19日
253 阅读
0 评论
2 点赞
1
...
3
4
5
...
9