mobx中跟新了数据视图没变化_【第1781期】MobX 简明教程

前言

SEEConf,2020年1月4号杭州见,C位抢票见文章末尾。今日早读文章由腾讯@whinc投稿分享。

正文从这开始~~

导读:MobX 是一个优秀的响应式状态管理库,在流行的状态管理库 Redux 之外为我们提供了其他选择。如果你还没有尝试过 MobX,我强烈建议你继续阅读本文,并跟着示例动手实践体验一下。本文是 MobX 的入门教程,文章包含 MobX 的设计哲学、状态派生模型、核心API以及与 React 的集成。

MobX 是一个简单、可伸缩的响应式状态管理库。通过 MobX 你可以用最直观的方式修改状态,其他的一切 MobX 都会为你处理好(如自动更新UI),并且具有非常高的性能。

MobX 文档的概念和 API 比较多,初次接触时可能会感觉无从下手或者抓不住重点,本文尝试提供一份 MobX 核心的知识的简明教程,作为阅读官方文档之前的热身。

MobX 的设计哲学

在学习使用 MobX API 之前,我们首先要了解 MobX 的设计哲学,它是我们在思考 MobX 应用时的心智模型,可以帮助我们更好的使用 MobX API。

MobX 的设计哲学概括起来就一句话:Anything that can be derived from the application state, should be derived. Automatically. (任何可以从应用状态中派生的内容,都应当自动地被派生。)

理解这句话的关键是搞清楚【派生】的含义是什么?在 MobX 中【派生】的含义比较广泛,包括:

  • 用户接口(UI),如组件、页面、图表

  • 派生数据(computed data),如从数组中计算得到的数组长度

  • 副作用(side effect),如发送网络请求、设置定时任务、打印日志等

我们平时常看到的状态响应模型,其中的响应就可以看做是状态的一种派生,MobX 将这种模型进行泛化,形成更通用的状态派生模型,接下来会详细介绍。

MobX 状态响应模型

状态响应模型概括起来主要包含三个要素:定义状态、响应状态、修改状态(如下图所示)。

979a17f0d14d1ea640c4dd5925336c82.png

MobX 中通过observable来定义可观察状态, 它接受任意 JS 值(包括Object、Array、Map、Set),返回原始数据的代理对象,代理对象与原始数据具有相同的接口,你可以把代理对象当做原始数据使用。

// 定义状态

const store = observable({

count: 0

});

MobX 中通过autorun来定义状态变化时要执行的响应操作,它接受一个函数。此后,每当observable中定义的状态发生变化时,MobX 都会立即执行该函数。

// 响应状态

autorun(() => {

console.log("count:", store.count);

});

MobX 中修改状态和修改原始数据的方式没什么区别,这也是 MobX 的优点——符合直觉的操作方式。

// 修改状态

store.count += 1;

把上面的部分串起来就是一个最简单的 MobX 示例了(如下),示例中每次修改 count 的值时会自动打印一条日志,并且日志包含最新的 count 值。这个示例揭示了 MobX 中最核心的功能。

import { observable, autorun } from "mobx";

// 1. 定义状态

const store = observable({

count: 0

});

// 2. 响应状态

autorun(() => {

console.log("count:", store.count);

});

// count: 0

// 3. 修改状态

store.count += 1;

// count: 1

上面例子中,首先通过 MobX 提供的observable函数定义状态,例子的状态是{count: 0}。然后通过通过 MobX 提供的autorun函数定义状态响应函数,例子中是一条打印当前count值得的语句,当定义的状态中的任何值发生变化时,该响应函数会立即执行,并且是由 MobX 自动完成的。最后是修改状态,和操作对象属性一样,例子中是对count属性进行自增操作。

MobX 状态派生模型

从上一节中我们知道 MobX 的状态响应函数是在状态变化时执行某些操作。实际应用中这些操作可分为两类:带副作用(如打印日志、渲染 UI、请求网络等)和不带副作用(如计算数组的长度)。MobX 将这些操作统称为派生(Derivations),即可从应用状态中派生出来的任何内容。

其中不带副作用的操作是一个纯函数,一般是根据当前状态计算返回一个新的值。为了区分带副作用和不带副作用的两类情况,MobX 将 Derivations 概念细分成两个概念 Reactions 和 Computed values 来区分二者。此外,MobX 还提供了一个可选的概念 Action 来表示对 State 的修改操作,用于约束和预测应用状态的修改行为。这些概念汇总在一起如下图:

52763a66b195200cb7a709d0eec1490d.png

下面是一个简单的示例,完整展示了上图中涉及的所有概念。

index.html 文件

id="container">

index.js 文件

import { observable, autorun, computed, action } from "mobx"

const containerEl = document.querySelector("#container");

// State

const store = observable({

count: 0

});

// Actions

window.increaseCount = action(() => store.count++);

// Computed values

const doubleCount = computed(() => 2 * store.count);

// Reactions

autorun(() => {

containerEl.innerHTML = `

${store.count} * 2 = ${doubleCount.get()}

+1

`;

});

// 0 * 2 = 0

// (点击按钮)

// 1 * 2 = 2

// (点击按钮)

// 2 * 2 = 4

这个示例展示了一个简单的乘法,点击按钮后数据会自增,同时计算的结果也随之更新。相比上一个例子,它有几个值得注意的区别:

  • 通过computed定义计算值,并返回计算值对象doubleCount,通过其get/set方法访问内部计算值。computed接受一个返回计算值的函数,在函数内部可以使用observable定义的状态数据(如count),每当count的值发生变化时,doubleCount内部的计算值会自动更新。

  • 通过action定义状态修改操作,action接受一个函数,并返回一个签名相同的函数。在函数内部可直接修改obsevable定义的状态(如count)触发autorun和computed重新运行。

  • autorun中的响应操作替换成了渲染 UI,每当状态发生变化时重新渲染 UI。

MobX 核心 API 解析

MobX 的 API 可分为四类:定义状态(observable)、响应状态(autorun, computed)、修改状态(action)、辅助函数。下面挑出最核心的 API 进行重点介绍,但不会涉及 API 的详细用法(请参考MobX Api Reference)。

MobX 目前同时支持 v4 和 v5 两个版本,这两个版本的 API 是相同的(功能相同),他们的区别在于内部实现数据响应的方式不同,如果使用 v4 版本时需要注意文档中标注的注意情况。

observable

observable用于定义可观察状态,其类型定义如下(已简化):

extends Object>(value: T): T & IObservableObject;

= any>(value: T[]): IObservableArray;

= any, V = any>(value: Map, V>): ObservableMap, V>;

= any>(value: Set): ObservableSet;

它接受Object/Array/Map/Set类型的数据作为参数,并返回对应数据的代理对象,代理对象和原数据类型具有相同的接口,你可以像使用原始数据一样使用代理对象。例如:

import { observable } from "mobx";

const object = observable({a: 1})

console.log(object.a)

const array = observable([1, 2])

console.log(array[0])

const map = observable(new Map({a: 1}))

console.log(map.get('a'))

const set = observable(new Set([1, 2]))

console.log(set.has(1))

observable观察的数据可以嵌套,嵌套的数据也会被观察。例如:

import { observable, autorun } from "mobx";

const store = observable({

a: {

b: [1, 2]

}

})

autorun(() => console.log(store.a.b[0]))

// 1

store.a.b[0] += 1

// 2

observable支持动态添加可观察状态。例如:

import { observable, autorun } from "mobx";

const store = observable({});

autorun(() => {

console.log("a =", store.a);

});

// a = undefined

store.a = 1;

// a = 1

动态添加可观察状态,仅适用于 MobX v5+ 版本,MobX v4 及以下版本需要借助辅助函数,详见Direct Observable manipulation。

autorun

autorun用于定义响应函数,其类型定义如下(已简化):

autorun(reaction: () => any): IReactionDisposer;

autorun接受一个响应函数 reaction,并在定义时立即执行一次 reaction 函数, reaction 函数内部可以执行带有副作用的操作。以后,每当依赖状态发生变化时,autorun自动重新运行 reaction 函数。autorun第一次运行 reaction 函数是为了搜集依赖状态——运行 reaction 过程中实际使用的状态(通过obj.name或obj['name']解引用方式使用的状态)。

例如下面例子,autorun中使用了状态a,因此当状态a的值发生变化时,会执行响应函数。而状态b虽然被列为可观察状态,但由于在autorun中没有被实际使用,因此当状态b的值发生变化时,不会执行 响应函数 。这是 MobX 的“聪明”之处,它能根据状态的实际使用情况,细粒度地控制更新范围。由于减少了不必要的执行开销,从而提升了程序性能。

import { observable, autorun } from "mobx";

const store = observable({

a: 1,

b: 2

});

autorun(() => {

console.log("a =", store.a);

});

// a = 1

store.a += 1;

// a = 2

store.b += 1;

// (无输出)

让我们回顾一下 MobX 的使用,通过observable定义状态,在autorun中使用状态,当autorun中使用到的状态发生变化时,该autorun重新执行。绝大部分情况下它都工作的很好,如果你遇到修改了状态而autorun没有如你预期的那样运行,这时候你需要深入了解 MobX 是如何响应状态变化的,推荐阅读What does MobX react to?。

computed

computed用于定义计算值,其类型定义如下(已简化):

(func: () => T) => { get(): T, set(value: T): void}

computed与autorun相似,他们都会在依赖的状态发生变化时会重新运行,不同之处是computed接收的是纯函数并且返回一个计算值,这个计算值在状态变化时会自动更新,计算值可以在autorun中使用。

例如下面例子中,ca是一个计算值,它依赖状态a的值,当状态a的值发生变化时,ca会重新计算值。计算值ca是一个“装箱”对象,需要通过get/set访问内部值,只有这样才能保持计算值的引用不变而内部值又是可变的。

import { observable, autorun, computed } from "mobx";

const store = observable({

a: 1

});

const ca = computed(() => {

return 10 * store.a;

});

autorun(() => {

console.log(`${store.a} * 10 = ${ca.get()}`);

});

// 1 * 10 = 10

store.a += 1;

// 2 * 10 = 20

store.a += 1;

// 3 * 10 = 30

由于computed被视作是纯函数,MobX 提供了许多开箱即用的优化措施,例如对计算值的缓存和惰性计算。

computed值会被缓存

每当读取computed值时,如果其依赖的状态或其他computed值未发生变化,则使用上次的缓存结果,以减少计算开销,对于复杂的computed值,缓存可以大大提高性能。

例如下面例子中,computed值ca和cb分别依赖状态a和b,第一次执行autorun时,ca和cb都会重新计算,然后修改状态a的值,第二次执行autorun时,只有ca会重新计算,而cb则使用上次的缓存结果。

import { observable, autorun, computed } from "mobx";

const store = observable({

a: 1,

b: 1

});

const ca = computed(() => {

console.log("recomputed ca");

return 10 * store.a;

});

const cb = computed(() => {

console.log("recomputed cb");

return 10 * store.b;

});

autorun(() => {

console.log(

`a = ${store.a}, ca = ${ca.get()}, b = ${store.b}, cb = ${cb.get()}`

);

});

// recomputed ca

// recomputed cb

// a = 1, ca = 10, b = 1, cb = 10

store.a += 1;

// recomputed ca

// a = 2, ca = 20, b = 1, cb = 10

为了观察computed的计算过程,插入了打印日志的语句,这会带有副作用,实际中不要这样做

computed值会惰性计算

只有computed值被使用时才重新计算值。反言之,即使computed值依赖的状态发生了变化,但是它暂时没有被使用,那么它不会重新计算。

例如下面例子中,computed值ca依赖状态a。当状态a的值小于 3 时,autorun运行时只打印状态a的值,由于computed值ca未被使用,所以ca不会从新计算。当状态a的值增长到 3 以后,autorun运行时同时打印状态a和computed值ca,由于computed值ca被使用了,所以ca会重新计算。

import { observable, autorun, computed } from "mobx";

const store = observable({

a: 1

});

const ca = computed(() => {

console.log("recomputed ca");

return 10 * store.a;

});

autorun(() => {

if (store.a >= 3) {

console.log(`a = ${store.a}, ca = ${ca.get()}`);

} else {

console.log(`a = ${store.a}`);

}

});

// a = 1

store.a += 1;

// a = 2

store.a += 1;

// recomputed ca

// a = 3, ca = 30

action

action用于定义状态修改操作,其类型定义如下(已简化):

extends Function>(fn: T) => T

虽然没有action也可以直接修改状态,但是通过action显式地修改状态,使得状态的变化可预测(状态的变化能定位到是哪个action引起的)。此外,action函数是事务型的,通过action修改状态时,响应函数不会立即执行,而是等到action结束后才执行,这有助于提升性能。

例如下面例子中,展示了修改状态的两种方式,一种是直接修改状态a,另一种是通过调用预先定义的action修改状态。值得注意的是,在一次action中连续两次修改状态a的值,只会触发一次autorun的执行。

import { observable, autorun, action } from "mobx";

const store = observable({

a: 1

});

autorun(() => {

console.log(`a = ${store.a}`);

});

// a = 1

store.a += 1;

// a = 2

store.a += 1;

// a = 3

const increaseA = action(() => {

store.a += 1;

store.a += 1;

});

increaseA();

// a = 5

对 MobX 进行一些配置后,可以使action成为修改状态的唯一方式,这可以避免不受约束的修改状态行为发生,有利于提升项目的可维护性。

例如下面例子中,配置 enforceActions 为"always"后,就只能通过action修改状态了,如果尝试直接修改状态将会触发异常。

import { observable, autorun, action, configure } from "mobx";

// 强制只能通过 action 修改状态

configure({

enforceActions: "always"

});

const store = observable({

a: 1

});

autorun(() => {

console.log(`a = ${store.a}`);

});

// a = 1

// store.a += 1;

// 直接修改状态,将会抛出如下异常

// Error: [mobx] Since strict-mode is enabled, changing observed

// observable values outside actions is not allowed.

// Please wrap the code in an `action` if this change is intended.

const increaseA = action(() => {

store.a += 1;

});

increaseA();

// a = 2

MobX 与 React 集成

MobX 是框架无关的,你可以单独使用它,也可以与任何流行的 UI 框架进行一起使用,MobX 官方提供了 React/Vue/Angular 等流行框架的绑定实现。MobX 最常见的是与 React 一起使用,他们的绑定实现是 mobx-react(或 mobx-react-lite)。

mobx-react 提供了一个observer方法, 它是一个高阶组件,它接收 React 组件并返回一个新的 React 组件,返回的新组件能响应(通过observable定义的)状态的变化,即组件能在可观察状态变化时自动更新。observer方法是对 MobX 提供的autorun方法和 React 组件更新机制的封装,以便于在 React 中使用,你依然可以在 React 中使用autorun来更新组件。下面是observer方法的类型声明,它支持组件类和函数组件。

function observer<T extends React.ComponentClass | React.FunctionComponent>(target: T): T

下面是组件类使用 MobX 的示例,通过observable定义可观察状态,并通过observer包裹组件,之后组件事件处理方法中修改状态后,组件会自动更新,无需手动调用 React 的setState()来更新组件。

import React from "react";

import { observable } from "mobx";

import { observer } from "mobx-react";

class Counter extends React.Component {

constructor(props) {

super(props);

this.store = observable({

count: 0

});

}

render() {

return (

<button onClick={() => store.count++}>

{store.count}

button>

)

}

}

export default observer(Counter);

下面是函数组件使用 MobX 的示例,与上面类组件类似,区别是使用 mobx-react 提供的useLocalStore定义客观察状态,useLocalStore内部也是使用observable定义可观察状态。

import React, { useMemo } from "react";

import { observable } from "mobx";

import { observer, useLocalStore } from "mobx-react";

const Counter = () => {

const store = useLocalStore(() => ({

count: 0

}));

// 等价于下面

// const store = useMemo(() => observable({ count: 0 }), []);

return (

<button onClick={() => store.count++}>

{store.count}

button>

)

};

export default observer(Counter);

小结

MobX 的设计哲学是“可从应用状态中派生的任何内容都应当自动的被派生”,后半句有两个关键字:自动和派生。心中秉持这一设计哲学,再来看 MobX 的派生状态模型就比较清晰了,Computed values 和 Reactions 都可以视作是从 State 中派生出的,State 变化时触发 Computed values 的重新计算和 Reations 的重新运行。为了让派生能自动的进行,MobX 通过Object.definePropery或Proxy方式拦截对象的读写操作,从而允许用户以自然的方式来修改状态,MobX 负责更新派生的内容。

MobX 提供了几个核心 API 来帮助定义状态(observable)、响应状态(autorun, computed)和修改状态(action),通过这些 API 可以让程序立即具备响应式能力。这些 API 接口并不复杂,但要熟练使用,需要深入理解 MobX 响应机制,文中通过一些简单的示例来辅助理解这些 API 的行为。

MobX 可以单独使用,也可以与任何流行的 UI 框架一起使用,Github 上可以找到 MobX 与流行框架的绑定实现。不过 MobX 最常见的是与 React 一起使用,mobx-react 是流行的 MobX 和 React 的绑定实现库,本文介绍了它在组件类和函数组件上的一些基本用法。

参考

  • MobX Documentations

  • mobx-react

关于本文 作者:@whinc 原文:https://github.com/whinc/blog/issues/16

b206cab1309267f6939f122375d024c9.png

他曾分享过

【第1611期】前端路由原理解析和实现

为你推荐

【第1586期】基于Redux/Vuex/MobX等库的通用化状态OOP

【第1302期】基于 MobX 构建视图框架无关的数据层-与 Vue 的结合

【第1736期】现代 JavaScript 教程 - 代码风格

d7671a9bac7d1d9017026fd642c54838.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/355727.shtml

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

相关文章

excel导航窗格_Excel小技巧16:在每天的某个时刻自动打开特定工作簿

学习Excel技术&#xff0c;关注微信公众号&#xff1a;excelperfect我想要在每天下班前&#xff0c;将自已一天的工作进行整理并简短记录在一个Excel工作簿中。然而&#xff0c;有时候忙&#xff0c;可能会忘记&#xff1b;有时候到下班时间了&#xff0c;急于下班&#xff0c;…

51单片机按键控制数码管0~9_51单片机外部中断

前面为大家介绍的点亮LED灯、数码管、按键只用到了51单片机的IO资源&#xff0c;我们要是仅仅用单片机点灯、操作数码管&#xff0c;那可真是大才小用了。这些都只是51单片机资源的冰山一角&#xff0c;51单片机还有好多的功能&#xff0c;我后面将为大家一一介绍。今天为大家介…

IIS7开启gZip动态压缩

1.安装动态压缩模块&#xff1a; 安装过程可能的报错&#xff1a;This application has requested the Runtime to terminate it in an unusual way. 解决办法>> 报错&#xff1a;错误: 尝试安装 动态内容压缩 失败&#xff0c;错误代码为 0x8007000E。 存储空间不足&am…

mysql查询不重复记录数_mysql查询不重复的行内容,不重复的记录数.count,distinct

有这么一个表 记录了id, p_id, p_name , p_content , p_time 1 343 aaa aaaaaa 2012-09-01 2 344 bbb bbbbbb 2012-09-02 3 321 ccc cccccccc 2012-09-03 4 343 aaa aaaaaa 2012-09-04 想查询不重复的行的内容,并且输出 p_sum ( 产品p_id出现重复的次数) sele有这么一个表记录了…

使用Java中的FileChannel和ByteBuffer在文件中读取/写入文件

过去&#xff0c;我讨论过RandomAccessFile以及如何将其用于在Java中进行更快的IO&#xff0c;在本Java NIO教程中&#xff0c;我们将了解如何通过使用FileChannel和ByteBuffer来使用读/写数据。 Channel提供了一种从文件读取数据的替代方法&#xff0c;它提供了比InputStream…

mysql 导入百万级数据 几种 java_Java 修行第034天--执行计划及其使用--Oracle数据导入导出--第三章MySQL使用...

执行计划中牢记几句话:-- 尽量避免是*代替所有列,编写查询语句时使用具体列名代替*,可以防止全表扫描-- 尽可能少的使用like关键字进行模糊查询-- 建立适当的索引可以提高查询效率十三. 执行计划--通过PL/SQL Developer查看查询的1 执行计划是一条查询语句在Oracle中的执行过程…

摄像头分辨率怎么调整_亿联CAM50 - 智能话机专属高清摄像头

亿联CAM50是通过USB连接的高清视频摄像机&#xff0c;适用于亿联桌面高端智能话机&#xff08;SIP-T58V和SIP-T58A&#xff09;&#xff0c;致力于提供一流的个人视频通信体验&#xff0c;优化视频协作。CAM50高清摄像机即插即用&#xff0c;无需额外安装驱动软件&#xff0c;也…

ios系统python编译器_MacBook如何安装Python编译器-百度经验

编程是一门需要动手实践的技能&#xff0c;由于Python的性能&#xff0c;许多人都将其作为学习编程的入门语言。而要想学好Python&#xff0c;首先要在电脑上安装Python&#xff0c;并安装一个可以解释Python的文本编辑器。在此以在MacBook上安装Sublime Text为例。 工具/原料 …

jvm需要多长时间进行转义分析? 可能比您想象的要长。

这篇文章着眼于转义分析&#xff0c;特别是jvm在运行的程序中执行转义分析需要多长时间。 我做了一些观察&#xff0c;但目前还没有全部解释。 作为介绍&#xff0c;让我们绕道看看jvm -Xcomp中一个鲜为人知且使用更少的标志&#xff08;这将是一件好事&#xff09;。 该标志…

Java补漏(一)

&#xfeff;&#xfeff;第一章前言 在学长的建议下&#xff0c;为了弥补之前学Java漏下的或者不是非常清楚的知识点&#xff0c;买了本蛮好的教科书-《Java学习笔记&#xff08;JDK6&#xff09;》&#xff0c;正式又一次学习。为了记下一些让我恍然大悟的知识。写了本文档。…

spring environment_程序员:Spring项目中简单几步实现多个动态数据源切换

每一个请求与其他的用户是面对不同的数据库&#xff0c;这就需要用到动态数据源切换&#xff0c;来满足不同数据库、不同数据表(不同数据源)的灵活调用。动态数据源切换满足mysql、oracle等主流数据库进行动态数据源切换。使用方法在 WEB-INF 目录下建立 lib 目录&#xff0c;并…

算法笔记_163:算法提高 最大乘积(Java)

目录 1 问题描述 2 解决方案 1 问题描述 问题描述对于n个数&#xff0c;从中取出m个数&#xff0c;如何取使得这m个数的乘积最大呢&#xff1f;输入格式第一行一个数表示数据组数每组输入数据共2行&#xff1a;第1行给出总共的数字的个数n和要取的数的个数m&#xff0c;1<n&…

ServletRequest startAsync()的用途有限

前段时间我遇到了Servlet 3.0中AsyncContext.start&#xff08;…&#xff09;的目的是什么&#xff1f; 题。 引用上述方法的Javadoc &#xff1a; 使容器调度线程&#xff08;可能从托管线程池中&#xff09;运行指定的Runnable 。 提醒大家&#xff0c; AsyncContext是Servl…

python3.7下载tensorflow_【AI初体验】在anaconda中python3.7版本安装Tensorflow 与 Keras来玩玩...

哈啰&#xff0c;大家好&#xff0c; 单纯分享自己摸索学习AI的过程&#xff0c; 在自己的文章【Python 超入门】(1) 心原一马从零开始带你学程序中&#xff0c; 记录了安装撰写python的工具-anaconda 的方法&#xff0c; 当时安装的版本是python3.7版&#xff0c; 但是据说目前…

古巴平台上的通用过滤器–类固醇上的excel过滤器

正如我上次承诺的那样&#xff0c;我计划浏览该平台的某些功能&#xff0c;这些功能我认为非常有价值。 所以我将在这里做一些系列。 从明显的用户界面&#xff0c;过滤&#xff0c;安全性到一些高级功能&#xff08;如Web Portal&#xff0c;可扩展性&#xff0c;审核&#xf…

基准测试:Java 8 Lambda和流如何使您的代码慢5倍

与长期的实现相比&#xff0c;Java 8 lambda和流的性能如何&#xff1f; Lambda表达式和流在Java 8中受到了热烈的欢迎。这些是迄今为止很激动人心的功能&#xff0c;很长一段时间以来&#xff0c;它们就已经应用到Java中了。 新的语言功能使我们可以在代码中采用更具功能性的…

ssm框架逻辑删除mysql_MybatisPlus--CRUD接口及主键增长策略、自动填充、乐观锁更新数据...

目录一、insert1、插入操作2、主键策略二、update1、根据Id更新操作2、自动填充3、乐观锁三、select1、根据id查询记录2、通过多个id批量查询3、简单的条件查询4、分页四、delete1、根据id删除记录2、批量删除3、简单的条件查询删除4、逻辑删除一、insert1、插入操作RunWith(Sp…

python对英语的要求_学python需要英语基础吗

在很多人的眼里&#xff0c;学习编程需要英语基础&#xff0c;因为程序代码全是英文字母&#xff0c;如果没有英语基础可能很难学懂编程。程序代码是英文确实没有错&#xff0c;但是也不是必须得懂英语&#xff0c;因为计算机程序有自己语言&#xff0c;并不是我们生活中的英语…

python找不到csv文件_Python如何读取csv文件

逗号分隔值&#xff08;Comma-Separated Values&#xff0c;CSV&#xff0c;有时也称为字符分隔值&#xff0c;因为分隔字符也可以不是逗号&#xff09;&#xff0c;其文件以纯文本形式存储表格数据&#xff08;数字和文本&#xff09;。纯文本意味着该文件是一个字符序列&…

python cv2模块imshow_Python-OpenCV:cv2.imread(),cv2.imshow(),cv2.imwrite()

一、需要工具本机使用python 2.7.10下调试代码均通过&#xff0c;一下学习需要有一定的代码阅读能力&#xff0c;一下学习只介绍函数方法&#xff1a;Python 作为一种高效简洁的直译式语言非常适合我们用来解决日常工作的问题。而且它简单易学&#xff0c;初学者几个小时就可以…