使用 sqlalchemy one() 函数可以从数据库引擎返回多行吗?

With sqlalchemy one() function can more than one row be returned from the database engine?

来自文档:

Return exactly one result or raise an exception.

这是函数调用。我想知道的是,如果数据库引擎是 运行 通过 tcp 通信的其他地方(例如),机器 运行 SQLAlchemy 应用程序是否可以接收到多个结果?

我认为这将独立于 DB,但如果不是这种情况,我的问题是针对 hana DB。

can the machine running the sqlalchemy application ever receive more than one result?

是的。通过 mysql+mysqlclient.

确认

示例数据:

class Message(Base):
    __tablename__ = "message"
    id = sa.Column(sa.Integer, primary_key=True)
    data = sa.Column(sa.String(50), nullable=False)

    def __repr__(self):
        return f"<Message(id={self.id}, data='{self.data}')>"


Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)

with sa.orm.Session(engine, future=False) as session:
    session.add_all([Message(data="Alfa"), Message(data="Bravo")])
    session.commit()

测试查询:

with sa.orm.Session(engine) as session:
    result = session.query(Message).one()

Wireshark 数据包:

0000   40 2c f4 34 c0 d3 00 21 70 75 83 c1 08 00 45 00   @,.4...!pu....E.
0010   00 ca 2d ec 40 00 3f 06 8a 77 c0 a8 00 c7 c0 a8   ..-.@.?..w......
0020   00 b3 0c ea ef 75 ab 6d 1c 34 2a ae cc 7b 50 18   .....u.m.4*..{P.
0030   01 f5 91 aa 00 00 01 00 00 01 02 34 00 00 02 03   ...........4....
0040   64 65 66 04 74 65 73 74 07 6d 65 73 73 61 67 65   def.test.message
0050   07 6d 65 73 73 61 67 65 0a 6d 65 73 73 61 67 65   .message.message
0060   5f 69 64 02 69 64 0c 3f 00 0b 00 00 00 03 03 42   _id.id.?.......B
0070   00 00 00 38 00 00 03 03 64 65 66 04 74 65 73 74   ...8....def.test
0080   07 6d 65 73 73 61 67 65 07 6d 65 73 73 61 67 65   .message.message
0090   0c 6d 65 73 73 61 67 65 5f 64 61 74 61 04 64 61   .message_data.da
00a0   74 61 0c ff 00 c8 00 00 00 fd 01 10 00 00 00 05   ta..............
00b0   00 00 04 fe 00 00 21 00 07 00 00 05 01 31 04 41   ......!......1.A
00c0   6c 66 61 08 00 00 06 01 32 05 42 72 61 76 6f 05   lfa.....2.Bravo.
00d0   00 00 07 fe 00 00 21 00                           ......!.

请注意,这两行都 return 在同一个数据包中编辑。因此,在这种情况下,即使 SQLAlchemy 使用 .fetchone(),数据库也可能 return 多行(如 中所述:数据库可能未配置或无法配置为仅 return 一次一行)。

所以,至少对于默认的 MySQL 配置,.one() 不限制 rows/objects returned 的数量,它只验证我们确实收到了一个他们中的。这就是我们得到异常的原因

sqlalchemy.exc.MultipleResultsFound: Multiple rows were found when exactly one was required

幕后Query.one()uses a "fetch one" approach,但这还不是故事的全部。您的客户端是否首先缓冲整个查询结果取决于您使用的驱动程序和 DBMS——例如它是否支持服务器端游标。

此外,SQLAlchemy Query 删除了单个 ORM 实体结果的重复数据,例如

session.query(MyModel).one()

为了做到这一点,它必须继续读取结果集,直到它找到一个非唯一的结果,在这种情况下它会引发异常,或者没有更多的结果。有人可能想知道什么时候甚至会有这样的重复,答案是“使用连接时”:

session.query(MyModel).join(MyModelChild).one()

最终结果是它必须读取整个结果集,或者如果使用 ORM 和 Query API 或 [=17=,则最多读取第一个非唯一结果] 2.0 风格 API.