Flask-SQLAlchemy

news2024/7/4 5:59:54

认识Flask-SQLAlchemy

  1. Flask-SQLAlchemy 是一个为 Flask 应用增加 SQLAlchemy 支持的扩展。它致力于简化在 Flask 中 SQLAlchemy 的使用。
  2. SQLAlchemy 是目前python中最强大的 ORM框架, 功能全面, 使用简单。

ORM优缺点
优点

  1. 有语法提示, 省去自己拼写SQL,保证SQL语法的正确性
  2. orm提供方言功能(dialect, 可以转换为多种数据库的语法), 减少学习成本
  3. 防止sql注入攻击
  4. 搭配数据迁移, 更新数据库方便
  5. 面向对象, 可读性强, 开发效率高

缺点

  1. 需要语法转换, 效率比原生sql低
  2. 复杂的查询往往语法比较复杂 (可以使用原生sql替换)

环境安装

pip install flask-sqlalchemy

flask-sqlalchemy 在安装/使用过程中, 如果出现 ModuleNotFoundError: No module named 'MySQLdb’错误, 则表示缺少mysql依赖包, 可依次尝试下列两个方案后重试:
方案1: 安装 mysqlclient依赖包 (如果失败再尝试方案2)

pip install mysqlclient

方案2: 安装pymysql依赖包

pip install pymysql

mysqlclient 和 pymysql 都是用于mysql访问的依赖包, 前者由C语言实现的, 而后者由python实现, 前者的执行效率比后者更高, 但前者在windows系统中兼容性较差, 工作中建议优先前者。

组件初始化
基本配置

flask-sqlalchemy 的相关配置也封装到了 flask 的配置项中, 可以通过app.config属性 或 配置加载方案 (如config.from_object) 进行设置


数据库URI(连接地址)格式: 协议名://用户名:密码@数据库IP:端口号/数据库名, 如:
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test31'

注意点如果数据库驱动使用的是 pymysql, 则协议名需要修改为
mysql+pymysql://xxxxxxx
 

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# 设置数据库连接地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test31'
# 是否追踪数据库修改(开启后会触发一些钩子函数)  一般不开启, 会影响性能
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 是否显示底层执行的SQL语句
app.config['SQLALCHEMY_ECHO'] = True


两种初始化方式
.方式1
flask-sqlalchemy 支持两种组件初始化方式:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# 应用配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test31'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True

# 方式1: 初始化组件对象, 直接关联Flask应用
db = SQLAlchemy(app)


方式2: 先创建组件, 延后关联Flass应用

from flask import Flask
from flask_sqlalchemy import SQLAlchemy


# 方式2: 初始化组件对象, 延后关联Flask应用
db = SQLAlchemy()


def create_app(config_type):
    """工厂函数"""

    # 创建应用
    flask_app = Flask(__name__)
    # 加载配置
    config_class = config_dict[config_type]
    flask_app.config.from_object(config_class)

    # 关联flask应用
    db.init_app(app)

    return flask_app


构建模型类

flask-sqlalchemy 的关系映射和 Django-orm 类似

类 对应 表
类属性 对应 字段
实例对象 对应 记录

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import os
import pymysql as MySQLdb

basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:yu201541010@127.0.0.1:3306/pythontest'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True

# 创建组件对象
db = SQLAlchemy(app)


# 构建模型类  类->表  类属性->字段  实例对象->记录
class User(db.Model):
    __tablename__ = 't_user'  # 设置表名, 表名默认为类名小写
    id = db.Column(db.Integer, primary_key=True)  # 设置主键, 默认自增
    name = db.Column('username', db.String(20), unique=True)  # 设置字段名 和 唯一约束
    age = db.Column(db.Integer, default=10, index=True)  # 设置默认值约束 和 索引

with app.app_context():
    db.create_all()

if __name__ == '__main__':
    app.run(debug=True)


注意点

  1. 模型类必须继承 db.Model, 其中 db 指对应的组件对象
  2. 表名默认为类名小写, 可以通过 __tablename__类属性 进行修改
  3. 类属性对应字段, 必须是通过 db.Column() 创建的对象
  4. 可以通过 create_all() 和 drop_all()方法 来创建和删除所有模型类对应的表常用的字段类型

常用的字段选项


注意点: 如果没有给对应字段的类属性设置default参数, 且添加数据时也没有给该字段赋值, 则sqlalchemy会给该字段设置默认值 None

 

数据操作
增加数据

@app.route('/')
def index():
    # 增加数据
    user1 = User(name = 'zs', age = 20)
    #将模型对象添加到会话中
    db.session.add(user1)
    db.session.commit()
    return "index"


注意点:

这里的 会话 并不是 状态保持机制中的 session,而是 sqlalchemy 的会话。它被设计为 数据操作的执行者, 从SQL角度则可以理解为是一个 加强版的数据库事务
sqlalchemy 会 自动创建事务, 并将数据操作包含在事务中, 提交会话时就会提交事务
事务提交失败会自动回滚
查询数据

class Users(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
    email = db.Column(db.String(64))
    age = db.Column(db.Integer)
    def __repr__(self):
        return "(%s, %s, %s, %s)" % (self.id, self.name, self.email, self.age)
@app.route('/createusers')
def createusers():
    user1 = Users(name='wang', email='wang@163.com', age=20)
    user2 = Users(name='zhang', email='zhang@189.com', age=33)
    user3 = Users(name='chen', email='chen@126.com', age=23)
    user4 = Users(name='zhou', email='zhou@163.com', age=29)
    user5 = Users(name='tang', email='tang@itheima.com', age=25)
    user6 = Users(name='wu', email='wu@gmail.com', age=25)
    user7 = Users(name='qian', email='qian@gmail.com', age=23)
    user8 = Users(name='liu', email='liu@itheima.com', age=30)
    user9 = Users(name='li', email='li@163.com', age=28)
    user10 = Users(name='sun', email='sun@163.com', age=26)
    db.session.add_all([user1, user2, user3, user5, user4, user6, user7, user8,user9,user10])
    db.session.commit()
    return "success"
@app.route('/query')
def query():
    user = Users.query.first()
    return user.name+" "+user.email


# 查询所有用户数据
User.query.all() 返回列表, 元素为模型对象

# 查询有多少个用户
User.query.count()

# 查询第1个用户
User.query.first()  返回模型对象/None

# 查询id为4的用户[3种方式]
# 方式1: 根据id查询  返回模型对象/None
User.query.get(4)  

# 方式2: 等值过滤器 关键字实参设置字段值  返回BaseQuery对象
# BaseQuery对象可以续接其他过滤器/执行器  如 all/count/first等
User.query.filter_by(id=4).all()  

# 方式3: 复杂过滤器  参数为比较运算/函数引用等  返回BaseQuery对象
User.query.filter(User.id == 4).first()  

# 查询名字结尾字符为g的所有用户[开始 / 包含]
User.query.filter(User.name.endswith("g")).all()
User.query.filter(User.name.startswith("w")).all()
User.query.filter(User.name.contains("n")).all()
User.query.filter(User.name.like("w%n%g")).all()  # 模糊查询

# 查询名字和邮箱都以li开头的所有用户[2种方式]
User.query.filter(User.name.startswith('li'), User.email.startswith('li')).all()
from sqlalchemy import and_
User.query.filter(and_(User.name.startswith('li'), User.email.startswith('li'))).all()

# 查询age是25 或者 `email`以`itheima.com`结尾的所有用户
from sqlalchemy import or_
User.query.filter(or_(User.age==25, User.email.endswith("itheima.com"))).all()

# 查询名字不等于wang的所有用户[2种方式]
from sqlalchemy import not_
User.query.filter(not_(User.name == 'wang')).all()
User.query.filter(User.name != 'wang').all()

# 查询id为[1, 3, 5, 7, 9]的用户
User.query.filter(User.id.in_([1, 3, 5, 7, 9])).all()

# 所有用户先按年龄从小到大, 再按id从大到小排序, 取前5个
User.query.order_by(User.age, User.id.desc()).limit(5).all()

# 查询年龄从小到大第2-5位的数据   2 3 4 5
User.query.order_by(User.age).offset(1).limit(4).all()

# 分页查询, 每页3个, 查询第2页的数据  paginate(页码, 每页条数)
pn = User.query.paginate(2, 3)
pn.pages 总页数  pn.page 当前页码 pn.items 当前页的数据  pn.total 总条数

# 查询每个年龄的人数    select age, count(name) from t_user group by age  分组聚合
from sqlalchemy import func
data = db.session.query(User.age, func.count(User.id).label("count")).group_by(User.age).all()
for item in data:
    # print(item[0], item[1])
    print(item.age, item.count)  # 建议通过label()方法给字段起别名, 以属性方式获取数据


# 只查询所有人的姓名和邮箱  优化查询   User.query.all()  # 相当于select *
from sqlalchemy.orm import load_only
data = User.query.options(load_only(User.name, User.email)).all()  # flask-sqlalchem的语法
for item in data:
    print(item.name, item.email)

data = db.session.query(User.name, User.email).all()  # sqlalchemy本体的语法
for item in data:
    print(item.name, item.email)

更新数据
flask-sqlalchemy 提供了两种更新数据的方案 

先查询, 再更新
对应SQL中的 先select, 再update
基于过滤条件的更新 (推荐方案)
对应SQL中的 update xx where xx = xx (也称为 update子查询 )
先查询, 再更新
这种方式的缺点

查询和更新分两条语句, 效率低
如果并发更新, 可能出现更新丢失问题(Lost Update)

class Goods(db.Model):
    __tablename__ = 't_good'
    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(20), unique=True)
    count = db.Column(db.Integer)
@app.route('/addgood')
def addgood():
    goods = Goods(name='方便面', count=10)
    db.session.add(goods)
    db.session.commit()
    return "success"
@app.route('/updategood')
def updategood():
    goods = Goods.query.filter(Goods.name=='方便面').first()
    goods.count = goods.count - 1
    db.session.commit()
    return "success"


基于过滤条件的更新
这种方式的优点:

一条语句, 被网络IO影响程度低, 执行效率更高
查询和更新在一条语句中完成, 单条SQL具有原子性, 不会出现更新丢失问题
会对满足过滤条件的所有记录进行更新, 可以实现批量更新处理
操作步骤如下:

配合 查询过滤器filter() 和 更新执行器update() 进行数据更新
提交会话

@app.route('/updategood2')
def updategood2():
    Goods.query.filter(Goods.name=='方便面').update({'count':Goods.count-1})
    db.session.commit()
    return "success"


删除数据
类似更新数据, 也存在两种删除数据的方案
先查询, 再删除

对应SQL中的 先select, 再delete
基于过滤条件的删除 (推荐方案)

对应SQL中的 delete xx where xx = xx (也称为 delete子查询 )
这种方式的缺点:

查询和删除分两条语句, 效率低

@app.route('/deletegood')
def deletegood():
    goods = Goods.query.filter(Goods.name=='方便面').first()
    db.session.delete(goods)
    db.session.commit()
    return "success"


基于过滤条件的删除
这种方式的优点:

一条语句, 被网络IO影响程度低, 执行效率更高
会对满足过滤条件的所有记录进行删除, 可以实现批量删除处理
操作步骤如下:

配合 查询过滤器filter() 和 删除执行器delete() 进行数据删除
提交会话

@app.route('/deletegood2')
def deletegood2():
    Goods.query.filter(Goods.name=='方便面').delete()
    db.session.commit()
    return "success"


增删改操作都需要提交会话, 对应事务中进行数据库变化后提交事务
刷新数据
Session 被设计为数据操作的执行者, 会先将操作产生的数据保存到内存中
在执行 flush刷新操作 后, 数据操作才会同步到数据库中
有两种情况下会 隐式执行刷新操作
提交会话
执行查询操作 (包括 update 和 delete 子查询)
开发者也可以 手动执行刷新操作 session.flush()
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# 相关配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test31'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)


# 构建模型类  
class Goods(db.Model):
    __tablename__ = 't_good'  
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(20), unique=True) 
    count = db.Column(db.Integer)  


@app.route('/')
def purchase():

    goods = Goods(name='方便面', count=20)
    db.session.add(goods)
    # 主动执行flush操作, 立即执行SQL操作(数据库同步)
    db.session.flush()

    # Goods.query.count()  # 查询操作会自动执行flush操作
    db.session.commit()  # 提交会话会自动执行flush操作

    return "index"


if __name__ == '__main__':
    db.drop_all()
    db.create_all()

    app.run(debug=True)

多表查询

案例中包含两个模型类: User用户模型 和 Address地址模型, 并且一个用户可以有多个地址, 两张表之间存在一对多关系

class Address(db.Model):
    __tablename__='t_adr'
    id = db.Column(db.Integer, primary_key=True)
    detail = db.Column(db.String(20))
    user_id = db.Column(db.Integer)
@app.route('/addadr')
def addadr():
    adr1 = Address(detail='中关村3号', user_id=1)
    adr2 = Address(detail='华强北5号', user_id=1)
    db.session.add_all([adr2, adr1])
    db.session.commit()
    return "success"


关联查询
关联查询步骤: (以主查从为例)

先查询主表数据
再通过外键字段查询 关联的从表数据

@app.route('/queryadr')
def queryadr():
    user1 = User.query.filter_by(name='zs').first()
    adrs = Address.query.filter_by(user_id=user1.id).all()
    for adr in adrs:
        print(adr.detail)
    return "success"


连接查询

开发中有 联表查询需求 时, 一般会使用 join连接查询
sqlalchemy 也提供了对应的查询语法
db.session.query(主表模型字段1, 主表模型字段2, 从表模型字段1, xx.. ).join(从表模型类, 主表模型类.主键 == 从表模型类.外键)
1
join语句 属于查询过滤器, 返回值也是 BaseQuery 类型对象

@app.route('/queryadr2')
def queryadr2():
    data = db.session.query(User.id, Address.detail).join(Address, User.id==Address.user_id).filter(User.name=='zs').all()
    for item in data:
        print(item.detail, item.id)
    return "success"


关联查询的性能优化

通过前边的学习, 可以发现 无论使用 外键 还是 关系属性 查询关联数据, 都需要查询两次, 一次查询用户数据, 一次查询地址数据
两次查询就需要发送两次请求给数据库服务器, 如果数据库和web应用不在一台服务器中, 则 网络IO会对查询效率产生一定影响
可以考虑使用 连接查询 join 使用一条语句就完成关联数据的查询
# 使用join语句优化关联查询
adrs = Address.query.join(User, Address.user_id == User.id).filter(User.name == '张三').all()  # 列表中包含地址模型对象

Session机制
生命周期
flask-sqlalchemy 对于 sqlalchemy本体 的 Session 进行了一定的封装:
Session的生命周期和请求相近 

请求中的首次数据操作会创建Session
整个请求过程中使用的Session为同一个, 并且线程隔离
请求结束时会自动销毁Session(释放内存)


Session和事务

Session中可以包含多个事务, 提交事务失败后, 会自动执行SQL的回滚操作
同一个请求中, 想要在前一个事务失败的情况下创建新的事务, 必须先手动回滚事务 Session.rollback
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# 相关配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/toutiao'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)


# 构建模型类 
class User(db.Model):
    __tablename__ = 't_user'  
    id = db.Column(db.Integer, primary_key=True)  
    name = db.Column('username', db.String(20), unique=True) 
    age = db.Column(db.Integer, default=0, index=True)  


@app.route('/')
def index():

    """事务1"""
    try:
        user1 = User(name='zs', age=20)
        db.session.add(user1)
        db.session.commit()
    except BaseException:
        # 手动回滚   同一个session中, 前一个事务如果失败, 必须手动回滚, 否则无法创建新的事务
        db.session.rollback()

    """事务2"""
    user1 = User(name='lisi', age=30)
    db.session.add(user1)
    db.session.commit()

    return "index"


if __name__ == '__main__':
    """为了进行测试, 首次运行 建表并添加一条测试数据后, 注释下方代码, 并重新运行测试"""

    # 重置所有继承自db.Model的表
    # db.drop_all()
    # db.create_all()

    # 添加一条测试数据
    # user1 = User(name='zs', age=20)
    # db.session.add(user1)
    # db.session.commit()

    app.run(debug=True)

数据迁移


flask-migrate组件 为flask-sqlalchemy提供了数据迁移功能, 以便进行数据库升级, 如增加字段、修改字段类型等
安装组件 pip install flask-migrate

# hm_数据迁移.py 

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:yu201541010@127.0.0.1:3306/pythontest'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)
#迁移组件初始化
Migrate(app, db)
class User(db.Model):
    __tablename__ ='t_user'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column('username', db.String(20), unique=True)

@app.route('/')
def index():
    return "index"

if __name__ =='__main__':
    app.run()


执行迁移命令

终端进入当前文件目录下,注意export命令后面等号不能有空格

  1. export FLASK_APP=hm_数据迁移.py  # 设置环境变量指定启动文件
  2. flask db init  # 生成迁移文件夹  只执行一次
  3. flask db migrate  # ⽣成迁移版本, 保存到迁移文件夹中
  4. flask db upgrade  # 执行迁移


执行迁移命令前需要先设置环境变量指定启动文件

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

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

相关文章

誉天HCIP-Datacom课程简介

HCIP-Datacom课程介绍:HCIP-Datacom分为一个核心技术方向:HCIP-Datacom-Core Technology H12-821 (核心技术)六个可选子方向:HCIP-Datacom-Advanced Routing & Switching Technology H12-831 (高级路…

ubuntu设置共享文件夹成功后却不显示找不到(已解决)

1.首先输下面命令查看是否真的设置成功共享文件夹 vmware-hgfsclient如果确实已经设置过共享文件夹将输出window下共享文件夹名字 2.确认自己已设置共享文件夹后输入下面的命令 //如果之前没有命令包则先执行sudo apt-get install open-vm-tools sudo vmhgfs-fuse .host:/ /mn…

Ubuntu18.04.4裸机配置

下载虚拟机Ubuntu18.04.4 链接:https://pan.baidu.com/s/1jyucyUSXa9-Fw9ctuU87hA 提取码:o42a –来自百度网盘超级会员V5的分享 VMware选择镜像安装 设置你的用户名,就像windows上登录用户一样简单 下一步……下一步……如此简单 下载…

《Effects of Graph Convolutions in Multi-layer Networks》阅读笔记

一.文章概述 本文研究了在XOR-CSBM数据模型的多层网络的第一层以上时,图卷积能力的基本极限,并为它们在数据中信号的不同状态下的性能提供了理论保证。在合成数据和真实世界数据上的实验表明a.卷积的数量是决定网络性能的一个更重要的因素,而…

TiDB数据库从入门到精通系列之一:TiDB数据库的软硬件环境要求和系统配置检查

TiDB数据库从入门到精通系列之一:TiDB数据库的软硬件环境要求和系统配置检查 一、软件和硬件配置要求1.操作系统及平台要求2.服务器建议配置3.网络要求4.磁盘空间要求 二、TiDB 环境与系统配置检查1.在 TiKV 部署目标机器上添加数据盘 EXT4 文件系统挂载参数2.设置 …

ECOLOGY9实现正文文档按发布范围授权查看

需求:E9流程需要流程归档后,正文文档按发布范围授权查看,不需要是流程参与者。 解决:表单中定义发布范围是人力资源条件 在流程基础设置-功能设置中设置启用按人力资源 条件字段赋权。 实现的效果。

司徒理财:8.15黄金美盘多空最新操作建议

黄金一直没能跌破1902的支撑,司徒理财依旧维持低多看涨的思路不变,早盘1905多单继续持有中,静待美盘拉升!黄金现在的下跌力度已经衰竭,并且日线上已经跌至200日均线的支撑位置,大周期的均线支撑&#xff0c…

WSL2 ubuntu子系统OpenCV调用本机摄像头的RTSP视频流做开发测试

文章目录 前言一、Ubuntu安装opencv库二、启动 Windows 本机的 RTSP 视频流下载解压 EasyDarwin查看本机摄像头设备开始推流 三、在ubuntu 终端编写代码创建目录及文件创建CMakeLists.txt文件启动 cmake 配置并构建 四、结果展示启动图形界面在图形界面打开终端找到 rtsp_demo运…

阿里云与中国中医科学院合作,推动中医药行业数字化和智能化发展

据相关媒体消息,阿里云与中国中医科学院的合作旨在推动中医药行业的数字化和智能化发展。随着互联网的进步和相关政策的支持,中医药产业受到了国家的高度关注。这次合作将以“互联网 中医药”为载体,致力于推进中医药文化的传承和创新发展。…

PDB Database - 高质量 RCSB PDB 蛋白质结构筛选与过滤

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/132307119 Protein Data Bank (PDB) 是一个收集和存储三维结构数据的公共数据库,主要包括蛋白质和核酸分子。PDB 由美国、欧洲和日本三…

机器学习深度学习——机器翻译(序列生成策略)

👨‍🎓作者简介:一位即将上大四,正专攻机器学习的保研er 🌌上期文章:机器学习&&深度学习——seq2seq实现机器翻译(详细实现与原理推导) 📚订阅专栏:机…

卡车盲区监测+360全景

一、背景分析 1.AI视觉智能终端的ADAS主动防撞告警、DMS驾驶员异常行为告警功能。通过摄像头和人工智能算法对前方车辆、车道、交通场景进行检测识别,再结合对车辆运动状态和驾驶员行为的分析,有效预测ADAS前车碰撞、车道偏离等危险,并对DMS…

pytorch3d成功安装

一、pytorch3d是什么? PyTorch3D的目标是帮助加速深度学习和3D交叉点的研究。3D数据比2D图像更复杂,在从事Mesh R-CNN和C3DPO等项目时,我们遇到了一些挑战,包括3D数据表示、批处理和速度。我们开发了许多有用的算子和抽象&#xf…

好用画流程图软件推荐 excalidraw

作者:明明如月学长, CSDN 博客专家,蚂蚁集团高级 Java 工程师,《性能优化方法论》作者、《解锁大厂思维:剖析《阿里巴巴Java开发手册》》、《再学经典:《EffectiveJava》独家解析》专栏作者。 热门文章推荐…

《Zookeeper》源码分析(十一)之选举通信网络辅助类

目录 Listener数据结构构造函数run() ListenerHandler数据结构run() SendWorker数据结构构造函数run() RecvWorker数据结构run() Listener Listener用于管理服务器的选举端口。 数据结构 构造函数 run() Listener的主要工作是创建一系列的ListenerHandler并将他们投放到线程池…

无线充电底座

<项目>无线充电器 前言 个人DIY的无线充电底座&#xff08;带磁吸&#xff09;&#xff0c;基于IP6829方案。 Drawn By:67373 硬件部分 3D模型 资料开源链接 https://github.com/linggan17/WirelessCharge

03-循环和关系表达式

循环和关系表达式 5.1、for循环 例子 // forloop.cpp -- introducing the for loop #include <iostream> int main() {using namespace std;int i; // create a counter // initialize; test ; updatefor (i 0; i < 5; i)cout << "C knows loops.\n…

从零开始学习VBA(一)

前置配置设置 首先配置开发设置&#xff08;不同版本的配置方法会有差异&#xff0c;可根据自己使用的EXCEL版本到网络上找对应的方法&#xff0c;比如直接搜索Excel2010 开发工具&#xff09; 以下为excel2016配置方法&#xff1a; 操作路径&#xff1a;文件-选项-自定义功…

1269. 停在原地的方案数

链接&#xff1a; ​​​​​​1269. 停在原地的方案数 题解&#xff1a;坐标型动态规划 class Solution { public:int numWays(int steps, int arrLen) {if (arrLen < 0) {return 0;}// 因为需要返回到0下标位置所以&#xff0c;最远也就是一半int len std::min(steps/…

【福建事业单位-公共基础-】01哲学基本概述和唯物论

【福建事业单位-公共基础-】01哲学基本概述和唯物论 一、哲学基本概述二、辩证唯物论&#xff08;1题&#xff09; 相关考点 一、哲学基本概述 向导、导向、指导&#xff0c;都是中性词&#xff0c;都可以&#xff1b;但是先导是褒义词&#xff0c;要跟上真正的哲学&#xff1…