1 回答

TA貢獻1752條經驗 獲得超4個贊
您選擇了一個不好的示例,因為您通常會重用數據庫連接,而不是每次使用時打開和關閉一個數據庫連接。因此,您可以將數據庫連接傳遞給使用它的函數,并在調用者中進行資源管理,而不需要資源管理器:
// Imports etc omitted for the sake of readability
func PingHandler(db *sql.DB) http.Handler (
? ? return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
? ? ? ?if err := db.ping(); err != nil {
? ? ? ? ? http.Error(w,e.Error(),500)
? ? ? ?}
? ? })
)
func main(){
? ? db,_ := sql.Open("superdb",os.Getenv("APP_DBURL"))
? ? // Note the db connection will only be closed if main exits.
? ? defer db.Close()
? ? // Setup the server
? ? http.Handle("/ping", PingHandler(db))
? ? server := &http.Server{Addr: ":8080"}
? ? // Create a channel for listening on SIGINT, -TERM and -QUIT
? ? stop := make(chan os.Signal, 1)
? ? // Register channel to be notified on said signals
? ? signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
? ? go func(){
? ? ? ? ? ? // When we get the signal...
? ? ? ? ? ? <- stop
? ? ? ? ? ? ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
? ? ? ? ? ? // ... we gracefully shut down the server.
? ? ? ? ? ? // That ensures that no new connections, which potentially
? ? ? ? ? ? // would use our db connection, are accepted.
? ? ? ? ? ? if err := server.Shutdown(ctx); err != nil {
? ? ? ? ? ? ? ? // handle err
? ? ? ? ? ? }
? ? }
? ? // This blocks until the server is shut down.
? ? // AFTER it is shut down, main exits, the deferred calls are executed.
? ? // In this case, the database connection is closed.
? ? // And it is closed only after the last handler call which uses the connection is finished.
? ? // Mission accomplished.
? ? server.ListenAndServe()
}
因此,在這個示例中,不需要資源管理器,而且老實說,我想不出真正需要資源管理器的示例。在極少數情況下,我需要類似的東西,我使用了sync.Pool
.
但是,對于 gRPC 客戶端連接,也無需維護池:
[...]但是,ClientConn 應該自行管理連接,因此如果連接斷開,它將自動重新連接。如果您有多個后端,則可以連接到其中多個后端并在它們之間實現負載平衡。[...]
因此,同樣的原則適用:創建一個連接(池),根據需要傳遞它,確保在完成所有工作后關閉它。
不要將資源管理隱藏在其他地方,而是盡可能靠近使用資源的代碼并盡可能明確地管理資源。
- 1 回答
- 0 關注
- 141 瀏覽
添加回答
舉報