SQLAlchemy(十)
ORM操作在实际项目中的应用非常多,涉及到的框架也是根据不同的项目有不同的处理模块,不过操作流程和步骤都是大同小异基本没有什么太大变化,唯一需要注意的就是在实际操作过程中你要使用的ORM框架的处理性能和是否支持事务、是否支持分布式等特性来进行确定使用哪个ORM框架进行操作,一般在python程序中ORM操作都是对mysqldb和pymysql这样的底层模块进行的封装处理。例如文章中要讲解的sqlalchemy就是底层封装mysqldb的实现,不过我们的在使用过程中需要使用pymysql进行替代。
1、安装
$ pip install sqlalchemy
安装完成之后,可以通过引入sqlalchemy进行版本查看,确认sqlalchemy是否安装成功

2、连接引擎
使用sqlalchemy进行数据库操作,首先我们需要建立一个指定数据库的连接引擎对象。建立引擎对象的方式被封装在了sqlalchemy.create_engine函数中,通过指定的数据库连接信息就可以进行创建。
创建数据库连接引擎时参数设置语法:
# 引入建立引擎的模块
from sqlalchemy import create_engine # pymsql创建引擎连接
# mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]
engine = create_engine("mysql+pymysql://root:123456@192.168.3.109:3306/test", encoding="utf-8", echo=True)
指定的数据库连接字符串表示了目标数据库的配置信息;encoding配置参数指定了和和数据库之间交换的数据的编码方式,同时echo参数表示随时在控制台展示和数据库之间交互的各种信息。
create_engine()函数返回的是sqlalchemy最核心的接口之一,该引擎对象会根据开发人员指定的数据库进行对应的sql api的调用处理。
3、连接会话
创建了数据库连接引擎对象之后,我们需要获取和指定数据库之间的连接,通过连接进行数据库中数据的增删改查操作,和数据库的连接我们称之为和指定数据库之间的会话。
我们使用 sessionmaker 方法创建session。
# 引入创建session连接会话的模块
from sqlalchemy.orm import sessionmaker # 创建一个连接会话对象;需要指定是和哪个数据库引擎之间的会话
Session = sessionmaker(bind=engine)
session = Session() # 如果在创建会话的时候没有指定数据库引擎,可以通过如下的方式完成引擎绑定操作
# Session = sessionmaker()
# Session.configure(bind=engine)
# session = Session()
此时的session不是线程安全的,并且我们一般session对象都是全局的,那么在多线程情况下,当多个线程共享一个session时,数据处理就会发生错误。为了保证线程安全,需使用scoped_session方法。
# 引入创建session连接会话的模块
from sqlalchemy.orm import sessionmaker, scoped_session # 创建一个连接会话对象;需要指定是和哪个数据库引擎之间的会话
Session = scoped_session(sessionmaker(bind=engine))
session = Session()
4、ORM之Object操作
我们的程序中的对象要使用sqlalchemy的管理,实现对象的orm操作,就需要按照框架指定的方式进行类型的创建操作,sqlalchemy封装了基础类的声明操作和字段属性的定义限制方式,开发人员要做的事情就是引入需要的模块并在创建对象的时候使用它们即可
基础类封装在sqlalchemy.ext.declarative.declarative_base模块中
字段属性的定义封装在sqlalchemy模块中,通过sqlalchemy.Column定义属性,通过封装的Integer、String、Float等定义属性的限制
常用的SQLAlchemy字段类型
| 类型名 | python中类型 | 说明 |
|---|---|---|
| Integer | int | 普通整数,一般是32位 |
| SmallInteger | int | 取值范围小的整数,一般是16位 |
| BigInteger | int或long | 不限制精度的整数 |
| Float | float | 浮点数 |
| Numeric | decimal.Decimal | 普通整数,一般是32位 |
| String | str | 变长字符串 |
| Text | str | 变长字符串,对较长或不限长度的字符串做了优化 |
| Unicode | unicode | 变长Unicode字符串 |
| UnicodeText | unicode | 变长Unicode字符串,对较长或不限长度的字符串做了优化 |
| Boolean | bool | 布尔值 |
| Date | datetime.date | 时间 |
| Time | datetime.datetime | 日期和时间 |
| LargeBinary | str | 二进制文件 |
常用的SQLAlchemy列选项
| 选项名 | 说明 |
|---|---|
| primary_key | 如果为True,代表表的主键 |
| unique | 如果为True,代表这列不允许出现重复的值 |
| index | 如果为True,为这列创建索引,提高查询效率 |
| nullable | 如果为True,允许有空值,如果为False,不允许有空值 |
| default | 为这列定义默认值 |
常用的SQLAlchemy关系选项
| 选项名 | 说明 |
|---|---|
| backref | 在关系的另一模型中添加反向引用 |
| primary join | 明确指定两个模型之间使用的联结条件 |
| uselist | 如果为False,不使用列表,而使用标量值 |
| order_by | 指定关系中记录的排序方式 |
| secondary | 指定多对多中记录的排序方式 |
| secondary join | 在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件 |
4.1 创建基础类
# 引入需要的模块
from sqlalchemy.ext.declarative import declarative_base # 创建基础类
BaseModel = declarative_base()
4.2 创建模型类
定义模型类必须继承自之前创建的基础类BaseModel,同时通过指定__tablename__确定和数据库中某个数据表之间的关联关系,指定某列类型为primary_key设定的主键,其他就是通过Column指定的自定义属性了。
sqlalchemy会根据指定的__tablename__和对应的Column列字段构建自己的accessors访问器对象,这个过程可以称为instrumentation,经过instrumentation映射的类型就可以进行数据库中数据的操作了。
# 引入需要的模块
from sqlalchemy import Column, String, Integer, ForeignKey # 创建模型类
class User(BaseModel):
# 定义表名
__tabelname__ = "tbl_user" # 创建字段类型
id = Column(Integer, primary_key=True)
name = Column(String(50))
age = Column(Integer) class Author(BaseModel):
__tablename__ = "tbl_author" id = Column(Integer, primary_key=True)
name = Column(String(50)) class Book(BaseModel):
__tablename__ = "tbl_book" id = Column(Integer, primary_key=True)
book_name = Column(String(50))
# ForeignKey 定义外键,需要导入
author_id = Column(Integer, ForeignKey("tbl_author.id"))
4.3 模型类映射操作
完成了模型类的定义之后,Declarative会通过python的metaclass对模型类进行操作,根据定义的模型类创建table对象,构建程序中类型和数据库table对象之间的映射mapping关系。
通过类型对象的metadata可以实现和数据库之间的交互,有需要时可以通过metadata发起create table操作,通过Base.metadata.create_all()进行操作,该操作会检查目标数据库中是否有需要创建的表,不存在的情况下创建对应的表。
# 删除所有模型类创建的表格(慎用)
BaseModel.metadata.drop_all(engine)
# 创建所有模型类的表格,有则不创建
BaseModel.metadata.create_all(engine)
5、数据的增、查、改、删
5.1 增
在程序代码中根据定义的数据类型创建对象的方式比较简单,创建对象并通过会话对象将数据对象持久化到数据库中。
# 增
user1 = User(name="张三", age=18)
user2 = User(name="李四", age=19)
user3 = User(name="王五", age=20)
# 将单个对象加入到会话对象中
session.add(user1)
# 将多个对象加入到会话对象中
session.add_all([user2, user3])
# 提交数据
session.commit()
5.2 查
Session是sqlalchemy和数据库交互的桥梁,Session提供了一个Query对象实现数据库中数据的查询操作
5.2.1 基础查询
查询所有数据
# 返回User对象所有字段的所有信息,返回结果为对象列表
session.query(User)
排序查询
# 指定排序查询
session.query(User).order_by(User.id) # 升序查询
session.query(User).order_by(-User.id) # 降序查询
session.query(User).order_by(-User.id, User.name) # 多条件排序查询
查询指定列
# 返回User对象字段为id和name的所有信息,返回结果为元组列表
session.query(User.id, User.name)
为字段取别名
# 为字段取别名
session.query(User.id, User.name.label("n"))
# 对应SQL语句:SELECT tbl_user.id AS tbl_user_id, tbl_user.name AS n FROM tbl_user
分页查询
# 使用limit()+offset()切片分页
# limit()限制返回条数
# offset()偏移
ret = session.query(User).limit(3).offset(2).all() # 返回第2条以后的3条数据,即第3至第5条数据
print(ret) # 使用slice()切片分页
ret = session.query(User).slice(2, 5).all() # 返回第3至第5条数据
print(ret) # 使用python列表切片分页
ret = session.query(User).all()[2:5] # 返回第3至第5条数据
print(ret)
分组查询
# 分组查询
session.query(User.name).group_by(User.name)
聚合函数
# 查询常用聚合函数
from sqlalchemy.sql import func
session.query(func.max(User.age), # 最大
func.min(User.age), # 最小
func.sum(User.age), # 求和
func.avg(User.age), # 平均
func.count(User.age) # 统计
)
去重
# 去重查询
from sqlalchemy import distinct
session.query(distinct(User.name))
5.2.2 条件筛选
在实际使用过程中经常用到条件查询,主要通过filter和filter_by进行操作,重点讲解使用最为频繁的filter条件筛选函数
等值条件_equals / not equals
# 等于
session.query(User).filter(User.name == "李四")
# 不等于
session.query(User).filter(User.name != "李四")
模糊条件_like/notlike
# 用户名包含“张”
session.query(User).filter(User.name.like("%张%"))
# 用户名不包含“张”
session.query(User).filter(User.name.notlike('%张%'))
范围条件_in / not in
# in
session.query(User).filter(User.id.in_([1, 2, 4])) # not in
session.query(User).filter(~User.id.in_([1, 2, 4]))
空值条件
# 空值
session.query(User).filter(User.name == None)
session.query(User).filter(User.name.is_(None)) # 非空
session.query(User).filter(User.name != None)
session.query(User).filter(User.name.isnot(None))
并且条件
from sqlalchemy import and_
session.query(User).filter(User.name == '张三').filter(User.age == 18)
session.query(User).filter(User.name == '张三', User.age == 18)
session.query(User).filter(and_(User.name == '张三', User.age == 18))
或者条件
from sqlalchemy import or_
session.query(User).filter(or_(User.name == '张三', User.name == '李四'))
5.2.3 多表查询
# 多表查询
session.query(Author.name, Book.book_name).filter(Author.id == Book.author_id)
# 对应SQL:SELECT tbl_author.name, tbl_book.book_name FROM tbl_author, tbl_book WHERE tbl_author.id = tbl_book.author_id # 内联查询join
session.query(Author.name, Book.book_name).join(Author, Author.id == Book.author_id)
# 对应SQL:SELECT tbl_author.name, tbl_book.book_name FROM tbl_book INNER JOIN tbl_author ON tbl_author.id = tbl_book.author_id # 左联查询outerjoin。没有右联查询
session.query(Author.name, Book.book_name).outerjoin(Author, Author.id == Book.author_id)
# 对应SQL:SELECT tbl_author.name, tbl_book.book_name FROM tbl_book LEFT OUTER JOIN tbl_author ON tbl_author.id = tbl_book.author_id # 并集查询
author_name = session.query(Author.name)
book_name = session.query(Book.book_name)
author_name.union(book_name)
# 对应SQL:SELECT anon_1.c_name FROM
# (SELECT tbl_author.name as c_name FROM tbl_author UNION SELECT tbl_book.book_name as c_name FROM tbl_book) AS anon_1
5.2.4 获取查询结果
获取查询对象有这么几种方法one(),all(),first(),one(),one_or_none(),scalar(),以及get()等。
下面对这几个方法的用法及效果做简单解释。
all()
返回查询到的所有的结果。
这个方法比较危险的地方是如果数据量大且没有使用limit子句限制的话,所有的结果都会加载到内存中。
它返回的是一个列表,如果查询不到任何结果,返回的是空列表。
ret = session.query(User).all()
print(ret) # [<__main__.User object at 0x0000000003894F60>, <__main__.User object at 0x00000000038942E8>]
first()
返回查询到的第一个结果,如果没有查询到结果,返回None。
ret = session.query(User).first()
print(ret) # <__main__.User object at 0x0000000003894358>
one()
如果只能查询到一个结果,返回它,否则抛出异常。
没有结果时抛sqlalchemy.orm.exc.NoResultFound,有超过一个结果时抛sqlalchemy.orm.exc.MultipleResultsFound。
ret = session.query(User).filter(User.id == 2).one()
print(ret) # <__main__.User object at 0x00000000038954A8>
one_or_none()
比起one()来,区别只是查询不到任何结果时不再抛出异常而是返回None。
ret = session.query(User).filter(User.id == 2).one_or_none()
print(ret) # <__main__.User object at 0x00000000038954A8>
scalar()
这个方法与.one_or_none()的效果一样。
如果查询到很多结果,抛出sqlalchemy.orm.exc.MultipleResultsFound异常。
如果只有一个结果,返回它,没有结果返回None。
ret = session.query(User).filter(User.id == 2).scalar()
print(ret) # <__main__.User object at 0x00000000038954A8>
get()
这是个比较特殊的方法。它用于根据主键来返回查询结果,因此它有个参数就是要查询的对象的主键。
如果没有该主键的结果返回None,否则返回这个结果。
ret = session.query(User).get(2)
print(ret) # <__main__.User object at 0x00000000038954A8>
当获取的结果为一个对象时,可以通过 对象.模型类属性 的方式取出值
user = session.query(User).get(2)
print(user) # <__main__.User object at 0x00000000038954A8>
print(user.name) # 李四
5.3 改
# update()更新数据
session.query(User).filter(User.id == 2).update({"name": "李四改"})
session.query(User).filter(User.id >= 4).update({"age": 88})
session.commit()
5.4 删
# delete()删除数据
session.query(User).filter(User.id == 2).delete()
session.query(User).filter(User.id >= 4).delete()
session.commit()
6、执行原生SQL语句
使用原生sql语句需要引入text方法,传入要执行的sql语句,若需要给sql语句传参,需要使用 :param 的方式定义参数名,然后使用 params() 并以键值对的方式传入值
from sqlalchemy import text
session.query(User).from_statement(text('select * from tbl_user where name=:name and age=:age')).params(name='李四', age=19)
session.query(User).from_statement(text('update tbl_user set name=:name where id=:id')).params(name='赵六', id=1)
session.commit()
还有一种类似于pymysql使用 execute() 执行原生sql的方法
ret = session.execute('select * from tbl_user where name=:name', {"name": "赵六"}).fetchall() # 所有数据以元组的形式保存在列表中
print(ret) # [(1, '赵六', 18, 2), (4, '赵六', 18, 2)]
ret = session.execute('select * from tbl_user where name=:name', {"name": "赵六"}).fetchone() # 返回第一条数据,无则为None
print(ret) # (1, '赵六', 18, 2)
附码:
# 引入建立引擎的模块
from sqlalchemy import create_engine
# 引入创建session连接会话的模块
from sqlalchemy.orm import sessionmaker, scoped_session
# 模型类需要使用的模块
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String, Integer, ForeignKey
# 数据操作的模块
from sqlalchemy import distinct, and_, or_
# 执行原生SQL的模块
from sqlalchemy import text # 1、pymsql创建引擎连接
# mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]
engine = create_engine("mysql+pymysql://root:123456@192.168.3.109:3306/test", encoding="utf-8", echo=True) # 2、创建一个连接会话对象;需要指定是和哪个数据库引擎之间的会话
Session = sessionmaker(bind=engine)
session = Session() # 如果在创建会话的时候没有指定数据库引擎,可以通过如下的方式完成引擎绑定操作
# Session = sessionmaker()
# Session.configure(bind=engine)
# session = Session() # 安全session
# Session = scoped_session(sessionmaker(bind=engine))
# session = Session() # 3、模型类
# 创建基础类
BaseModel = declarative_base() # 创建模型类
class User(BaseModel):
# 定义表名
__tabelname__ = "tbl_user" # 创建字段类型
id = Column(Integer, primary_key=True)
name = Column(String(50))
age = Column(Integer) class Author(BaseModel):
__tablename__ = "tbl_author" id = Column(Integer, primary_key=True)
name = Column(String(50)) class Book(BaseModel):
__tablename__ = "tbl_book" id = Column(Integer, primary_key=True)
book_name = Column(String(50))
# ForeignKey 定义外键,需要导入
author_id = Column(Integer, ForeignKey("tbl_author.id")) # 删除所有模型类创建的表格(慎用)
# BaseModel.metadata.drop_all(engine)
# 创建所有模型类的表格,有则不创建
BaseModel.metadata.create_all(engine) # 4、数据操作
# 增
user1 = User(name="张三", age=18)
user2 = User(name="李四", age=19)
user3 = User(name="王五", age=20)
# 将单个对象加入到会话对象中
session.add(user1)
# 将多个对象加入到会话对象中
session.add_all([user2, user3])
# 提交数据
session.commit() # 返回User对象所有字段的所有信息,返回结果为对象列表
session.query(User) # 指定排序查询
session.query(User).order_by(User.id) # 升序查询
session.query(User).order_by(-User.id) # 降序查询
session.query(User).order_by(-User.id, User.name) # 多条件排序查询 # 返回User对象字段为id和name的所有信息,返回结果为元组列表
session.query(User.id, User.name) # 为字段取别名
session.query(User.id, User.name.label("n"))
# 对应SQL语句:SELECT tbl_user.id AS tbl_user_id, tbl_user.name AS n FROM tbl_user # 分组查询
session.query(User.name).group_by(User.name) # 查询常用聚合函数
from sqlalchemy.sql import func
session.query(func.max(User.age), # 最大
func.min(User.age), # 最小
func.sum(User.age), # 求和
func.avg(User.age), # 平均
func.count(User.age) # 统计
) # 去重查询
session.query(distinct(User.name)) # 使用limit()+offset()切片分页
# limit()限制返回条数
# offset()偏移
ret = session.query(User).limit(3).offset(2).all() # 返回第2条以后的3条数据,即第3至第5条数据
print(ret) # 使用slice()切片分页
ret = session.query(User).slice(2, 5).all() # 返回第3至第5条数据
print(ret) # 使用python列表切片分页
ret = session.query(User).all()[2:5] # 返回第3至第5条数据
print(ret) # 等于
session.query(User).filter(User.name == "李四")
# 不等于
session.query(User).filter(User.name != "李四") # 用户名包含“张”
session.query(User).filter(User.name.like("%张%"))
# 用户名不包含“张”
session.query(User).filter(User.name.notlike('%张%')) # in
session.query(User).filter(User.id.in_([1, 2, 4]))
# not in
session.query(User).filter(~User.id.in_([1, 2, 4])) # 空值
session.query(User).filter(User.name == None)
session.query(User).filter(User.name.is_(None)) # 非空
session.query(User).filter(User.name != None)
session.query(User).filter(User.name.isnot(None)) # 并且
session.query(User).filter(User.name == '张三').filter(User.age == 18)
session.query(User).filter(User.name == '张三', User.age == 18)
session.query(User).filter(and_(User.name == '张三', User.age == 18)) # 或者
session.query(User).filter(or_(User.name == '张三', User.name == '李四')) # 多表查询
session.query(Author.name, Book.book_name).filter(Author.id == Book.author_id)
# 对应SQL:SELECT tbl_author.name, tbl_book.book_name FROM tbl_author, tbl_book WHERE tbl_author.id = tbl_book.author_id # 内联查询join
session.query(Author.name, Book.book_name).join(Author, Author.id == Book.author_id)
# 对应SQL:SELECT tbl_author.name, tbl_book.book_name FROM tbl_book INNER JOIN tbl_author ON tbl_author.id = tbl_book.author_id # 左联查询outerjoin。没有右联查询
session.query(Author.name, Book.book_name).outerjoin(Author, Author.id == Book.author_id)
# 对应SQL:SELECT tbl_author.name, tbl_book.book_name FROM tbl_book LEFT OUTER JOIN tbl_author ON tbl_author.id = tbl_book.author_id # 并集查询
author_name = session.query(Author.name)
book_name = session.query(Book.book_name)
author_name.union(book_name)
# 对应SQL:SELECT anon_1.c_name FROM
# (SELECT tbl_author.name as c_name FROM tbl_author UNION SELECT tbl_book.book_name as c_name FROM tbl_book) AS anon_1 # all()返回所有的数据
session.query(User).all() # first()返回查询到的第一个结果,如果没有查询到结果,返回None。
session.query(User).first() # one()如果只能查询到一个结果,返回它,否则抛出异常。
session.query(User).filter(User.id == 2).one() # one_or_none()比起one()来,区别只是查询不到任何结果时不再抛出异常而是返回None。
session.query(User).filter(User.id == 2).one_or_none() # scalar()这个方法与.one_or_none()的效果一样。
session.query(User).filter(User.id == 2).scalar() # get()这是个比较特殊的方法。它用于根据主键来返回查询结果,因此它有个参数就是要查询的对象的主键。如果没有该主键的结果返回None,否则返回这个结果。
session.query(User).get(2) # update()更新数据
session.query(User).filter(User.id == 2).update({"name": "李四改"})
session.query(User).filter(User.id >= 4).update({"age": 88})
session.commit() # delete()删除数据
session.query(User).filter(User.id == 2).delete()
session.query(User).filter(User.id >= 4).delete()
session.commit() # 执行原生SQL
session.query(User).from_statement(text('select * from tbl_user where name=:name and age=:age')).params(name='李四', age=19)
session.query(User).from_statement(text('update tbl_user set name=:name where id=:id')).params(name='赵六', id=1)
session.commit()
原文参考:https://blog.csdn.net/u012089823/article/details/94650310
SQLAlchemy(十)的更多相关文章
- 我的python开发目录模块连接
一.python语言 二.HTML 三.css 四.javascript 五.DOM 六.jquery 七.AJAX 八.WEB前端插件 九.自定义WEB框架 十.WEB框架之tornado 十一.M ...
- Python开发【十二章】:ORM sqlalchemy
一.对象映射关系(ORM) orm英文全称object relational mapping,就是对象映射关系程序,简单来说我们类似python这种面向对象的程序来说一切皆对象,但是我们使用的数据库却 ...
- 循序渐进Python3(十)-- 2 -- SqlAlchemy
ORM 对象关系映射(英语:Object Relation Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类 ...
- 循序渐进Python3(十)-- 3 -- SqlAlchemy
使用sqlalchemy 创建外键关联 ), ), ) host_user = Column(String(), ), ), ]).first()for item in works.workinfo: ...
- python【第十二篇下】操作MySQL数据库以及ORM之 sqlalchemy
内容一览: 1.Python操作MySQL数据库 2.ORM sqlalchemy学习 1.Python操作MySQL数据库 2. ORM sqlachemy 2.1 ORM简介 对象关系映射(英语: ...
- python运维开发(十二)----rabbitMQ、pymysql、SQLAlchemy
内容目录: rabbitMQ python操作mysql,pymysql模块 Python ORM框架,SQLAchemy模块 Paramiko 其他with上下文切换 rabbitMQ Rabbit ...
- python第六十六天--sqlalchemy
#!usr/bin/env python #-*-coding:utf-8-*- # Author calmyan #python #2017/7/6 21:29 #__author__='Admin ...
- python(十二)下:ORM框架SQLAlchemy使用学习
此出处:http://blog.csdn.net/fgf00/article/details/52949973 本节内容 ORM介绍 sqlalchemy安装 sqlalchemy基本使用 多外键关联 ...
- 第二百八十九节,MySQL数据库-ORM之sqlalchemy模块操作数据库
MySQL数据库-ORM之sqlalchemy模块操作数据库 sqlalchemy第三方模块 sqlalchemysqlalchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API ...
- 六十 数据库访问 使用SQLAlchemy
数据库表是一个二维表,包含多行多列.把一个表的内容用Python的数据结构表示出来的话,可以用一个list表示多行,list的每一个元素是tuple,表示一行记录,比如,包含id和name的user表 ...
随机推荐
- 【Service】【Database】【Cache】Redis
1. 简介: 1.1. redis == REmote DIctionary Server 1.2. KV cache and store, in-memory, 持久化,主从(sentinel实现一 ...
- 【Linux】【Basis】用户、组和权限管理
1. 概念: 1.1. 每个使用者都有,用户标识UID和密码:并且有身份(Authentication),授权(Authorization),审计(Audition):组(用户组,用户容器) 1.2. ...
- Non-terminating decimal expansion; no exact representable decimal result.
Non-terminating decimal expansion; no exact representable decimal result. 翻译为:非终止十进制扩展; 没有确切的可表示的小数 ...
- 基于Web的质量和测试度量指标
直观了解软件质量和测试的完整性 VectorCAST/Analytics可提供便于用户理解的web仪表盘视图来显示软件代码质量和测试完整性指标,让用户能够掌握单个代码库的趋势,或对比多个代码库的度量指 ...
- KrakenD url匹配通配符 url_pattern wildcard
KrakenD是一个高性能Api网关, api转发的推荐做法是每个api一个配置项,也就是一个endpoint,其开发者认为api网关和纯粹的L7路由不一样(文章链接). 因此社区版并没有提供通配符 ...
- SharedWorker实现多标签页联动计时器
web workers对于每个前端开发者并不陌生,在mdn中的定义:Web Worker为Web内容在后台线程中运行脚本提供了一种简单的方法.线程可以执行任务而不干扰用户界面.此外,他们可以使用XML ...
- 转:Android preference首选项框架
详解Android首选项框架ListPreference 探索首选项框架 在 深入探讨Android的首选项框架之前,首先构想一个需要使用首选项的场景,然后分析如何实现这一场景.假设你正在编写一个应用 ...
- 极简!一个注解就能创建Jaeger的Span
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- AT1381 エンド・オブ・ビギニング 题解
Content 有 \(n\) 组询问,每组询问给定三个字符串 \(s_1,s_2,s_3\). 如果 \(s_1\) 是 BEGINNING,输出 \(s_3\) 的第一个字符. 如果 \(s_1\ ...
- mysql联合查询更新数据库例子
mysql联合查询更新数据库例子,用户表,部门表,把用户表中的部门属性更新为部门表的主键UPDATE user_table AS utINNER JOIN belongdept AS bd ON bd ...