[{"data":1,"prerenderedAt":2444},["ShallowReactive",2],{"content:\u002F2026\u002F04\u002Fkratos-transaction":3,"surround:\u002F2026\u002F04\u002Fkratos-transaction":2435},{"id":4,"title":5,"body":6,"categories":2413,"date":2415,"description":2416,"draft":2417,"extension":2418,"image":2419,"meta":2420,"navigation":129,"path":2422,"permalink":2419,"published":2419,"readingTime":2423,"recommend":2419,"references":2419,"seo":2428,"sitemap":2429,"stem":2430,"tags":2431,"type":2433,"updated":2415,"__hash__":2434},"content\u002Fposts\u002F2026\u002F04\u002Fkratos-transaction.md","Kratos 事务管理与循环依赖解决方案",{"type":7,"value":8,"toc":2410},"minimark",[9,20,33,46,58,67,71,550,553,665,674,677,2406],[10,11,12,16,17],"p",{},[13,14,15],"code",{"code":15},"Kratos"," 当中的数据流向是 ",[13,18,19],{"code":19},"server -> biz -> data",[10,21,22,25,26,29,30],{},[13,23,24],{"code":24},"data"," 需要实现 ",[13,27,28],{"code":28},"biz"," 中定义的接口，利用注入的基础设施做 ",[13,31,32],{"code":32},"crud",[10,34,35,36,38,39,41,42,45],{},"但实际上我们需要在 ",[13,37,28],{"code":28},"层去开启事务的时候需要依赖于 ",[13,40,24],{"code":24}," 层的 ",[13,43,44],{"code":44},"DB","实例",[10,47,48,49,52,53,57],{},"如果在 data 层暴露一个 ",[13,50,51],{"code":51},"GetDB"," 的方法，看上去没什么问题，实际上会导致一个",[54,55,56],"strong",{},"循环依赖","的问题",[10,59,60,61,63,64,66],{},"对于这种情况，我们可以在 ",[13,62,24],{"code":24}," 层去创建一个事务管理器，并在 ",[13,65,28],{"code":28}," 层去定义事务管理器需要实现的接口，这样抽离公共模块能保证代码的文件运行同时保证解耦。",[68,69,70],"h2",{"id":70},"代码相关实现",[72,73,78],"pre",{"className":74,"code":75,"language":76,"meta":77,"style":77},"language-go shiki shiki-themes github-light github-dark","shortvid-service\u002Finternal\u002Fdata\u002Ftx.go\npackage data\n\nimport (\n\t\"shortvid-backend\u002Fapp\u002Fshortvid-service\u002Finternal\u002Fbiz\"\n\n\t\"github.com\u002Fgo-kratos\u002Fkratos\u002Fv2\u002Flog\"\n\t\"gorm.io\u002Fgorm\"\n)\n\ntype txRepo struct {\n\tdata *Data\n}\n\nfunc NewTxRepo(data *Data) biz.TxRepo {\n\treturn &txRepo{\n\t\tdata: data,\n\t}\n}\n\nfunc (r *txRepo) ExecFunc(fn func(tx *gorm.DB) error) error {\n\terr := r.data.db.Transaction(func(tx *gorm.DB) error {\n\t\treturn fn(tx)\n\t})\n\tif err != nil {\n\t\tr.data.logger.Log(log.LevelError, \"error\", \"transaction failed\")\n\t\treturn err\n\t}\n\treturn nil\n}\n","go","",[13,79,80,114,124,131,144,161,166,178,190,196,201,218,232,238,243,281,298,308,317,322,327,389,433,451,463,485,514,526,535,545],{"__ignoreMap":77},[81,82,85,89,93,96,99,102,104,106,108,111],"span",{"class":83,"data-line":84,"line":84},"line",1,[81,86,88],{"class":87},"sVt8B","shortvid",[81,90,92],{"class":91},"szBVR","-",[81,94,95],{"class":87},"service",[81,97,98],{"class":91},"\u002F",[81,100,101],{"class":87},"internal",[81,103,98],{"class":91},[81,105,24],{"class":87},[81,107,98],{"class":91},[81,109,110],{"class":87},"tx.",[81,112,113],{"class":91},"go\n",[81,115,117,120],{"class":83,"data-line":116,"line":116},2,[81,118,119],{"class":91},"package",[81,121,123],{"class":122},"sScJk"," data\n",[81,125,127],{"class":83,"data-line":126,"line":126},3,[81,128,130],{"emptyLinePlaceholder":129},true,"\n",[81,132,134,137,140],{"class":83,"data-line":133,"line":133},4,[81,135,136],{"class":91},"import",[81,138,139],{"class":87}," ",[81,141,143],{"class":142},"sSDpw","(\n",[81,145,147,151,155,158],{"class":83,"data-line":146,"line":146},5,[81,148,150],{"class":149},"indent","\t",[81,152,154],{"class":153},"sZZnC","\"",[81,156,157],{"class":122},"shortvid-backend\u002Fapp\u002Fshortvid-service\u002Finternal\u002Fbiz",[81,159,160],{"class":153},"\"\n",[81,162,164],{"class":83,"data-line":163,"line":163},6,[81,165,130],{"emptyLinePlaceholder":129},[81,167,169,171,173,176],{"class":83,"data-line":168,"line":168},7,[81,170,150],{"class":149},[81,172,154],{"class":153},[81,174,175],{"class":122},"github.com\u002Fgo-kratos\u002Fkratos\u002Fv2\u002Flog",[81,177,160],{"class":153},[81,179,181,183,185,188],{"class":83,"data-line":180,"line":180},8,[81,182,150],{"class":149},[81,184,154],{"class":153},[81,186,187],{"class":122},"gorm.io\u002Fgorm",[81,189,160],{"class":153},[81,191,193],{"class":83,"data-line":192,"line":192},9,[81,194,195],{"class":142},")\n",[81,197,199],{"class":83,"data-line":198,"line":198},10,[81,200,130],{"emptyLinePlaceholder":129},[81,202,204,207,210,213,215],{"class":83,"data-line":203,"line":203},11,[81,205,206],{"class":91},"type",[81,208,209],{"class":122}," txRepo",[81,211,212],{"class":91}," struct",[81,214,139],{"class":87},[81,216,217],{"class":142},"{\n",[81,219,221,223,226,229],{"class":83,"data-line":220,"line":220},12,[81,222,150],{"class":149},[81,224,225],{"class":87},"data ",[81,227,228],{"class":91},"*",[81,230,231],{"class":122},"Data\n",[81,233,235],{"class":83,"data-line":234,"line":234},13,[81,236,237],{"class":142},"}\n",[81,239,241],{"class":83,"data-line":240,"line":240},14,[81,242,130],{"emptyLinePlaceholder":129},[81,244,246,249,252,255,258,261,264,267,269,271,274,277,279],{"class":83,"data-line":245,"line":245},15,[81,247,248],{"class":91},"func",[81,250,251],{"class":122}," NewTxRepo",[81,253,254],{"class":142},"(",[81,256,24],{"class":257},"s4XuR",[81,259,260],{"class":91}," *",[81,262,263],{"class":122},"Data",[81,265,266],{"class":142},")",[81,268,139],{"class":87},[81,270,28],{"class":122},[81,272,273],{"class":87},".",[81,275,276],{"class":122},"TxRepo",[81,278,139],{"class":87},[81,280,217],{"class":142},[81,282,284,286,289,292,295],{"class":83,"data-line":283,"line":283},16,[81,285,150],{"class":149},[81,287,288],{"class":91},"return",[81,290,291],{"class":91}," &",[81,293,294],{"class":122},"txRepo",[81,296,217],{"class":297},"sJX2D",[81,299,301,303,305],{"class":83,"data-line":300,"line":300},17,[81,302,150],{"class":149},[81,304,150],{"class":149},[81,306,307],{"class":87},"data: data,\n",[81,309,311,313,315],{"class":83,"data-line":310,"line":310},18,[81,312,150],{"class":149},[81,314,77],{"class":87},[81,316,237],{"class":297},[81,318,320],{"class":83,"data-line":319,"line":319},19,[81,321,237],{"class":142},[81,323,325],{"class":83,"data-line":324,"line":324},20,[81,326,130],{"emptyLinePlaceholder":129},[81,328,330,332,334,336,339,341,343,345,347,350,352,355,358,360,363,365,368,370,372,374,376,379,381,383,385,387],{"class":83,"data-line":329,"line":329},21,[81,331,248],{"class":91},[81,333,139],{"class":87},[81,335,254],{"class":142},[81,337,338],{"class":257},"r ",[81,340,228],{"class":91},[81,342,294],{"class":122},[81,344,266],{"class":142},[81,346,139],{"class":87},[81,348,349],{"class":122},"ExecFunc",[81,351,254],{"class":142},[81,353,354],{"class":257},"fn",[81,356,357],{"class":91}," func",[81,359,254],{"class":297},[81,361,362],{"class":257},"tx",[81,364,260],{"class":91},[81,366,367],{"class":122},"gorm",[81,369,273],{"class":87},[81,371,44],{"class":122},[81,373,266],{"class":297},[81,375,139],{"class":87},[81,377,378],{"class":91},"error",[81,380,266],{"class":142},[81,382,139],{"class":87},[81,384,378],{"class":91},[81,386,139],{"class":87},[81,388,217],{"class":142},[81,390,392,394,397,400,403,406,408,410,413,415,417,419,421,423,425,427,429,431],{"class":83,"data-line":391,"line":391},22,[81,393,150],{"class":149},[81,395,396],{"class":87},"err ",[81,398,399],{"class":91},":=",[81,401,402],{"class":87}," r.data.db.",[81,404,405],{"class":122},"Transaction",[81,407,254],{"class":297},[81,409,248],{"class":91},[81,411,254],{"class":412},"sqkie",[81,414,362],{"class":257},[81,416,260],{"class":91},[81,418,367],{"class":122},[81,420,273],{"class":87},[81,422,44],{"class":122},[81,424,266],{"class":412},[81,426,139],{"class":87},[81,428,378],{"class":91},[81,430,139],{"class":87},[81,432,217],{"class":412},[81,434,436,438,440,442,445,447,449],{"class":83,"data-line":435,"line":435},23,[81,437,150],{"class":149},[81,439,150],{"class":149},[81,441,288],{"class":91},[81,443,444],{"class":122}," fn",[81,446,254],{"class":142},[81,448,362],{"class":87},[81,450,195],{"class":142},[81,452,454,456,458,461],{"class":83,"data-line":453,"line":453},24,[81,455,150],{"class":149},[81,457,77],{"class":87},[81,459,460],{"class":412},"}",[81,462,195],{"class":297},[81,464,466,468,471,474,477,481,483],{"class":83,"data-line":465,"line":465},25,[81,467,150],{"class":149},[81,469,470],{"class":91},"if",[81,472,473],{"class":87}," err ",[81,475,476],{"class":91},"!=",[81,478,480],{"class":479},"sj4cs"," nil",[81,482,139],{"class":87},[81,484,217],{"class":297},[81,486,488,490,492,495,498,500,503,506,509,512],{"class":83,"data-line":487,"line":487},26,[81,489,150],{"class":149},[81,491,150],{"class":149},[81,493,494],{"class":87},"r.data.logger.",[81,496,497],{"class":122},"Log",[81,499,254],{"class":412},[81,501,502],{"class":87},"log.LevelError, ",[81,504,505],{"class":153},"\"error\"",[81,507,508],{"class":87},", ",[81,510,511],{"class":153},"\"transaction failed\"",[81,513,195],{"class":412},[81,515,517,519,521,523],{"class":83,"data-line":516,"line":516},27,[81,518,150],{"class":149},[81,520,150],{"class":149},[81,522,288],{"class":91},[81,524,525],{"class":87}," err\n",[81,527,529,531,533],{"class":83,"data-line":528,"line":528},28,[81,530,150],{"class":149},[81,532,77],{"class":87},[81,534,237],{"class":297},[81,536,538,540,542],{"class":83,"data-line":537,"line":537},29,[81,539,150],{"class":149},[81,541,288],{"class":91},[81,543,544],{"class":479}," nil\n",[81,546,548],{"class":83,"data-line":547,"line":547},30,[81,549,237],{"class":142},[10,551,552],{},"biz 层的接口",[72,554,556],{"className":74,"code":555,"language":76,"meta":77,"style":77},"shortvid-service\u002Finternal\u002Fbiz\u002Ftx.go\npackage biz\n\nimport \"gorm.io\u002Fgorm\"\n\n\u002F\u002F 事务聚合器\ntype TxRepo interface {\n\tExecFunc(fn func(*gorm.DB) error) error\n}\n",[13,557,558,580,587,591,602,606,612,626,661],{"__ignoreMap":77},[81,559,560,562,564,566,568,570,572,574,576,578],{"class":83,"data-line":84,"line":84},[81,561,88],{"class":87},[81,563,92],{"class":91},[81,565,95],{"class":87},[81,567,98],{"class":91},[81,569,101],{"class":87},[81,571,98],{"class":91},[81,573,28],{"class":87},[81,575,98],{"class":91},[81,577,110],{"class":87},[81,579,113],{"class":91},[81,581,582,584],{"class":83,"data-line":116,"line":116},[81,583,119],{"class":91},[81,585,586],{"class":122}," biz\n",[81,588,589],{"class":83,"data-line":126,"line":126},[81,590,130],{"emptyLinePlaceholder":129},[81,592,593,595,598,600],{"class":83,"data-line":133,"line":133},[81,594,136],{"class":91},[81,596,597],{"class":153}," \"",[81,599,187],{"class":122},[81,601,160],{"class":153},[81,603,604],{"class":83,"data-line":146,"line":146},[81,605,130],{"emptyLinePlaceholder":129},[81,607,608],{"class":83,"data-line":163,"line":163},[81,609,611],{"class":610},"sJ8bj","\u002F\u002F 事务聚合器\n",[81,613,614,616,619,622,624],{"class":83,"data-line":168,"line":168},[81,615,206],{"class":91},[81,617,618],{"class":122}," TxRepo",[81,620,621],{"class":91}," interface",[81,623,139],{"class":87},[81,625,217],{"class":142},[81,627,628,630,632,634,636,638,640,642,644,646,648,650,652,654,656,658],{"class":83,"data-line":180,"line":180},[81,629,150],{"class":149},[81,631,349],{"class":122},[81,633,254],{"class":297},[81,635,354],{"class":257},[81,637,357],{"class":91},[81,639,254],{"class":412},[81,641,228],{"class":91},[81,643,367],{"class":122},[81,645,273],{"class":87},[81,647,44],{"class":122},[81,649,266],{"class":412},[81,651,139],{"class":87},[81,653,378],{"class":91},[81,655,266],{"class":297},[81,657,139],{"class":87},[81,659,660],{"class":91},"error\n",[81,662,663],{"class":83,"data-line":192,"line":192},[81,664,237],{"class":142},[10,666,667,668,670,671,673],{},"在真正用到事务的时候将",[13,669,276],{"code":276},"注入到 ",[13,672,28],{"code":28}," 的结构体当中",[10,675,676],{},"代码示例：",[72,678,680],{"className":74,"code":679,"language":76,"meta":77,"style":77},"type UsersRepo interface {\n\tCreateUser(ctx context.Context, user *model.User) error\n\tCreateUserWithTx(ctx context.Context, tx *gorm.DB, user *model.User) error\n\tGetUserByEmailAndProvider(ctx context.Context, email string, provider string) (*model.User, error)\n\tGetUserByUID(ctx context.Context, UID int) (*model.User, error)\n\tUpdateLoginInfo(ctx context.Context, userUID int) error\n}\n\ntype UsersUsecase struct {\n\tlogger      log.Logger\n\ttxRepo      TxRepo\n\trepo        UsersRepo\n\taccountRepo AccountRepo\n}\n\n\u002F\u002F FirebaseFindOrCreateUser 查询或创建用户[Firebase]\nfunc (uc *UsersUsecase) FirebaseFindOrCreateUser(ctx context.Context, dto *UserDTO) (*UserProfileVO, bool, error) {\n\t\u002F\u002F 判断账户是否存在\n\texistAcc, err := uc.accountRepo.GetByEmailAndProvider(ctx, dto.Email, dto.Provider)\n\tif err != nil {\n\t\tuc.logger.Log(log.LevelError, \"msg\", \"Get account by email and provider failed\", \"error\", err)\n\t\treturn nil, false, err\n\t}\n\tif existAcc != nil {\n\t\t\u002F\u002F 账户存在, 继续查找用户\n\t\texistUser, err := uc.repo.GetUserByUID(ctx, existAcc.UID)\n\t\tif err != nil {\n\t\t\tuc.logger.Log(log.LevelError, \"msg\", \"Get user by uid failed\", \"error\", err)\n\t\t\treturn nil, false, err\n\t\t}\n\t\tif existUser == nil {\n\t\t\treturn nil, false, errors.New(\"account exists, but user not found\")\n\t\t}\n\n\t\treturn &UserProfileVO{\n\t\t\tID:          existUser.ID,\n\t\t\tUID:         existUser.UID,\n\t\t\tCtime:       existUser.CreatedAt.Unix(),\n\t\t\tNickname:    existUser.Nickname,\n\t\t\tAvatar:      existUser.Avatar,\n\t\t\tEmail:       existAcc.Email,\n\t\t\tProvider:    existAcc.Provider,\n\t\t\tProviderUID: existAcc.ProviderUID,\n\t\t}, false, nil\n\t}\n\n\t\u002F\u002F 创建账户和用户(强关联操作)\n\tuser := &model.User{\n\t\tNickname:    dto.Nickname,\n\t\tAvatar:      dto.Avatar,\n\t\tLastLoginAt: time.Now(),\n\t}\n\taccount := &model.Account{\n\t\tEmail:       dto.Email,\n\t\tProvider:    dto.Provider,\n\t\tProviderUID: dto.ProviderUID,\n\t}\n\terr = uc.txRepo.ExecFunc(func(tx *gorm.DB) error {\n\t\tmaxCount := 10\n\t\tfor range maxCount {\n\t\t\t\u002F\u002F 生成唯一的UID\n\t\t\tuser.UID = uc.generateUniqueUserUID()\n\t\t\terr := uc.repo.CreateUserWithTx(ctx, tx, user)\n\n\t\t\tif err != nil {\n\t\t\t\tvar mysqlErr *mysql.MySQLError\n\t\t\t\tif errors.As(err, &mysqlErr) && mysqlErr.Number == 1062 {\n\t\t\t\t\tuc.logger.Log(log.LevelInfo, \"msg\", \"UserUID already exists, retrying\", \"userUID\", user.UID)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tuc.logger.Log(log.LevelError, \"msg\", \"Create user failed\", \"error\", err)\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\taccount.UID = user.UID\n\t\terr := uc.accountRepo.CreateAccountWithTx(ctx, tx, account)\n\t\tif err != nil {\n\t\t\tuc.logger.Log(log.LevelError, \"msg\", \"Create account failed\", \"error\", err)\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t})\n\n\tif err != nil {\n\t\tuc.logger.Log(log.LevelError, \"msg\", \"Create user and account failed\", \"error\", err)\n\t\treturn nil, false, err\n\t}\n\n\treturn &UserProfileVO{\n\t\tID:          user.ID,\n\t\tUID:         user.UID,\n\t\tCtime:       user.CreatedAt.Unix(), \u002F\u002F 创建时间\n\t\tNickname:    user.Nickname,         \u002F\u002F 昵称\n\t\tAvatar:      user.Avatar,           \u002F\u002F 头像\n\t\tEmail:       account.Email,         \u002F\u002F 邮箱\n\t\tProvider:    account.Provider,      \u002F\u002F 提供商\n\t\tProviderUID: account.ProviderUID,   \u002F\u002F 提供商UID\n\t}, true, nil\n}\n",[13,681,682,695,736,783,835,880,910,914,918,931,946,956,966,976,980,984,989,1058,1065,1087,1103,1135,1153,1161,1178,1187,1210,1228,1259,1277,1287,1308,1338,1349,1354,1369,1381,1393,1415,1427,1439,1451,1463,1475,1495,1504,1509,1517,1537,1547,1557,1576,1585,1606,1616,1626,1636,1645,1686,1701,1719,1731,1755,1779,1784,1805,1832,1881,1920,1936,1951,1985,2000,2013,2025,2036,2041,2056,2079,2098,2130,2143,2154,2159,2170,2181,2186,2203,2233,2250,2259,2264,2277,2287,2297,2318,2331,2344,2357,2370,2383,2401],{"__ignoreMap":77},[81,683,684,686,689,691,693],{"class":83,"data-line":84,"line":84},[81,685,206],{"class":91},[81,687,688],{"class":122}," UsersRepo",[81,690,621],{"class":91},[81,692,139],{"class":87},[81,694,217],{"class":142},[81,696,697,699,702,704,707,710,712,715,717,720,722,725,727,730,732,734],{"class":83,"data-line":116,"line":116},[81,698,150],{"class":149},[81,700,701],{"class":122},"CreateUser",[81,703,254],{"class":297},[81,705,706],{"class":257},"ctx",[81,708,709],{"class":122}," context",[81,711,273],{"class":87},[81,713,714],{"class":122},"Context",[81,716,508],{"class":87},[81,718,719],{"class":257},"user",[81,721,260],{"class":91},[81,723,724],{"class":122},"model",[81,726,273],{"class":87},[81,728,729],{"class":122},"User",[81,731,266],{"class":297},[81,733,139],{"class":87},[81,735,660],{"class":91},[81,737,738,740,743,745,747,749,751,753,755,757,759,761,763,765,767,769,771,773,775,777,779,781],{"class":83,"data-line":126,"line":126},[81,739,150],{"class":149},[81,741,742],{"class":122},"CreateUserWithTx",[81,744,254],{"class":297},[81,746,706],{"class":257},[81,748,709],{"class":122},[81,750,273],{"class":87},[81,752,714],{"class":122},[81,754,508],{"class":87},[81,756,362],{"class":257},[81,758,260],{"class":91},[81,760,367],{"class":122},[81,762,273],{"class":87},[81,764,44],{"class":122},[81,766,508],{"class":87},[81,768,719],{"class":257},[81,770,260],{"class":91},[81,772,724],{"class":122},[81,774,273],{"class":87},[81,776,729],{"class":122},[81,778,266],{"class":297},[81,780,139],{"class":87},[81,782,660],{"class":91},[81,784,785,787,790,792,794,796,798,800,802,805,808,810,813,815,817,819,821,823,825,827,829,831,833],{"class":83,"data-line":133,"line":133},[81,786,150],{"class":149},[81,788,789],{"class":122},"GetUserByEmailAndProvider",[81,791,254],{"class":297},[81,793,706],{"class":257},[81,795,709],{"class":122},[81,797,273],{"class":87},[81,799,714],{"class":122},[81,801,508],{"class":87},[81,803,804],{"class":257},"email",[81,806,807],{"class":91}," string",[81,809,508],{"class":87},[81,811,812],{"class":257},"provider",[81,814,807],{"class":91},[81,816,266],{"class":297},[81,818,139],{"class":87},[81,820,254],{"class":297},[81,822,228],{"class":91},[81,824,724],{"class":122},[81,826,273],{"class":87},[81,828,729],{"class":122},[81,830,508],{"class":87},[81,832,378],{"class":91},[81,834,195],{"class":297},[81,836,837,839,842,844,846,848,850,852,854,857,860,862,864,866,868,870,872,874,876,878],{"class":83,"data-line":146,"line":146},[81,838,150],{"class":149},[81,840,841],{"class":122},"GetUserByUID",[81,843,254],{"class":297},[81,845,706],{"class":257},[81,847,709],{"class":122},[81,849,273],{"class":87},[81,851,714],{"class":122},[81,853,508],{"class":87},[81,855,856],{"class":257},"UID",[81,858,859],{"class":91}," int",[81,861,266],{"class":297},[81,863,139],{"class":87},[81,865,254],{"class":297},[81,867,228],{"class":91},[81,869,724],{"class":122},[81,871,273],{"class":87},[81,873,729],{"class":122},[81,875,508],{"class":87},[81,877,378],{"class":91},[81,879,195],{"class":297},[81,881,882,884,887,889,891,893,895,897,899,902,904,906,908],{"class":83,"data-line":163,"line":163},[81,883,150],{"class":149},[81,885,886],{"class":122},"UpdateLoginInfo",[81,888,254],{"class":297},[81,890,706],{"class":257},[81,892,709],{"class":122},[81,894,273],{"class":87},[81,896,714],{"class":122},[81,898,508],{"class":87},[81,900,901],{"class":257},"userUID",[81,903,859],{"class":91},[81,905,266],{"class":297},[81,907,139],{"class":87},[81,909,660],{"class":91},[81,911,912],{"class":83,"data-line":168,"line":168},[81,913,237],{"class":142},[81,915,916],{"class":83,"data-line":180,"line":180},[81,917,130],{"emptyLinePlaceholder":129},[81,919,920,922,925,927,929],{"class":83,"data-line":192,"line":192},[81,921,206],{"class":91},[81,923,924],{"class":122}," UsersUsecase",[81,926,212],{"class":91},[81,928,139],{"class":87},[81,930,217],{"class":142},[81,932,933,935,938,941,943],{"class":83,"data-line":198,"line":198},[81,934,150],{"class":149},[81,936,937],{"class":87},"logger      ",[81,939,940],{"class":122},"log",[81,942,273],{"class":87},[81,944,945],{"class":122},"Logger\n",[81,947,948,950,953],{"class":83,"data-line":203,"line":203},[81,949,150],{"class":149},[81,951,952],{"class":87},"txRepo      ",[81,954,955],{"class":122},"TxRepo\n",[81,957,958,960,963],{"class":83,"data-line":220,"line":220},[81,959,150],{"class":149},[81,961,962],{"class":87},"repo        ",[81,964,965],{"class":122},"UsersRepo\n",[81,967,968,970,973],{"class":83,"data-line":234,"line":234},[81,969,150],{"class":149},[81,971,972],{"class":87},"accountRepo ",[81,974,975],{"class":122},"AccountRepo\n",[81,977,978],{"class":83,"data-line":240,"line":240},[81,979,237],{"class":142},[81,981,982],{"class":83,"data-line":245,"line":245},[81,983,130],{"emptyLinePlaceholder":129},[81,985,986],{"class":83,"data-line":283,"line":283},[81,987,988],{"class":610},"\u002F\u002F FirebaseFindOrCreateUser 查询或创建用户[Firebase]\n",[81,990,991,993,995,997,1000,1002,1005,1007,1009,1012,1014,1016,1018,1020,1022,1024,1027,1029,1032,1034,1036,1038,1040,1043,1045,1048,1050,1052,1054,1056],{"class":83,"data-line":300,"line":300},[81,992,248],{"class":91},[81,994,139],{"class":87},[81,996,254],{"class":142},[81,998,999],{"class":257},"uc ",[81,1001,228],{"class":91},[81,1003,1004],{"class":122},"UsersUsecase",[81,1006,266],{"class":142},[81,1008,139],{"class":87},[81,1010,1011],{"class":122},"FirebaseFindOrCreateUser",[81,1013,254],{"class":142},[81,1015,706],{"class":257},[81,1017,709],{"class":122},[81,1019,273],{"class":87},[81,1021,714],{"class":122},[81,1023,508],{"class":87},[81,1025,1026],{"class":257},"dto",[81,1028,260],{"class":91},[81,1030,1031],{"class":122},"UserDTO",[81,1033,266],{"class":142},[81,1035,139],{"class":87},[81,1037,254],{"class":142},[81,1039,228],{"class":91},[81,1041,1042],{"class":122},"UserProfileVO",[81,1044,508],{"class":87},[81,1046,1047],{"class":91},"bool",[81,1049,508],{"class":87},[81,1051,378],{"class":91},[81,1053,266],{"class":142},[81,1055,139],{"class":87},[81,1057,217],{"class":142},[81,1059,1060,1062],{"class":83,"data-line":310,"line":310},[81,1061,150],{"class":149},[81,1063,1064],{"class":610},"\u002F\u002F 判断账户是否存在\n",[81,1066,1067,1069,1072,1074,1077,1080,1082,1085],{"class":83,"data-line":319,"line":319},[81,1068,150],{"class":149},[81,1070,1071],{"class":87},"existAcc, err ",[81,1073,399],{"class":91},[81,1075,1076],{"class":87}," uc.accountRepo.",[81,1078,1079],{"class":122},"GetByEmailAndProvider",[81,1081,254],{"class":297},[81,1083,1084],{"class":87},"ctx, dto.Email, dto.Provider",[81,1086,195],{"class":297},[81,1088,1089,1091,1093,1095,1097,1099,1101],{"class":83,"data-line":324,"line":324},[81,1090,150],{"class":149},[81,1092,470],{"class":91},[81,1094,473],{"class":87},[81,1096,476],{"class":91},[81,1098,480],{"class":479},[81,1100,139],{"class":87},[81,1102,217],{"class":297},[81,1104,1105,1107,1109,1112,1114,1116,1118,1121,1123,1126,1128,1130,1133],{"class":83,"data-line":329,"line":329},[81,1106,150],{"class":149},[81,1108,150],{"class":149},[81,1110,1111],{"class":87},"uc.logger.",[81,1113,497],{"class":122},[81,1115,254],{"class":412},[81,1117,502],{"class":87},[81,1119,1120],{"class":153},"\"msg\"",[81,1122,508],{"class":87},[81,1124,1125],{"class":153},"\"Get account by email and provider failed\"",[81,1127,508],{"class":87},[81,1129,505],{"class":153},[81,1131,1132],{"class":87},", err",[81,1134,195],{"class":412},[81,1136,1137,1139,1141,1143,1145,1147,1150],{"class":83,"data-line":391,"line":391},[81,1138,150],{"class":149},[81,1140,150],{"class":149},[81,1142,288],{"class":91},[81,1144,480],{"class":479},[81,1146,508],{"class":87},[81,1148,1149],{"class":479},"false",[81,1151,1152],{"class":87},", err\n",[81,1154,1155,1157,1159],{"class":83,"data-line":435,"line":435},[81,1156,150],{"class":149},[81,1158,77],{"class":87},[81,1160,237],{"class":297},[81,1162,1163,1165,1167,1170,1172,1174,1176],{"class":83,"data-line":453,"line":453},[81,1164,150],{"class":149},[81,1166,470],{"class":91},[81,1168,1169],{"class":87}," existAcc ",[81,1171,476],{"class":91},[81,1173,480],{"class":479},[81,1175,139],{"class":87},[81,1177,217],{"class":297},[81,1179,1180,1182,1184],{"class":83,"data-line":465,"line":465},[81,1181,150],{"class":149},[81,1183,150],{"class":149},[81,1185,1186],{"class":610},"\u002F\u002F 账户存在, 继续查找用户\n",[81,1188,1189,1191,1193,1196,1198,1201,1203,1205,1208],{"class":83,"data-line":487,"line":487},[81,1190,150],{"class":149},[81,1192,150],{"class":149},[81,1194,1195],{"class":87},"existUser, err ",[81,1197,399],{"class":91},[81,1199,1200],{"class":87}," uc.repo.",[81,1202,841],{"class":122},[81,1204,254],{"class":412},[81,1206,1207],{"class":87},"ctx, existAcc.UID",[81,1209,195],{"class":412},[81,1211,1212,1214,1216,1218,1220,1222,1224,1226],{"class":83,"data-line":516,"line":516},[81,1213,150],{"class":149},[81,1215,150],{"class":149},[81,1217,470],{"class":91},[81,1219,473],{"class":87},[81,1221,476],{"class":91},[81,1223,480],{"class":479},[81,1225,139],{"class":87},[81,1227,217],{"class":412},[81,1229,1230,1232,1234,1236,1238,1240,1242,1244,1246,1248,1251,1253,1255,1257],{"class":83,"data-line":528,"line":528},[81,1231,150],{"class":149},[81,1233,150],{"class":149},[81,1235,150],{"class":149},[81,1237,1111],{"class":87},[81,1239,497],{"class":122},[81,1241,254],{"class":142},[81,1243,502],{"class":87},[81,1245,1120],{"class":153},[81,1247,508],{"class":87},[81,1249,1250],{"class":153},"\"Get user by uid failed\"",[81,1252,508],{"class":87},[81,1254,505],{"class":153},[81,1256,1132],{"class":87},[81,1258,195],{"class":142},[81,1260,1261,1263,1265,1267,1269,1271,1273,1275],{"class":83,"data-line":537,"line":537},[81,1262,150],{"class":149},[81,1264,150],{"class":149},[81,1266,150],{"class":149},[81,1268,288],{"class":91},[81,1270,480],{"class":479},[81,1272,508],{"class":87},[81,1274,1149],{"class":479},[81,1276,1152],{"class":87},[81,1278,1279,1281,1283,1285],{"class":83,"data-line":547,"line":547},[81,1280,150],{"class":149},[81,1282,150],{"class":149},[81,1284,77],{"class":87},[81,1286,237],{"class":412},[81,1288,1290,1292,1294,1296,1299,1302,1304,1306],{"class":83,"data-line":1289,"line":1289},31,[81,1291,150],{"class":149},[81,1293,150],{"class":149},[81,1295,470],{"class":91},[81,1297,1298],{"class":87}," existUser ",[81,1300,1301],{"class":91},"==",[81,1303,480],{"class":479},[81,1305,139],{"class":87},[81,1307,217],{"class":412},[81,1309,1311,1313,1315,1317,1319,1321,1323,1325,1328,1331,1333,1336],{"class":83,"data-line":1310,"line":1310},32,[81,1312,150],{"class":149},[81,1314,150],{"class":149},[81,1316,150],{"class":149},[81,1318,288],{"class":91},[81,1320,480],{"class":479},[81,1322,508],{"class":87},[81,1324,1149],{"class":479},[81,1326,1327],{"class":87},", errors.",[81,1329,1330],{"class":122},"New",[81,1332,254],{"class":142},[81,1334,1335],{"class":153},"\"account exists, but user not found\"",[81,1337,195],{"class":142},[81,1339,1341,1343,1345,1347],{"class":83,"data-line":1340,"line":1340},33,[81,1342,150],{"class":149},[81,1344,150],{"class":149},[81,1346,77],{"class":87},[81,1348,237],{"class":412},[81,1350,1352],{"class":83,"data-line":1351,"line":1351},34,[81,1353,130],{"emptyLinePlaceholder":129},[81,1355,1357,1359,1361,1363,1365,1367],{"class":83,"data-line":1356,"line":1356},35,[81,1358,150],{"class":149},[81,1360,150],{"class":149},[81,1362,288],{"class":91},[81,1364,291],{"class":91},[81,1366,1042],{"class":122},[81,1368,217],{"class":412},[81,1370,1372,1374,1376,1378],{"class":83,"data-line":1371,"line":1371},36,[81,1373,150],{"class":149},[81,1375,150],{"class":149},[81,1377,150],{"class":149},[81,1379,1380],{"class":87},"ID:          existUser.ID,\n",[81,1382,1384,1386,1388,1390],{"class":83,"data-line":1383,"line":1383},37,[81,1385,150],{"class":149},[81,1387,150],{"class":149},[81,1389,150],{"class":149},[81,1391,1392],{"class":87},"UID:         existUser.UID,\n",[81,1394,1396,1398,1400,1402,1405,1408,1410,1412],{"class":83,"data-line":1395,"line":1395},38,[81,1397,150],{"class":149},[81,1399,150],{"class":149},[81,1401,150],{"class":149},[81,1403,1404],{"class":87},"Ctime:       existUser.CreatedAt.",[81,1406,1407],{"class":122},"Unix",[81,1409,254],{"class":142},[81,1411,266],{"class":142},[81,1413,1414],{"class":87},",\n",[81,1416,1418,1420,1422,1424],{"class":83,"data-line":1417,"line":1417},39,[81,1419,150],{"class":149},[81,1421,150],{"class":149},[81,1423,150],{"class":149},[81,1425,1426],{"class":87},"Nickname:    existUser.Nickname,\n",[81,1428,1430,1432,1434,1436],{"class":83,"data-line":1429,"line":1429},40,[81,1431,150],{"class":149},[81,1433,150],{"class":149},[81,1435,150],{"class":149},[81,1437,1438],{"class":87},"Avatar:      existUser.Avatar,\n",[81,1440,1442,1444,1446,1448],{"class":83,"data-line":1441,"line":1441},41,[81,1443,150],{"class":149},[81,1445,150],{"class":149},[81,1447,150],{"class":149},[81,1449,1450],{"class":87},"Email:       existAcc.Email,\n",[81,1452,1454,1456,1458,1460],{"class":83,"data-line":1453,"line":1453},42,[81,1455,150],{"class":149},[81,1457,150],{"class":149},[81,1459,150],{"class":149},[81,1461,1462],{"class":87},"Provider:    existAcc.Provider,\n",[81,1464,1466,1468,1470,1472],{"class":83,"data-line":1465,"line":1465},43,[81,1467,150],{"class":149},[81,1469,150],{"class":149},[81,1471,150],{"class":149},[81,1473,1474],{"class":87},"ProviderUID: existAcc.ProviderUID,\n",[81,1476,1478,1480,1482,1484,1486,1488,1490,1492],{"class":83,"data-line":1477,"line":1477},44,[81,1479,150],{"class":149},[81,1481,150],{"class":149},[81,1483,77],{"class":87},[81,1485,460],{"class":412},[81,1487,508],{"class":87},[81,1489,1149],{"class":479},[81,1491,508],{"class":87},[81,1493,1494],{"class":479},"nil\n",[81,1496,1498,1500,1502],{"class":83,"data-line":1497,"line":1497},45,[81,1499,150],{"class":149},[81,1501,77],{"class":87},[81,1503,237],{"class":297},[81,1505,1507],{"class":83,"data-line":1506,"line":1506},46,[81,1508,130],{"emptyLinePlaceholder":129},[81,1510,1512,1514],{"class":83,"data-line":1511,"line":1511},47,[81,1513,150],{"class":149},[81,1515,1516],{"class":610},"\u002F\u002F 创建账户和用户(强关联操作)\n",[81,1518,1520,1522,1525,1527,1529,1531,1533,1535],{"class":83,"data-line":1519,"line":1519},48,[81,1521,150],{"class":149},[81,1523,1524],{"class":87},"user ",[81,1526,399],{"class":91},[81,1528,291],{"class":91},[81,1530,724],{"class":122},[81,1532,273],{"class":87},[81,1534,729],{"class":122},[81,1536,217],{"class":297},[81,1538,1540,1542,1544],{"class":83,"data-line":1539,"line":1539},49,[81,1541,150],{"class":149},[81,1543,150],{"class":149},[81,1545,1546],{"class":87},"Nickname:    dto.Nickname,\n",[81,1548,1550,1552,1554],{"class":83,"data-line":1549,"line":1549},50,[81,1551,150],{"class":149},[81,1553,150],{"class":149},[81,1555,1556],{"class":87},"Avatar:      dto.Avatar,\n",[81,1558,1560,1562,1564,1567,1570,1572,1574],{"class":83,"data-line":1559,"line":1559},51,[81,1561,150],{"class":149},[81,1563,150],{"class":149},[81,1565,1566],{"class":87},"LastLoginAt: time.",[81,1568,1569],{"class":122},"Now",[81,1571,254],{"class":412},[81,1573,266],{"class":412},[81,1575,1414],{"class":87},[81,1577,1579,1581,1583],{"class":83,"data-line":1578,"line":1578},52,[81,1580,150],{"class":149},[81,1582,77],{"class":87},[81,1584,237],{"class":297},[81,1586,1588,1590,1593,1595,1597,1599,1601,1604],{"class":83,"data-line":1587,"line":1587},53,[81,1589,150],{"class":149},[81,1591,1592],{"class":87},"account ",[81,1594,399],{"class":91},[81,1596,291],{"class":91},[81,1598,724],{"class":122},[81,1600,273],{"class":87},[81,1602,1603],{"class":122},"Account",[81,1605,217],{"class":297},[81,1607,1609,1611,1613],{"class":83,"data-line":1608,"line":1608},54,[81,1610,150],{"class":149},[81,1612,150],{"class":149},[81,1614,1615],{"class":87},"Email:       dto.Email,\n",[81,1617,1619,1621,1623],{"class":83,"data-line":1618,"line":1618},55,[81,1620,150],{"class":149},[81,1622,150],{"class":149},[81,1624,1625],{"class":87},"Provider:    dto.Provider,\n",[81,1627,1629,1631,1633],{"class":83,"data-line":1628,"line":1628},56,[81,1630,150],{"class":149},[81,1632,150],{"class":149},[81,1634,1635],{"class":87},"ProviderUID: dto.ProviderUID,\n",[81,1637,1639,1641,1643],{"class":83,"data-line":1638,"line":1638},57,[81,1640,150],{"class":149},[81,1642,77],{"class":87},[81,1644,237],{"class":297},[81,1646,1648,1650,1652,1655,1658,1660,1662,1664,1666,1668,1670,1672,1674,1676,1678,1680,1682,1684],{"class":83,"data-line":1647,"line":1647},58,[81,1649,150],{"class":149},[81,1651,396],{"class":87},[81,1653,1654],{"class":91},"=",[81,1656,1657],{"class":87}," uc.txRepo.",[81,1659,349],{"class":122},[81,1661,254],{"class":297},[81,1663,248],{"class":91},[81,1665,254],{"class":412},[81,1667,362],{"class":257},[81,1669,260],{"class":91},[81,1671,367],{"class":122},[81,1673,273],{"class":87},[81,1675,44],{"class":122},[81,1677,266],{"class":412},[81,1679,139],{"class":87},[81,1681,378],{"class":91},[81,1683,139],{"class":87},[81,1685,217],{"class":412},[81,1687,1689,1691,1693,1696,1698],{"class":83,"data-line":1688,"line":1688},59,[81,1690,150],{"class":149},[81,1692,150],{"class":149},[81,1694,1695],{"class":87},"maxCount ",[81,1697,399],{"class":91},[81,1699,1700],{"class":479}," 10\n",[81,1702,1704,1706,1708,1711,1714,1717],{"class":83,"data-line":1703,"line":1703},60,[81,1705,150],{"class":149},[81,1707,150],{"class":149},[81,1709,1710],{"class":91},"for",[81,1712,1713],{"class":91}," range",[81,1715,1716],{"class":87}," maxCount ",[81,1718,217],{"class":142},[81,1720,1722,1724,1726,1728],{"class":83,"data-line":1721,"line":1721},61,[81,1723,150],{"class":149},[81,1725,150],{"class":149},[81,1727,150],{"class":149},[81,1729,1730],{"class":610},"\u002F\u002F 生成唯一的UID\n",[81,1732,1734,1736,1738,1740,1743,1745,1748,1751,1753],{"class":83,"data-line":1733,"line":1733},62,[81,1735,150],{"class":149},[81,1737,150],{"class":149},[81,1739,150],{"class":149},[81,1741,1742],{"class":87},"user.UID ",[81,1744,1654],{"class":91},[81,1746,1747],{"class":87}," uc.",[81,1749,1750],{"class":122},"generateUniqueUserUID",[81,1752,254],{"class":297},[81,1754,195],{"class":297},[81,1756,1758,1760,1762,1764,1766,1768,1770,1772,1774,1777],{"class":83,"data-line":1757,"line":1757},63,[81,1759,150],{"class":149},[81,1761,150],{"class":149},[81,1763,150],{"class":149},[81,1765,396],{"class":87},[81,1767,399],{"class":91},[81,1769,1200],{"class":87},[81,1771,742],{"class":122},[81,1773,254],{"class":297},[81,1775,1776],{"class":87},"ctx, tx, user",[81,1778,195],{"class":297},[81,1780,1782],{"class":83,"data-line":1781,"line":1781},64,[81,1783,130],{"emptyLinePlaceholder":129},[81,1785,1787,1789,1791,1793,1795,1797,1799,1801,1803],{"class":83,"data-line":1786,"line":1786},65,[81,1788,150],{"class":149},[81,1790,150],{"class":149},[81,1792,150],{"class":149},[81,1794,470],{"class":91},[81,1796,473],{"class":87},[81,1798,476],{"class":91},[81,1800,480],{"class":479},[81,1802,139],{"class":87},[81,1804,217],{"class":297},[81,1806,1808,1810,1812,1814,1816,1819,1822,1824,1827,1829],{"class":83,"data-line":1807,"line":1807},66,[81,1809,150],{"class":149},[81,1811,150],{"class":149},[81,1813,150],{"class":149},[81,1815,150],{"class":149},[81,1817,1818],{"class":91},"var",[81,1820,1821],{"class":87}," mysqlErr ",[81,1823,228],{"class":91},[81,1825,1826],{"class":122},"mysql",[81,1828,273],{"class":87},[81,1830,1831],{"class":122},"MySQLError\n",[81,1833,1835,1837,1839,1841,1843,1845,1848,1851,1853,1856,1859,1862,1864,1866,1869,1872,1874,1877,1879],{"class":83,"data-line":1834,"line":1834},67,[81,1836,150],{"class":149},[81,1838,150],{"class":149},[81,1840,150],{"class":149},[81,1842,150],{"class":149},[81,1844,470],{"class":91},[81,1846,1847],{"class":87}," errors.",[81,1849,1850],{"class":122},"As",[81,1852,254],{"class":412},[81,1854,1855],{"class":87},"err, ",[81,1857,1858],{"class":91},"&",[81,1860,1861],{"class":87},"mysqlErr",[81,1863,266],{"class":412},[81,1865,139],{"class":87},[81,1867,1868],{"class":91},"&&",[81,1870,1871],{"class":87}," mysqlErr.Number ",[81,1873,1301],{"class":91},[81,1875,1876],{"class":479}," 1062",[81,1878,139],{"class":87},[81,1880,217],{"class":412},[81,1882,1884,1886,1888,1890,1892,1894,1896,1898,1900,1903,1905,1907,1910,1912,1915,1918],{"class":83,"data-line":1883,"line":1883},68,[81,1885,150],{"class":149},[81,1887,150],{"class":149},[81,1889,150],{"class":149},[81,1891,150],{"class":149},[81,1893,150],{"class":149},[81,1895,1111],{"class":87},[81,1897,497],{"class":122},[81,1899,254],{"class":142},[81,1901,1902],{"class":87},"log.LevelInfo, ",[81,1904,1120],{"class":153},[81,1906,508],{"class":87},[81,1908,1909],{"class":153},"\"UserUID already exists, retrying\"",[81,1911,508],{"class":87},[81,1913,1914],{"class":153},"\"userUID\"",[81,1916,1917],{"class":87},", user.UID",[81,1919,195],{"class":142},[81,1921,1923,1925,1927,1929,1931,1933],{"class":83,"data-line":1922,"line":1922},69,[81,1924,150],{"class":149},[81,1926,150],{"class":149},[81,1928,150],{"class":149},[81,1930,150],{"class":149},[81,1932,150],{"class":149},[81,1934,1935],{"class":91},"continue\n",[81,1937,1939,1941,1943,1945,1947,1949],{"class":83,"data-line":1938,"line":1938},70,[81,1940,150],{"class":149},[81,1942,150],{"class":149},[81,1944,150],{"class":149},[81,1946,150],{"class":149},[81,1948,77],{"class":87},[81,1950,237],{"class":412},[81,1952,1954,1956,1958,1960,1962,1964,1966,1968,1970,1972,1974,1977,1979,1981,1983],{"class":83,"data-line":1953,"line":1953},71,[81,1955,150],{"class":149},[81,1957,150],{"class":149},[81,1959,150],{"class":149},[81,1961,150],{"class":149},[81,1963,1111],{"class":87},[81,1965,497],{"class":122},[81,1967,254],{"class":412},[81,1969,502],{"class":87},[81,1971,1120],{"class":153},[81,1973,508],{"class":87},[81,1975,1976],{"class":153},"\"Create user failed\"",[81,1978,508],{"class":87},[81,1980,505],{"class":153},[81,1982,1132],{"class":87},[81,1984,195],{"class":412},[81,1986,1988,1990,1992,1994,1996,1998],{"class":83,"data-line":1987,"line":1987},72,[81,1989,150],{"class":149},[81,1991,150],{"class":149},[81,1993,150],{"class":149},[81,1995,150],{"class":149},[81,1997,288],{"class":91},[81,1999,525],{"class":87},[81,2001,2003,2005,2007,2009,2011],{"class":83,"data-line":2002,"line":2002},73,[81,2004,150],{"class":149},[81,2006,150],{"class":149},[81,2008,150],{"class":149},[81,2010,77],{"class":87},[81,2012,237],{"class":297},[81,2014,2016,2018,2020,2022],{"class":83,"data-line":2015,"line":2015},74,[81,2017,150],{"class":149},[81,2019,150],{"class":149},[81,2021,150],{"class":149},[81,2023,2024],{"class":91},"break\n",[81,2026,2028,2030,2032,2034],{"class":83,"data-line":2027,"line":2027},75,[81,2029,150],{"class":149},[81,2031,150],{"class":149},[81,2033,77],{"class":87},[81,2035,237],{"class":142},[81,2037,2039],{"class":83,"data-line":2038,"line":2038},76,[81,2040,130],{"emptyLinePlaceholder":129},[81,2042,2044,2046,2048,2051,2053],{"class":83,"data-line":2043,"line":2043},77,[81,2045,150],{"class":149},[81,2047,150],{"class":149},[81,2049,2050],{"class":87},"account.UID ",[81,2052,1654],{"class":91},[81,2054,2055],{"class":87}," user.UID\n",[81,2057,2059,2061,2063,2065,2067,2069,2072,2074,2077],{"class":83,"data-line":2058,"line":2058},78,[81,2060,150],{"class":149},[81,2062,150],{"class":149},[81,2064,396],{"class":87},[81,2066,399],{"class":91},[81,2068,1076],{"class":87},[81,2070,2071],{"class":122},"CreateAccountWithTx",[81,2073,254],{"class":142},[81,2075,2076],{"class":87},"ctx, tx, account",[81,2078,195],{"class":142},[81,2080,2082,2084,2086,2088,2090,2092,2094,2096],{"class":83,"data-line":2081,"line":2081},79,[81,2083,150],{"class":149},[81,2085,150],{"class":149},[81,2087,470],{"class":91},[81,2089,473],{"class":87},[81,2091,476],{"class":91},[81,2093,480],{"class":479},[81,2095,139],{"class":87},[81,2097,217],{"class":142},[81,2099,2101,2103,2105,2107,2109,2111,2113,2115,2117,2119,2122,2124,2126,2128],{"class":83,"data-line":2100,"line":2100},80,[81,2102,150],{"class":149},[81,2104,150],{"class":149},[81,2106,150],{"class":149},[81,2108,1111],{"class":87},[81,2110,497],{"class":122},[81,2112,254],{"class":297},[81,2114,502],{"class":87},[81,2116,1120],{"class":153},[81,2118,508],{"class":87},[81,2120,2121],{"class":153},"\"Create account failed\"",[81,2123,508],{"class":87},[81,2125,505],{"class":153},[81,2127,1132],{"class":87},[81,2129,195],{"class":297},[81,2131,2133,2135,2137,2139,2141],{"class":83,"data-line":2132,"line":2132},81,[81,2134,150],{"class":149},[81,2136,150],{"class":149},[81,2138,150],{"class":149},[81,2140,288],{"class":91},[81,2142,525],{"class":87},[81,2144,2146,2148,2150,2152],{"class":83,"data-line":2145,"line":2145},82,[81,2147,150],{"class":149},[81,2149,150],{"class":149},[81,2151,77],{"class":87},[81,2153,237],{"class":142},[81,2155,2157],{"class":83,"data-line":2156,"line":2156},83,[81,2158,130],{"emptyLinePlaceholder":129},[81,2160,2162,2164,2166,2168],{"class":83,"data-line":2161,"line":2161},84,[81,2163,150],{"class":149},[81,2165,150],{"class":149},[81,2167,288],{"class":91},[81,2169,544],{"class":479},[81,2171,2173,2175,2177,2179],{"class":83,"data-line":2172,"line":2172},85,[81,2174,150],{"class":149},[81,2176,77],{"class":87},[81,2178,460],{"class":412},[81,2180,195],{"class":297},[81,2182,2184],{"class":83,"data-line":2183,"line":2183},86,[81,2185,130],{"emptyLinePlaceholder":129},[81,2187,2189,2191,2193,2195,2197,2199,2201],{"class":83,"data-line":2188,"line":2188},87,[81,2190,150],{"class":149},[81,2192,470],{"class":91},[81,2194,473],{"class":87},[81,2196,476],{"class":91},[81,2198,480],{"class":479},[81,2200,139],{"class":87},[81,2202,217],{"class":297},[81,2204,2206,2208,2210,2212,2214,2216,2218,2220,2222,2225,2227,2229,2231],{"class":83,"data-line":2205,"line":2205},88,[81,2207,150],{"class":149},[81,2209,150],{"class":149},[81,2211,1111],{"class":87},[81,2213,497],{"class":122},[81,2215,254],{"class":412},[81,2217,502],{"class":87},[81,2219,1120],{"class":153},[81,2221,508],{"class":87},[81,2223,2224],{"class":153},"\"Create user and account failed\"",[81,2226,508],{"class":87},[81,2228,505],{"class":153},[81,2230,1132],{"class":87},[81,2232,195],{"class":412},[81,2234,2236,2238,2240,2242,2244,2246,2248],{"class":83,"data-line":2235,"line":2235},89,[81,2237,150],{"class":149},[81,2239,150],{"class":149},[81,2241,288],{"class":91},[81,2243,480],{"class":479},[81,2245,508],{"class":87},[81,2247,1149],{"class":479},[81,2249,1152],{"class":87},[81,2251,2253,2255,2257],{"class":83,"data-line":2252,"line":2252},90,[81,2254,150],{"class":149},[81,2256,77],{"class":87},[81,2258,237],{"class":297},[81,2260,2262],{"class":83,"data-line":2261,"line":2261},91,[81,2263,130],{"emptyLinePlaceholder":129},[81,2265,2267,2269,2271,2273,2275],{"class":83,"data-line":2266,"line":2266},92,[81,2268,150],{"class":149},[81,2270,288],{"class":91},[81,2272,291],{"class":91},[81,2274,1042],{"class":122},[81,2276,217],{"class":297},[81,2278,2280,2282,2284],{"class":83,"data-line":2279,"line":2279},93,[81,2281,150],{"class":149},[81,2283,150],{"class":149},[81,2285,2286],{"class":87},"ID:          user.ID,\n",[81,2288,2290,2292,2294],{"class":83,"data-line":2289,"line":2289},94,[81,2291,150],{"class":149},[81,2293,150],{"class":149},[81,2295,2296],{"class":87},"UID:         user.UID,\n",[81,2298,2300,2302,2304,2307,2309,2311,2313,2315],{"class":83,"data-line":2299,"line":2299},95,[81,2301,150],{"class":149},[81,2303,150],{"class":149},[81,2305,2306],{"class":87},"Ctime:       user.CreatedAt.",[81,2308,1407],{"class":122},[81,2310,254],{"class":412},[81,2312,266],{"class":412},[81,2314,508],{"class":87},[81,2316,2317],{"class":610},"\u002F\u002F 创建时间\n",[81,2319,2321,2323,2325,2328],{"class":83,"data-line":2320,"line":2320},96,[81,2322,150],{"class":149},[81,2324,150],{"class":149},[81,2326,2327],{"class":87},"Nickname:    user.Nickname,         ",[81,2329,2330],{"class":610},"\u002F\u002F 昵称\n",[81,2332,2334,2336,2338,2341],{"class":83,"data-line":2333,"line":2333},97,[81,2335,150],{"class":149},[81,2337,150],{"class":149},[81,2339,2340],{"class":87},"Avatar:      user.Avatar,           ",[81,2342,2343],{"class":610},"\u002F\u002F 头像\n",[81,2345,2347,2349,2351,2354],{"class":83,"data-line":2346,"line":2346},98,[81,2348,150],{"class":149},[81,2350,150],{"class":149},[81,2352,2353],{"class":87},"Email:       account.Email,         ",[81,2355,2356],{"class":610},"\u002F\u002F 邮箱\n",[81,2358,2360,2362,2364,2367],{"class":83,"data-line":2359,"line":2359},99,[81,2361,150],{"class":149},[81,2363,150],{"class":149},[81,2365,2366],{"class":87},"Provider:    account.Provider,      ",[81,2368,2369],{"class":610},"\u002F\u002F 提供商\n",[81,2371,2373,2375,2377,2380],{"class":83,"data-line":2372,"line":2372},100,[81,2374,150],{"class":149},[81,2376,150],{"class":149},[81,2378,2379],{"class":87},"ProviderUID: account.ProviderUID,   ",[81,2381,2382],{"class":610},"\u002F\u002F 提供商UID\n",[81,2384,2386,2388,2390,2392,2394,2397,2399],{"class":83,"data-line":2385,"line":2385},101,[81,2387,150],{"class":149},[81,2389,77],{"class":87},[81,2391,460],{"class":297},[81,2393,508],{"class":87},[81,2395,2396],{"class":479},"true",[81,2398,508],{"class":87},[81,2400,1494],{"class":479},[81,2402,2404],{"class":83,"data-line":2403,"line":2403},102,[81,2405,237],{"class":142},[2407,2408,2409],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sSDpw, html code.shiki .sSDpw{--shiki-default:#005cc5;--shiki-dark:#79b8ff}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sJX2D, html code.shiki .sJX2D{--shiki-default:#e36209;--shiki-dark:#ffab70}html pre.shiki code .sqkie, html code.shiki .sqkie{--shiki-default:#5a32a3;--shiki-dark:#b392f0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":77,"searchDepth":133,"depth":133,"links":2411},[2412],{"id":70,"depth":116,"text":70},[2414],"微服务","2026-04-12","介绍 Kratos 项目中的事务抽象方法，并通过接口解耦解决 data 与 biz 层之间的循环依赖。",false,"md",null,{"slots":2421},{},"\u002F2026\u002F04\u002Fkratos-transaction",{"text":2424,"minutes":2425,"time":2426,"words":2427},"4 min read",3.2,192000,640,{"title":5,"description":2416},{"loc":2422},"posts\u002F2026\u002F04\u002Fkratos-transaction",[15,2432],"事务管理","tech","G3BDsbubqdyDQawpr0YVVjL3hYk-G2r7lsJ82Qd59Ok",[2436,2440],{"title":2437,"path":2438,"stem":2439,"date":2415,"type":2433,"children":-1},"Kratos 服务注册与发现实践","\u002F2026\u002F04\u002Fkratos-svc-discover","posts\u002F2026\u002F04\u002Fkratos-svc-discover",{"title":2441,"path":2442,"stem":2443,"date":2415,"type":2433,"children":-1},"VS Code 中配置 Protobuf 开发环境","\u002F2026\u002F04\u002Fkratos-vscode-proto","posts\u002F2026\u002F04\u002Fkratos-vscode-proto",1786555054224]