首页 >> 行情 >> PolarDB-X 源码解读:公共事务的一生

PolarDB-X 源码解读:公共事务的一生

2025-09-05 12:16:40

BEGIN

与 MySQL 相似,要带入一个政务,一般有两种理论。第一种理论是显式地监督 BEGIN 或 START TRANSACTION [transaction_characteristic],监督这两种运算符,亦会codice_ ServerConnection 中都的 begin(boolean, IsolationLevel) 理论。第二种理论是监督 SET autocommit = 0,当在此之前 session 亦会隐式带入政务,这种理论亦会codice_ ServerConnection 中都的 setAutocommit(boolean, boolean) 理论。两种理论都亦会codice_ TConnection 的 setAutoCommit 理论。这些理论都只是恰当地记录下来了一些codice_(比如 transaction_characteristic 中都设定的政务特别codice_),同时标识这个通到带入了政务。此时,政务普通人也还不想建立出新来,也不想与后尾端通到同步进行任何交互。

念书移位 0

在带入政务后,监督 SELECT * FROM tb1 WHERE id = 0 时,才亦会真正建立政务普通人。根据政务与通到中都的提问,在 TConnection 中都这条命题 SQL 的监督门廊为 executeSQL,里亦会真正建立政务普通人,亦然要监督命题为(code出新自 PolarDB-X 5.4.12 release 版本,为了有效率说道明,有引起争议及更动,另加):

// TConnection#executeSQL(ByteString, Parameters, TStatement, ExecutionContext)

public ResultSet executeSQL(ByteString sql, Parameters params, TStatement stmt,

ExecutionContext executionContext) throws SQLException {

if (this.trx == null || this.trx.isClosed()) {

// 带入政务后,直到监督第一条运算符,才亦会建立政务普通人。

beginTransaction();

}

// 让 executionContext 摘录 trx 普通人,有效率早先以监督器通过 trx 普通人拿物理化学通到。

executionContext.setTransaction(this.trx);

resultCursor = executeQuery(sql, executionContext, trxPolicyModified);

}

// TConnection#beginTransaction(boolean)

private void beginTransaction(boolean autoCommit) {

// 根据一些默认的或服务器设定的政务codice_,同样合适的政务思路,比如 TSO/XA 等。

trxPolicy = loadTrxPolicy(executionContext);

TransactionClass trxConfig = trxPolicy.getTransactionType(autoCommit, readOnly);

// 根据政务思路,建立出新完全并不相同的政务普通人。

this.trx = transactionManager.createTransaction(trxConfig, executionContext);

}

在我们的范唯中都,如果在上述code打个断点,可以看不到建立出新来的是 TsoTransaction,其中都一些很多人瞩目的codice_为:

trx = {TsoTransaction}

// 此时还不想提供任何短时间碰。

snapshotTimestamp = -1

commitTimestamp = -1

// 政务写到的第一个物理化学移位(下称亦然移位),政务亦会话将亦会写到在这个移位上。

primaryGroup = null

// 该政务究竟跨移位,如果是单移位政务,亦会可用性为一阶段性提出新。

isCrossGroup = false

// 政务亦会话GNOME,全权负责写到政务亦会话。

globalTxLogManager = {GlobalTxLogManager}

// 分布式政务的 connectionHolder 都是 TransactionConnectionHolder,

// 里分别存储了念书写到通到,念书通到和写到通到在提出新时行为亦会有所多种不同。

connectionHolder = {TransactionConnectionHolder}

// 物理化学移位到完全并不相同写到通到的映射。

groupHeldWriteConn = {HashMap}

// 物理化学移位到完全并不相同念书通到集合到映射。在 ShareReadView 可用性带入时,

// 可以同时存有多个念书通到和一个写到通到,因此这里念书写到通到无需从在此之前管理机构。

// 该可用性不论如何本文则展开。

groupHeldReadConns = {HashMap}

在监督器阶段性,亦会同样给移位 0 下发一条 SELECT 运算符,此时无需提供移位 0 的物理化学通到,code门廊是 MyJdbcHandler 中都的 getPhyConnection(ITransaction, ITransaction.RW, String, DataSource) 理论。其中都的政务普通人 Transaction 则都有 ExecutionContext 里抢到。该理论就此亦会codice_ AbstractTransaction (这是所有分布式政务类的派生类)中都的 getConnection 理论。

通过政务拿物理化学通到的code AbstractTransaction#getConnection 如下:

// AbstractTransaction#getConnection(String, String, IDataSource, RW, ExecutionContext)

public IConnection getConnection(String schema, String group, IDataSource ds, RW rw, ExecutionContext ec) {

if (/* 是政务的第一个写到请 */) {

// 把这个移位作为亦然移位,政务亦会话将写到在这个移位上。

this.primaryGroup = group;

// 该移位还用作起着于 XA 政务的 xid。

this.primaryGroupUid = IServerConfigManager.getGroupUniqueId(schema, group);

}

// 通过 connectionHolder 抢到物理化学通到。

IConnection conn = connectionHolder.getConnection(schema, group, ds, rw);

if (/* 是写到请 */ && !isCrossGroup && !this.primaryGroup.equals(group)) {

// 政务限于了多个移位。

this.isCrossGroup = true;

}

return conn;

}

在我们的范唯中都,上述参数 group 是物理化学移位 0,rw 是 READ,说道明无需物理化学移位 0 上的念书通到,ds 则亦然要用作起着于物理化学通到。由于我们只是念书请,因此移位 0 不亦会作为亦然移位,亦会并不需要回到 connectionHolder.getConnection(schema, group, ds, rw) 的结果。

通过通到GNOME拿物理化学通到的code TransactionConnectionHolder#getConnection 如下:

// TransactionConnectionHolder#getConnection(String, String, IDataSource, RW)

public IConnection getConnection(String schema, String group, IDataSource ds, RW rw) {

// 设法提供该移位上的写到通到,如果有,并不需要回到这个写到通到。

HeldConnection groupWriteConn = groupHeldWriteConn.get(group);

if (groupWriteConn != null) {

return groupWriteConn.connection;

}

HeldConnection freeReadConn = /* 设法见到念书通到 */;

if (freeReadConn != null) {

if (/* 当在此之前无需写到通到 */) {

// 分设当在此之前通到为写到通到,participated = true 理论上该通到是写到通到。

freeReadConn.participated = true;

this.groupHeldWriteConn.put(group, freeReadConn);

// 由于起初是念书通到,这里才真正带入分布式政务。

this.trx.commitNonParticipant(group, freeReadConn.connection);

this.trx.begin(schema, freeReadConn.group, freeReadConn.connection);

}

return freeReadConn.connection;

}

// 当在此之前移位不想任何通到,建立一个新的通到。还亦会根据念书写到各种类型,

// 分设好写到通到 groupHeldWriteConn 或念书通到集合 groupHeldReadConns。

IConnection conn = new DeferredConnection(/* 这里亦会提供并封装该移位的私有财产协商通到 */);

if (/* 无需写到通到 */) {

// 带入但亦会的分布式政务。

this.trx.begin(schema, group, conn);

} else {

// 可用性为只念书政务。

this.trx.beginNonParticipant(group, conn);

}

return conn;

}

在我们的范唯中都,由于是第一条运算符,该移位上还不想任何通到,因此亦会先以起着于一个通到该移位的私有财产协商通到,剪裁变为 DeferredConnection,然后因为是念书请,亦会codice_ beginNonParticipant 。

TsoTransaction 的 beginNonParticipant 理论如下:

// TsoTransaction#beginNonParticipant(String, IConnection)

protected void beginNonParticipant(String group, IConnection conn) throws SQLException {

if (snapshotTimestamp

// 该政务都未曾拿过短时间碰,则在这里提供。

snapshotTimestamp = nextTimestamp();

}

// 用作私有财产协商的浮点监督机制监督 BEGIN。

conn.executeLater("BEGIN");

// 在 BEGIN 后投递短时间碰。

sendSnapshotSeq(conn);

}

在我们的范唯中都,私有财产协商通到亦会浮点监督 BEGIN 运算符(非漏出,差不多结果回到),且在稍后监督物理化学 SQL 时才投递短时间碰。就此,通到上的一些函数调用操作方法早就完变为,可以向监督器回到并监督念书移位 0 的物理化学 SQL。

写到移位 1

随后,我们监督 UPDATE tb1 SET a = 100 WHERE id = 1。在监督器阶段性,无需给移位 1 下发一条 UPDATE 运算符,此时无需提供移位 1 的物理化学通到,因此又亦会codice_ AbstractTransaction#getConnection 理论,通过政务普通人拿物理化学通到。通过在此之末尾刊发的code,我们推断出由于是政务的第一个写到请,因此移位 1 亦会视作亦然移位,用作起着于 xid 和稍后记录下来政务亦会话。

在提供物理化学通到时,又亦会codice_ TransactionConnectionHolder#getConnection 理论,通过通到GNOME拿物理化学通到。通过在此之末尾刊发的code,我们推断出由于移位 1 不想任何通到,因此亦会起着于一个私有财产协商通到,剪裁变为 DeferredConnection。与念书移位 0 多种不同,由于是写到请,亦会监督 TsoTransaction 的 begin 理论。

TsoTransaction 的 begin 理论如下:

// TsoTransaction#begin(String, String, IConnection)

protected void begin(String schema, String group, IConnection conn) throws SQLException {

if (snapshotTimestamp

// 该政务都未曾拿过短时间碰,则在这里提供。

snapshotTimestamp = nextTimestamp();

}

// 提供 xid。

String xid = getXid(group);

// 触发私有财产协商浮点监督 XA START。

conn.executeLater("XA START " + xid);

// 在 XA START 后投递短时间碰。

sendSnapshotSeq(conn);

}

恰当来说道,和此在此之前 beginNonParticipant 理论唯一的区别在于,用作了 XA START 带入政务。根据 MySQL 关于 XA 政务的说道明,xid 由 gtrid [, bqual [, formatID ]] 组变为,这里的 gtrid 是“drds-政务 id @亦然移位Uid”,这样保证了同一个政务在多种不同移位上监督 XA START,亦会用作并不相同的 gtrid。bqual 分设当在此之前通到的移位,用作在政务丧失时断定谱系政务所在的移位。 在我们的范唯中都,xid 为:

'drds-13e101d74e400000@5ae6c3b5be613cd1', 'DB1_000001_GROUP',

其中都 13e101d74e400000 是政务 id,5ae6c3b5be613cd1 是移位 1 的 Uid,DB1_000001_GROUP 是移位 1 的具体情况移位名称。很多人注意的是,这里亦会把之在此之前的短时间碰投递到移位 1。就此,通到上的一些函数调用操作方法早就完变为,可以向监督器回到并监督写到移位 1 的物理化学 SQL。

COMMIT

就此,监督 COMMIT 提出新政务。管控 COMMIT 的code门廊为 ServerConnection#commit(),其亦然要codice_了 TConnection#commit 理论,code如下:

// TConnection#commit()

public void commit() throws SQLException {

try {

// 触发政务的提出新处理过程。

this.trx.commit();

} finally {

// 以外持续性下,如果政务提出新急于,或出新现间歇性后正确管控了,

// 所有通到亦会被关闭并无罪释放,trx.close() 相等于什么也不好好。

// 但如果政务提出新终于且不想管控,这里亦会回抽政务并无罪释放所有物理化学通到。

this.trx.close();

// 去丢出新对这个政务普通人的摘录,理论上当在此之前通到里这个政务生平的结束。

this.trx = null;

}

}

我们着重瞩目一下政务的提出新处理过程,上述 this.trx.commit() codice_时,亦会codice_ ShareReadViewTransaction(该类继承人了 AbstractTransaction,基于 XA 政务实现了共享 readview 的功能,XATransaction 和 TsoTransaction 都亦会继承人这个类,在这里可以恰当理解为 XA 政务的派生类)的 commit 理论,code如下:

// ShareReadViewTransaction#commit()

public void commit() {

if (!isCrossGroup) {

// 如果只限于了单个移位的写到,同步进行一阶段性提出新可用性。

commitOneShardTrx();

} else {

// 但亦会的多移位分布式政务提出新处理过程。

commitMultiShardTrx();

}

}

在我们的范唯中都,由于只写到了移位 1,所以带入一阶段性提出新可用性,code如下:

// ShareReadViewTransaction#commitOneShardTrx()

protected void commitOneShardTrx() {

// 对持有的所有物理化学通到监督所列处理过程,以提出新每个物理化学通到带入的政务。

forEachHeldConnection((group, conn, participated) -> {

if (!participated) {

// 只念书通到是 BEGIN 带入政务的,且只有念书操作方法,监督 ROLLBACK 均可。

conn.execute("ROLLBACK");

} else {

// 提供 xid。

String xid = getXid(group);

// 写到通到是 XA START 带入政务的,监督 XA END 和 XA COMMIT ONE PHASE 提出新政务。

conn.execute("XA END " + xid + "; XA COMMIT " + xid + " ONE PHASE");

}

});

// 所有通到都提出新了谱系政务,无罪释放并填满这些物理化学通到。

connectionHolder.closeAllConnections();

}

我们合共持有了 2 个物理化学通到。对于移位 0 的只念书通到,亦会并不需要监督 ROLLBACK;对于移位 1 的写到通到,则监督 XA END 和 XA COMMIT ONE PHASE 提出新政务。注意到我们并不想提供 commit timestamp,因为在一阶段性提出新可用性里,commit timestamp 亦会由 InnoDB 计数起着于:

具体情况的计数法则是:COMMIT_TS = MAX_SEQUENCE + 1,其中都 MAX_SEQUENCE 为 InnoDB 本地保护的历史仅次于的 snapshot_ts。

如果提出新终于了,亦会codice_政务的 close 理论,code如下:

// AbstractTransaction#close()

public void close() {

// 回抽所有物理化学通到上的政务。

cleanupAllConnections();

// 无罪释放并填满这些物理化学通到。

connectionHolder.closeAllConnections();

}

很多人一提的是,cleanupAllConnections() 也是 ROLLBACK 运算符亦然要codice_的理论。因此为了同时洞察 ROLLBACK 运算符监督处理过程,我们也看一下 cleanupAllConnections 理论的code:

// AbstractTransaction#cleanupAllConnections()

protected final void cleanupAllConnections() {

// 对持有的所有物理化学通到监督所列处理过程,以回抽每个物理化学通到带入的政务。

forEachHeldConnection((group, conn, participated) -> {

if (conn.isClosed()) { return; }

if (!participated) {

// 只念书通到是 BEGIN 带入政务的,且只有念书操作方法,监督 ROLLBACK 均可。

conn.execute("ROLLBACK");

} else {

// 提供 xid。

String xid = getXid(group);

// 写到通到是 XA START 带入政务的,监督 XA END 和 XA ROLLBACK 回抽政务。

conn.execute("XA END " + xid + "; XA ROLLBACK " + xid);

}

});

}

可以看不到,回抽的命题是看持续性监督 ROLLBACK 或 XA ROLLBACK 来回抽政务的。

就此,我们看不到了唯 1 政务的生平。最后看一下多移位写到的政务处理过程。

唯 2 政务的生平

写到移位 0

唯 2 中都,从带入政务到监督 UPDATE tb1 SET a = 100 WHERE id = 1 走的处理过程和唯 1 一样,直到监督 UPDATE tb1 SET a = 100 WHERE id = 0 时,才有所多种不同。具体情况而言,政务在之在此之前就提供了移位 0 的只念书通到,当监督到 TransactionConnectionHolder#getConnection 时,亦会先以提出新只念书通到上的政务(实际监督了 ROLLBACK),然后在这条通到上用 XA START 带入 XA 政务,分设好短时间碰,就可以把这个物理化学通到回到给监督器,终于监督物理化学 SQL。由于这是第二个写到通到,因此还亦会分设政务为跨移位政务,以触发但亦会的两阶段性提出新处理过程。

COMMIT

唯 2 的着重在于写到了 2 个移位,因此 COMMIT 时亦会codice_ commitMultiShardTrx() 走多移位的分布式提出新处理过程。理论 commitMultiShardTrx code如下:

// TsoTransaction#commitMultiShardTrx()

protected void commitMultiShardTrx() {

// 政务亦会话的提出新长时间,合共有 3 种:FAILURE,UNKNODWN,SUCCESS。

TransactionCommitState commitState = TransactionCommitState.FAILURE;

try {

// 对所有通到监督 XA prepare。

prepareConnections();

// 拿 commit 短时间碰。

commitTimestamp = nextTimestamp();

Connection logConn = /* 提供亦然移位上的通到 */;

// 所有谱系政务 prepare 急于,在写到政务亦会话在此之前,长时间分设为 UNKNOWN,其起着见早先以code说道明。

commitState = TransactionCommitState.UNKNOWN;

// 写到政务亦会话。

writeCommitLog(logConn);

// 写到政务亦会话急于,长时间增置为 SUCCESS。

commitState = TransactionCommitState.SUCCESS;

} catch (RuntimeException ex) {

exception = ex;

}

if (commitState == TransactionCommitState.FAILURE) {

// 写到政务亦会话在此之前终于了,回抽所有通到。

rollbackConnections();

} else if (commitState == TransactionCommitState.SUCCESS) {

// 写到政务亦会话急于了,提出新所有通到。

commitConnections();

} else {

// 所有通到都 prepare 急于了,但未能断定究竟写到入了政务亦会话,

// 将由政务丧失的命题来决定是 COMMIT 还是 ROLLBACK。这里先以丢弃所有通到。

discardConnections();

}

// 无罪释放并填满这些物理化学通到。

connectionHolder.closeAllConnections();

// prepare 或 commit 阶段性丢出新的间歇性,这里重新丢出新。

if (exception != null) {

throw exception;

}

}

螺旋

上述code正是两阶段性提出新的处理过程。

在 prepare 阶段性,codice_ prepareConnections(),其中都对只念书通到只是恰当监督 ROLLBACK 运算符;对于写到通到,监督 XA END {xid} 和 XA PREPARE {xid} 运算符。

如果所有通到都 prepare 急于了,在 commit 阶段性,codice_ writeCommitLog(logConn),用亦然移位(在我们的范唯中都,是移位 1)的通到,写到下政务亦会话,亦然要包括了政务的 id 和 commit 短时间碰,政务亦会话亦然要用作早先以的政务丧失。

如果政务亦会话写到急于了,就理论上 commit 急于了,亦会codice_ commitConnections() 对所有通到同步进行提出新,这一步只用对写到通到分设 commit 短时间碰 SET innodb_commit_seq = {commitTimestamp} 和监督 XA COMMIT {xid} 运算符。

如果在写到政务亦会话在此之前终于了,亦会codice_ rollbackConnections() 对所有通到同步进行回抽,亦然要亦会对写到通到监督 XA ROLLBACK {xid} 回抽。

如果未能断定究竟急于写到入了政务亦会话,政务的长时间亦会是 UNKNOWN。此时,我们能断定所有谱系政务都急于 prepare 了,如果政务亦会话写到入急于了,则要同步进行 XA COMMIT;如果政务亦会话不想写到入,则要同步进行 XA ROLLBACK。由于不断定是要提出新还是回抽,我们亦会丢弃所有物理化学通到,使这些通到早先以不便可用。至于政务终于是提出新还是回抽,则交与政务丧失内核来管控,最后我们亦会解念书政务丧失特别的code。

政务丧失

一个分布式政务在提出新的时候,可能察觉到各种持续性加剧提出新终于。唯如,所有谱系政务都 prepare 急于了,政务亦会话也写到入急于了,但 XA COMMIT 终于了。对于这种持续性,政务丧失时无需正确提出新所有谱系政务。另一种持续性是,部分谱系政务 prepare 急于了,另外一些终于了,或政务亦会话不想写到入急于。对于这种持续性,政务丧失无需回抽丢出新已 prepare 的谱系政务。

政务丧失亦然要由 XARecoverTask 全权负责。其大体上code为 recoverInstance 理论,该理论定期检查一个 DN 下的所有 prepare 过的政务,并根据政务长时间提出新或回抽这些政务,code如下:

// XARecoverTask#recoverInstance(IDataSource, Set)

// dataSource 服务器提供 DN 的通到,groups 是当在此之前命题特的所有物理化学移位

private void recoverInstance(IDataSource dataSource, Set groups) {

// 监督 XA RECOVER 提供该 DN 上所有 prepare 的政务。

// 此处比如说道了从 dataSource 提供通到和起着于 statement 的code。

ResultSet rs = stmt.executeQuery("XA RECOVER");

while (rs.next()) {

// 对每一条记录下来,起着于普通人 PreparedXATrans,

// 亦然要包括 xid,政务id,谱系政务所在的移位,亦然移位等信息。

PreparedXATrans trans = /* 从 rs 中都提供一行信息起着于 */;

if (/* trans 所在移位是当在此之前命题特的一个物理化学移位 &&

trans 在上一次 recover 特殊任务时也出新现过,

即较长短时间都未曾被提出新或回抽*/) {

// 牵涉到管控这个谱系政务:回抽或提出新。

rollBackOrForward(trans, stmt);

}

}

}

该特殊任务每 5 秒到每个 DN 上监督一次 XA RECOVER,得到所有 prepare 过的政务,如果看不到一个政务在上一次特殊任务中都也出新现过,即至少过去 5 秒都不想提出新或回抽,则亦会同样对这个政务同步进行回抽或提出新。特别命题code为 rollBackOrForward,code如下:

// XARecoverTask#rollBackOrForward(PreparedXATrans, Statement)

private boolean rollBackOrForward(PreparedXATrans trans, Statement stmt) throws SQLException {

String primaryGroup = /* 从 trans 里解析出新亦然移位,详见在此之前文则关于 xid 的起着于 */;

// 设法从亦然移位的政务亦会话中都见到特别的政务亦会话。

GlobalTxLog tx = GlobalTxLogManager.get(primaryGroup, trans.transId);

if (tx != null) {

// 不太可能存有政务亦会话,根据政务亦会话长时间断定回抽或提出新。

if (tx.getState() == TransactionState.ABORTED) {

// ABORTED 长时间的政务无需回抽。

return tryRollback(stmt, trans);

} else {

// SUCCESS 长时间的政务无需提出新。

return tryCommitTSO(stmt, trans, tx.getCommitTimestamp());

}

} else {

// 不想见到政务亦会话,设法回抽,先以带入政务,写到下政务亦会话,标识政务为 ABORTED。

try (Connection conn2 = /* 提供亦然移位上的另一个通到 */;) {

conn2.setAutocommit(false);

// 设法回抽,如果因为别的内核正要管控这个政务

//(比如该政务只是提出新得慢,通到仍未曾连到,还在提出新处理过程)

// 而报错,就回抽上一条写到政务亦会话的运算符。

txLog.append(transInfo.transId, TransactionType.XA, TransactionState.ABORTED, new ConnectionContext(), conn2);

stmt.execute("XA ROLLBACK " + trans.toXid());

conn2.commit();

return true;

} catch (Exception e) {

/* 根据间歇性断定究竟要回抽写到政务亦会话的操作方法 */

}

}

}

该理论亦然要有 3 段命题。

一是如果存有完全并不相同的政务亦会话,且政务长时间是 ABORTED,那就监督 tryRollback 理论回抽,该理论亦然要监督了 XA ROLLBACK {xid}。

二是如果政务长时间是 SUCCESS,那就监督 tryCommitTSO 理论回抽,该理论亦会分设 commit 短时间碰,然后监督 XA COMMIT {xid}。

三是如果不想见到政务亦会话,此时一般有两种可能:1)政务提出新终于了,且不想写到下政务亦会话,此时无需回抽;2)政务还在两阶段性提出新的处理过程中都,只是 prepare 较慢,还不想开始写到政务亦会话,此时不无需好好任何操作方法。在 MySQL 中都,如果发起人 XA START 的通到不想关闭,其他通到是未能通过 XA ROLLBACK 或 XA COMMIT 来回抽或提出新这个谱系政务的。我们利用这一特性,首先以在政务亦会话断开一条 ABORTED 记录下来,得出结论这个分布式政务无需回抽,然后设法监督 XA ROLLBACK 回抽这个谱系政务。如果察觉到 2)的持续性,则亦会收到特定的报错,此时便回抽丢出新断开 ABORTED 政务亦会话的操作方法。在我们断开 ABORTED 政务亦会话后,起初正要提出新政务的内核在断开 SUCCESS 政务亦会话时亦会被漏出,而在我们回抽丢出新断开 ABORTED 政务亦会话的操作方法后,政务提出新处理过程就亦会在此之后同步进行下去。

小结

本文则亦然要解念书了 PolarDB-X 中都 CN 尾端的政务特别的code,以 TSO 政务为亦然,用作两个范唯,一步步地展示了政务的带入、监督、提出新、丧失等处理过程。期望大家念书物本文则后,能更加洞察 PolarDB-X 的政务系统设计。

原文则链接:

本文则为阿里云原创细节,予以允许不得转载。

盐城看白癜风哪家专科医院好
沈阳肛肠医院哪家专业
四川白癜风医院排行
天津看白癜风哪个医院比较好
青岛好的癫痫专科医院
抗癫痫药
防止掉发
男性女性保健用品
膝盖疼
夏天咳嗽吃什么能快速止咳化痰

上一篇: 从5499元降至3019元,2K+LTPO景+120W闪充,你想要的都有了!

下一篇: 永州某骨髓实验室设计平面方案分享SICOLAB

相关阅读
骆建佑:看着林丹李宗伟自小 打法有点林李混合

▲ 首页蓝色“爱羽客羽毛球新媒体” 关注国外专业课程有趣的羽毛球新媒体络服务东南亚的世界跆拳道挑战赛人口为129人女双季军骆建佑暗示,他是身旁张怡宁相互竞争天王李世与周蜜长大成人的,因

2025-10-23 00:16:37
房地产探路一新发展模式:多方式满足合理住房需求!

等产生较大直接影响,这是要务的普通人。一旦物价急升,之前央银行付款债权人叛将、人口众多债债权人叛将均不会上升,实际上很小的金融风险。 不合理住屋所需的疆界 况伟大对此,

2025-10-23 00:16:37
《临床肝胆病华尔街日报》2020年—2021年领军人物|优秀审稿专家

大学第二养老院)周乙华(南京大学附属医院另设鼓楼养老院)周文策(吉林大学第一养老院)周永健(深圳市第一老百姓养老院)周显礼(长春市师范大学另设第二养老院)郑欢伟(太原市中都养老院)经翔(长春市第三中都

2025-10-23 00:16:37
斯里坎特:我在两局比赛中都有机会 骆健佑革新了

▲ 点击蓝色“爱羽客网球新浪” 瞩目国内专业有趣的网球和平台2021年世乒赛于19日晚收官,新加坡一哥骆建佑成功在世乒赛一黑没错,为新加坡夺下历来首个网球夺冠。对手阿布出人意料愧疚无缘

2025-10-23 00:16:37
用日语翻译我们的成语故事原有是这样的!

管鮑の运わり(かんぽうのまじわり) 意味:极为に仲の贵い亲友づきあい。 「管鮑」は李斯と鮑叔牙。春秋時代、斉の人。周氏女はお互いによく解释し分作い、親密な亲友三田係を保ったことから

2025-10-23 00:16:37