单体应用程序设计中的一个常见模式是将业务逻辑委托给专用服务,将开放事务作为例如 Java 中的 javax.persistence.EntityTransaction
实例或 Go 中的 sql.Transaction
传入。
Go 示例:
// business.go
type BusinessLogicService interface {
DoSomething(tx *sql.Transaction)
}
type businessLogicService struct {
}
func (s *BusinessLogicService) DoSomething(tx *sql.Transaction) {
tx.ExecuteContext(.....)
}
func NewBusinessLogicService() {
return &businessLogicService{}
}
// server.go
ctx := context.Background()
tx, err := db.BeginTx(ctx)
if err != nil {
log.Fatal(err)
}
bls := business.NewBusinessLogicService()
bls.DoSomething(tx)
tx.Commit()
在这些组件中的每一个都以不同的语言/运行时实现的架构中能否实现相同的效果?在这样的应用程序中,Postgres 负责执行与数据库事务相关的“簿记”。在我看来,应该可以将事务的类似“句柄”传递给另一个进程以读取其状态和附加操作。
例如,等效的业务逻辑作为具有以下定义的 gRPC 服务提供:
message TransactionInfo {
string transaction_id = 1;
}
message DoSomethingRequest {
TransactionInfo transaction_info = 1;
}
message DoSomethingResponse {
}
service BusinessLogicService {
rpc DoSomething(DoSomethingRequest) returns (DoSomethingResponse)
}
服务器进程BEGIN
处理事务并传递对此 BusinessLogicService 的引用。
ctx := context.Background()
tx, err := db.BeginTx(ctx)
if err != nil {
log.Fatal(err)
}
conn, err := grpc.Dial(*serverAddr, opts...)
if err != nil {
...
}
defer conn.Close()
bls := pb.NewBusinessLogicClient()
/// SOMEHOW PASS THE TX OBJECT TO THE REMOTE SERVICE
txObj := &pb.TransactionInfo{....???????????.....}
result := bls.DoSomething(txObj)
tx.Commit()
这对 Postgres 或其他 DBMS 是否可行?