域名 就一个网站/惠州百度seo地址
前置:保存的一些成员变量
// 摄像头开启的 handler
private Handler cameraHandler;
// Camera session 会话 handler
private Handler sessionHandler;
//这里是个Context都行
private AppCompatActivity mActivity;
// 这个摄像头所有需要显示的 Surface,以TextureView创建的Surface在一开始就已经加进去了,如果用SurfaceView的话,注意管理好SurfaceView因为onstop,onStart创建和销毁的Surface
private List<Surface> mViewSurfaces;
private CameraManager cameraManager;private String mCameraId;
private CameraDevice mDevice;
//Camera 配置信息
private CameraCharacteristics mCharacteristics;
private CameraCaptureSession mSession;// 编码输入的Surface,由MediaCodec创建
private Surface mStreamSurface;
// 摄像头选择的输出大小
private Size mSize;//编码器
private MediaCodec mMediaCodec;
一、选择要打开的摄像头,并保存对应配置参数。
-
获取打开的摄像头 ID,以及获取对应参数配置.
try {
String[] cameraIdList = cameraManager.getCameraIdList();
// 遍历摄像头,获取第一个可用的摄像头,多个摄像头暂不播放
for (String id : cameraIdList) {
CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(id);
// 获取该摄像头的说明数据
int[] ints = cameraCharacteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
if (ints != null) {
Arrays.stream(ints).filter(value -> value == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE).close();
if (ints.length == 0) {
Log.d(TAG, “the camera has not basic supports.”);
continue;
}
mCameraId = id;
mCharacteristics = cameraCharacteristics;
// 由于目前无具体需求,使用第一个可连接的摄像头进行显示,选完就返回,有需要的获取配置参数自行判定
break;
}
}
} catch (CameraAccessException e) {
throw new RuntimeException(e);
}
说明:CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE 只是为了确定这个 Camera可用而已。
-
获取摄像头的所有的输出尺寸,选一个合适的
//获取配置参数
StreamConfigurationMap configurationMap = mCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
//拿到对应 ImageFormat.YUV_420_888 所有可输出的尺寸,一般比较多,1280x720,1920x1080等等一大堆,传参有点重要下面说明会说.
Stream stream = Arrays.stream(configurationMap.getOutputSizes(ImageFormat.YUV_420_888));
//这里我选了宽高相乘最大的
Optional max = stream
.max(Comparator.comparingInt(item -> item.getWidth() * item.getHeight()));
stream.close();
//把输出尺寸保存起来,后面创建编码器要用,其实就是视频的分辨率
max.ifPresent(value -> mSize = value);
获取Camera图像格式的方法:
int[] outputFormats = configurationMap.getOutputFormats();
遍历打印一下,选一个就行,但是尽量按照参数说明搭配需求去选。
二、创建编码器
-
通过步骤一拿到的输出尺寸,配置编码格式.(只设置了必要的几个参数,其他的自选加入)
//创建编码格式MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", mSize.getWidth(), mSize.getHeight());//设置码率mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, (int) (mSize.getHeight() * mSize.getWidth() * 0.2));//设置帧率60mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 60);//设置颜色格式,因为这里用的自动编码,就不用yuv420自己手动编了,直接用surfacemediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);//设置关键帧产生速度 1,单位是(帧/秒)mediaFormat.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1f);//摄像头编码角度会出现90度的偏差,设置正向旋转90显示正常效果,你要喜欢歪头90看其实也行mediaFormat.setInteger(MediaFormat.KEY_ROTATION, 90);Log.d(TAG, "MediaCodec format: " + mediaFormat);
说明:
(1) 编码格式创建中,video/avc 表示编码为 h264 编码,编码其实就是为了降低视频大小.
(2) 码率设置中,后面的乘以0.2只是为了降低码率,不然太清晰了。。。正常的大多数是乘以5,这样看着清晰多,当然大小也会增加.
(3) 帧率设置为24以上就行,不然就是PPT。
(4) 关键帧产生速度SDK25之后可以设为float类型,关键帧就是 i 帧,设置之后只是说尽量按这个速度产生,肯定不会一模一样的,0或者复数就是希望没帧都是关键帧
- 创建编码器
try {
//按照“video/avc”创建编码器,硬编码是基于硬件的,厂商不同会有不一样的硬编码实现,编码是Encode,别用成Decode解码器
mMediaCodec = MediaCodec.createEncoderByType(“video/avc”);
} catch (IOException e) {
e.printStackTrace();
}
//配置编码器,MediaCodec状态机就不说了,这里只提使用。参数4也是说明是编码器,和创建时不一致也会报错
mMediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
//创建输入Surface,和MediaFormat设置的KEY_COLOR_FORMAT参数是有联系的,format那里设错了就不能用自动挡的surface,且createInputSurface()方法必须在configure()之后,start()之前调用
mStreamSurface = mMediaCodec.createInputSurface();
//开启编码
mMediaCodec.start();
说明:四个点
(1) MediaCodec.createEncoderByType(“video/avc”),创建编码器,MediaCodec.createDecoderByType(“video/avc”)是创建解码器的。byName那个的话想用得先获取硬件已实现的编码器的名字才能调,虽然不麻烦,但是懒得敲,而且因为硬件厂商实现不同,兼容性还得考虑。
(2) configure()很容易就报错,参数4编解码值是不一样的,以及MediaFormat的设置,如果和摄像头、手机不支持也会报错,所以前面写的那些代码就是为了拿的,不然随便写一个就行了。
(3) MediaCodec.createInputSuface()方法必须在 configure()配置编码之后,start()开始编码之前调用,点进实现也有说明,出现其实也挺好解决,你也可以用mMediaCodec.setInputSurface(创建的常显Surface)去用自己的Surface,没有常显Surface的话可以静态方法MediaCodec.createPersistentInputSurface()创建一个常显Surface.
(4) 在 start()开启编码之后,MediaFormat参数格式其实是可以改的,只是需要用Bundle,通过key-value的方式设值,然后mMediaCodec.setParameters(bundle)去动态设置。
三、操作摄像头
- 打开摄像头预览
摄像头 ID之前已经拿过了,所以直接open就行了。
cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
Log.d(TAG, "onOpened, camera: " + camera);
mDevice = camera;
// Camera 打开之后,把创建的解码器 Surface 加入显示队列中addSurface(mStreamSurface);//创建请求CaptureRequest request = createCaptureRequest(mDevice, mViewSurfaces);//创建输出配置项List<OutputConfiguration> outputConfigurations = createOutputConfig(mViewSurfaces);try {SessionConfiguration config = new SessionConfiguration(SessionConfiguration.SESSION_REGULAR,outputConfigurations,new ThreadPoolExecutor(3, 5, 15, TimeUnit.SECONDS, new ArrayBlockingQueue<>(25)),new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(@NonNull CameraCaptureSession session) {mSession = session;try {//到这个回调,摄像头就可以正常预览了,编码器也会输出编码数据到输出队列了mSession.setRepeatingRequest(request, null, sessionHandler);} catch (CameraAccessException e) {throw new RuntimeException(e);}}@Overridepublic void onConfigureFailed(@NonNull CameraCaptureSession session) {Log.e(TAG, "onConfigureFailed, camera: " + session);if (mSession != null) mSession.close();if (mDevice != null) mDevice.close();mDevice = null;}});mDevice.createCaptureSession(config);} catch (CameraAccessException e) {error();}}@Overridepublic void onDisconnected(@NonNull CameraDevice camera) {Log.e(TAG, "onDisconnected, camera: " + camera);}@Overridepublic void onError(@NonNull CameraDevice camera, int error) {Log.e(TAG, "onError, camera: " + camera + " ,error : " + error);}}, cameraHandler);
-
创建CaptureRequest请求的函数(因为涉及到多个Surface,就单独创建了)
private CaptureRequest createCaptureRequest(CameraDevice cameraDevice, List surfaces) {
CaptureRequest.Builder captureRequest;
try {
//简单预览模式创建,有要求可以根据api去选video这些
captureRequest = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
//聚焦模式,不设置也可以
captureRequest.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
} catch (CameraAccessException e) {
throw new RuntimeException(e);
}
if (surfaces != null) {
//把每一个需要输出摄像头数据的Surface都加入
for (Surface surface : surfaces) {
if (surface == null) {
continue;
}
captureRequest.addTarget(surface);
}
}
return captureRequest.build();
} -
创建List的函数,Surface比较多,用的比较新的api去创建的session,老的api已经被标注遗弃了,所以单独列个方法。
private List createOutputConfig(List surfaces) {
List configs = new ArrayList<>(surfaces.size());
for (Surface surface : surfaces) {
if (surface == null) {
continue;
}
//SDK32,config.enableSurfaceSharing()开启分享后addSurface()添加新的输出面会有问题,所以就没以一个Config去添加所有Surface
OutputConfiguration config = new OutputConfiguration(surface);
//就只创建,啥也不做,有要求可以自己加
configs.add(config);
}
return configs;
}
四、获取编码器的编码数据
-
这部分网上挺多的,也不难.
//这个是保存录像数据的
FileOutputStream outputStream;
//每个关键帧的数据前面都需要添加spsPps的数据,不然无法解码播放
byte[] spsPps = null;boolean codecing = true;
//编码输出信息的对象,赋值由MediaCodec做
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();//当前可用的数据位置
int outputBufferIndex;
byte[] h264 = new byte[mCameraAdapter.getSize().getWidth() * mCameraAdapter.getSize().getHeight()];
//死循环获取,也可以对MediaCodec设置callback获取
while (codecing) {
//获取未来一段时间可用的输出缓冲区,如果存在可用,返回值大于等于0,bufferInfo也会被赋值,最大等待时间是100000微秒,其实就是100毫秒
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 100000);
Log.i(TAG, “dequeue output buffer outputBufferIndex=” + outputBufferIndex);//如果当前输出缓冲区没有可用的,返回负值,不同值含义不一样,有需要做判定即可if (outputBufferIndex < 0) { continue;}ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferIndex);Log.i(TAG, "Streaming bufferInfo,flags: " + bufferInfo.flags+ ", size: " + bufferInfo.size+ ", presentationTimeUs: " + bufferInfo.presentationTimeUs+ ", offset: " + bufferInfo.offset);//调整数据位置,从offset开始。这样我们一会儿读取就不用传offset偏差值了。 outputBuffer.position(bufferInfo.offset);//改完位置,那肯定要改极限位置吧,不然你数据不就少了数据末尾长度为offset的这一小部分?这两步不做也可以,get的时候传offset也一样outputBuffer.limit(bufferInfo.offset + bufferInfo.size);//现在的spsPps还是空的,这是不能做写入文件,保存之类操作的if (spsPps == null) {//创建写入的文件,保存录像try {File file = new File(mContext.getDataDir().getAbsolutePath() + "camera.h264");boolean newFile = file.createNewFile();outputStream = new FileOutputStream(file, true);} catch (Exception ignored) {}// sps pps获取并保存,还有其他方式可以获取,不过不一定有效,最好检验一下ByteBuffer sps = mMediaCodec.getOutputFormat().getByteBuffer("csd-0");ByteBuffer pps = mMediaCodec.getOutputFormat().getByteBuffer("csd-1");byte[] spsBites = new byte[sps.remaining()];byte[] ppsBites = new byte[pps.remaining()];sps.get(spsBites);pps.get(ppsBites);spsPps = new byte[spsBites.length + ppsBites.length];System.arraycopy(spsBites, 0, spsPps, 0, spsBites.length);System.arraycopy(ppsBites, 0, spsPps, spsBites.length, ppsBites.length);} else {//现在已经有spsPps数据了,可以开始了try {if (bufferInfo.size > h264.length) {h264 = new byte[bufferInfo.size];}h264 = new byte[bufferInfo.size];//获取编码数据outputBuffer.get(h264, 0, bufferInfo.size);//数据校验一下,如果是关键帧需要在头部加入spsPps,校验完的trans,就是编码好的h264编码数据了byte[] trans = trans(h264, 0, bufferInfo.size, bufferInfo.flags);//保存录像数据到文件中.暂定2G大小if (outputStream.getChannel().size() < (2L << 30)) {outputStream.write(trans);}//结束标志到达if (bufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {pusher.stop();isStreaming = false;}} catch (Exception e) {e.printStackTrace();} finally {//释放这个缓冲位置的数据,不释放就一直在,MediaCodec数据满了可不行mediaCodec.releaseOutputBuffer(outputBufferIndex, false);}}
}
说明:
(1) 获取编码的 index,大于等于零才是有效的,不然不能用。
(2) 保存h264编码数据之前,需要先获取spsPps,不然关键帧之前没有spsPps,解码播放端也不加的话就没法看了。
(3) 获取数据注意offset,真正有效的数据是 bytes[offset] 到 bytes[offset+size]这个位置,至于你是get()的时候传offset拿,还是possition()limit()后传0拿,就看你心情了。
(4) 这个index的输出缓冲区用完之后,记得释放
(5) 这个录像保存只是做个样子,如果真是录像,建议用 MediaMuxer 来做,直接传判定 index 后 传 buffinfo 就行,简单方便。
-
这是校验是不是关键帧的,很简单明了
private byte[] trans(byte[] h264, int offset, int length, int flags) {
//关键帧判定
if ((flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) {
// 每个关键帧前面需要添加spsPps
byte[] data = new byte[spsPps.length + length];
System.arraycopy(spsPps, 0, data, 0, spsPps.length);
System.arraycopy(h264, offset, data, spsPps.length, length);
length = data.length;return data;} else {return h264;}
}
五、播放保存的 h264 文件.
连上设备,我这边设置的文件位置是 Context.getDataDir().getAbsolutePath()/camera.h264,真实目录是 /data/data/包名/camera.h264,保存出来用vlc,或者ffmpeg命令ffplay播放就行了,亲测:windows自带的播放器无法解码(笑)。
相关文章:

camera2对摄像头编码h264
MediaCodec编码摄像头数据 前置:保存的一些成员变量 // 摄像头开启的 handler private Handler cameraHandler; // Camera session 会话 handler private Handler sessionHandler; //这里是个Context都行 private AppCompatActivity mActivity; // 这个摄像头所有需…...

Apache solr XXE 漏洞(CVE-2017-12629)
任务一: 复现环境中的漏洞 任务二: 利用XXE漏洞发送HTTP请求,在VPS服务器端接受请求,或收到DNS记录 任务三: 利用XXE漏洞读取本地的/etc/passwd文件 1.搭建环境 2.开始看wp的时候没有看懂为什么是core,然…...

HTML代码混淆技术:原理、应用和实现方法详解
HTML代码混淆是一种常用的反爬虫技术,它可以有效地防止爬虫对网站数据的抓取。本文将详细介绍HTML代码混淆技术的原理、应用以及实现方法,帮助大家更好地了解和运用这一技术。 一、HTML代码混淆的原理 HTML代码混淆是指将HTML源码通过特定的算法进行加…...

quickapp_快应用_系统接口应用
系统接口 在项目中使用到的接口都需要在配置文件manifest.json中声明,不然会报如下警告 [WARN] 请在 manifest.json 文件里声明项目代码中用到的接口: system.storage, service.account, system.package, system.webview[1]检查某app是否在手机上安装 官方文档&a…...

sqlmap400报错问题解决
python sqlmap.py -r sql.txt --batch --techniqueB --tamperspace2comment --risk 3 --force-ssl–batch 选项全部默认 不用再手动输入 –techniqueB 使用布尔盲注,该参数是指出要求使用的注入方式 –tamperspace2comment使用特殊脚本,space2comment是把…...

【S32DS报错】-2-提示Error while launching command:arm-none-eabi-gdb –version错误
目录 1 Error错误提示 2 Error错误原因 3 如何消除Error错误 结尾 【S32K3_MCAL从入门到精通】合集: S32K3_MCAL从入门到精通https://blog.csdn.net/qfmzhu/category_12519033.html 1 Error错误提示 使用S32DSJ-LinK下载程序,在Dedug Configurati…...

Windows核心编程 HOOK
目录 HOOK概述 HOOK API SetWindowsHookExA 函数(winuser.h) UnhookWindowsHookEx 函数(winuser.h) NextHookEx 函数(winuser.h) 局部钩子 全局钩子 为什么全局钩子需要用dll作为过程函数? HOOK概述 本质:Windows消系统的消息过滤器。 全局钩子…...

P4 Qt如何添加qss样式表文件和添加图片资源
目录 前言 01 添加图片资源文件 02 添加qss文件 前言 🎬 个人主页:ChenPi 🐻推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ 🔥 推荐专栏2: 《Qt基础_ChenPi的博客-CSDN博客》✨✨✨ 🌺本篇简介 :这一章…...

【华为OD题库-085】路灯照明II-Java
题目 在一条笔直的公路上安装了N个路灯,从位置0开始安装,路灯之间间距固定为100米。 每个路灯都有自己的照明半径,请计算第一个路灯和最后一个路灯之间,无法照明的区间的长度和。输入描述 第一行为一个数N,表示路灯个数…...

附录1、vuepress中的Markdown语法
# 一、标题 # 说明: #后面跟的内容就是标题,一个#就是一级标题,有几个#就是几级标题,例如2级标题就有两个##,markdown的2级和3级标题会默认自动作为子目录, 注意:#后面必须有个空格࿰…...

【matlab程序】matlab画螺旋图|旋转图
%% 数学之美====》螺旋线 % 海洋与大气科学 % 20231205 clear;clc;close all; n=10; t=0:0.01:2pin; R=1; xx=nan(length(t),1);yy=nan(length(t),1); for i=1:length(t) xx(i)=Rcos(t(i)); yy(i)=Rsin(t(i)); R=R+1; end figure set(gcf,‘position’,[50 50 1200 1200],‘col…...

计算三位数每位上数字的和
分数 10 作者 python课程组 单位 福州大学至诚学院 补充程序实现计算: 输入一个三位的整数(不接受实数),求这个三位数每一位上数字的和是多少?例如:输入:382,输出:和为…...

Gavin Wood:财库保守主义偏离了初心,应探索 Fellowship 等更有效的资金部署机制
波卡创始人 Gavin Wood 博士最近接受了 The Kusamarian 的采访,分享了他的过往经历、对治理的看法,还聊到了 AI、以太坊、女巫攻击、财库等话题。本文整理自 PolkaWorld 对专访编译的部分内容,主要包含了 Gavin 对治理、财库提案、生态资金分…...

Linux: sudo: unable to execute /opt/sbin/adm: No such file or directory
因为脚本语言第一行是指定解释器,但是里面包含非法^M字符,导致后续的系统调用,找不到解释器,然后报错误找不到文件。 所以这里存在一个问题,就是错误提示里虽然显示文件找不到,而且也把文件打印了出来。但是非法的字符却没有打印出来。所以导致让人迷惑的可能。 sudo: un…...

一文详解Java单元测试Junit
文章目录 概述、Junit框架快速入门单元测试概述main方法测试的问题junit单元测试框架优点:使用步骤: 使用案例包结构 Junit框架的常见注解测试 概述、Junit框架快速入门 单元测试概述 就是针对最小的功能单元(方法),…...

进制 + 原码,反码,补码
进制转换 整数部分 小数部分 原码 反码 补码 原码转补码: 左边和右边第一个1不变,中间取反。-0 除外。 计算机系统中数值一律用补码来存储的原因 其他 术语 进制表 进制数的表示 详细教程可转 爱编程的大丙...

2024年网络安全行业前景和技术自学
很多人不知道网络安全发展前景好吗?学习网络安全能做什么?今天为大家解答下 先说结论,网络安全的前景必然是超级好的 作为一个有丰富Web安全攻防、渗透领域老工程师,之前也写了不少网络安全技术相关的文章,不少读者朋…...

cocos 关于多个摄像机,动态添加节点的显示问题,需要动态修改layer。(跟随摄像机滚动)(神坑官网也不说明一下)
参考文章:Cocos 3.x 层级Layer - 简书 2D镜头跟随应该怎么实现呢 - Creator 3.x - Cocos中文社区 关于多个摄像机,动态添加节点的显示问题,需要动态修改layer? 场景:在制作摄像机跟随角色移动功能时,新增…...

freeswitch编译mod_av支持webrtc MCU通话
系统环境 一、FS相关网站 二、第三方库安装 1.apt安装 2.指定版本sofia-sip安装 3.指定版本spandsp安装 4.指定版本libks安装 5.指定版本openssl安装 三、指定版本FS安装 1.CPPFLAGS配置 2.编译器版本 3.FS配置编译 四、FS,fs_cli运行,模块加载 附录 1.安…...

K8s 入门指南(一):单节点集群环境搭建
前言 官方文档:Kubernetes 文档 | Kubernetes 系统配置 CentOS 7.9(2 核 2 G) 本文为 k8s 入门指南专栏,将会使用 kubeadm 搭建单节点 k8s 集群,详细讲解环境搭建部署的细节,专栏后面章节会以实战代码介绍…...

python socket编程6 - 使用PyQt6 开发UI界面实现TCP server和TCP client单机通讯的例子
使用PyQt6 开发UI界面实现TCP server和TCP client单机通讯的示例。 一、PyQt6 实现的界面 二、TCP server代码的修改示意 界面提供网络参数的配置,以及提供人机交互过程中的数据获取和显示。 1、把上面的server代码封装成两个部分 A、class Server 负责接受UI界面…...

centos上安装并持久化配置LVS
1 实验背景 1)系统版本:centos7.8 2)虚拟机:3个centos虚拟机,(其中一个做Director Server,另外两个做Real Server) 3) LVS大致有NAT ,DR ,Tun这三种模式,这里搭建一个典型的DR模式的LVS Direc…...

多线程并发Ping脚本
1. 前言 最近需要ping地址,还是挺多的,就使用python搞一个ping脚本,记录一下,以免丢失了。 2. 脚本介绍 首先检查是否存在True.txt或False.txt文件,并在用户确认后进行删除,然后从IP.txt的文件中读取IP地…...

SpringBoot Seata 死锁问题排查
现象描述:Spring Boot项目,启动的时候卡住了,一直卡在那里不动,没有报错,也没有日志输出 但是,奇怪的是,本地可以正常启动 好吧,姑且先不深究为什么本地可以启动而部署到服务器上就无…...

文章解读与仿真程序复现思路——电力系统自动化EI\CSCD\北大核心《考虑两阶段鲁棒优化配置的多微网合作博弈》
这个标题涉及到多个概念,让我们逐步解读: 考虑两阶段鲁棒优化配置: 两阶段: 指的是在解决问题或进行优化时,可能存在两个不同的阶段或步骤。这表明问题的解决不是一步完成的,而是需要经过多个步骤或阶段。鲁…...

Redis常见类型
常用类型String字符串类型Hash字典类型List列表类型Set集合类型ZSet有序集合类型 Java程序操作Redis类型代码操作Redis 常用类型 String字符串类型 使用方式: 使用场景: Hash字典类型 字典类型(Hash) 又被成为散列类型或者是哈希表类型࿰…...

深入了解数据库锁:类型、应用和最佳实践
目录 1. 引言 2. 数据库锁的基本概念 2.1 悲观锁和乐观锁 2.2 排他锁和共享锁 3. 悲观锁的应用场景 3.1 长事务和大事务 3.2 并发修改 3.3 数据库死锁 4. 悲观锁的最佳实践 4.1 精细控制锁的粒度 4.2 避免死锁 4.3 考虑乐观锁 5. 案例分析 5.1 银行系统的转账操作…...

python3.5安装教程及环境配置,python3.7.2安装与配置
大家好,小编来为大家解答以下问题,python3.5安装教程及环境配置,python3.7.2安装与配置,现在让我们一起来看看吧! python 从爬虫开始(一) Python 简介 首先简介一下Python和爬虫的关系与概念&am…...

ubuntu安装tomcat并配置前端项目
1.1查找 # 先更新 sudo apt update # 查找 apt search jdk1.2安装 sudo apt install openjdk-8-jdk1.3验证 java -version 2.安装tomcat 下载链接:Apache Tomcat - Apache Tomcat 8 Software Downloadshttps://tomcat.apache.org/download-80.cgi下载这个&…...

GeoPandas初体验:它是什么,我用它展示一下shp矢量数据
GeoPandas 是一个开源的 Python 库,用于处理地理空间数据。它扩展了 Pandas 这个流行的 Python 数据操作库,增加了对地理数据类型和操作的支持。GeoPandas 结合了 Pandas、Matplotlib 和 Shapely 的功能,提供了一个易于使用且高效的工具&…...