Closed JackChanw closed 6 months ago
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
If you want to operate multiple DBs, how can you add them more conveniently, through different configurations, or by implementing a configuration list? If it is a configuration list, how to use it, how about DB.Use("xxx") compatible?
🤖
你好,@JackChanw!我是Dosu,一个能帮你解决问题,回答问题,甚至成为贡献者的机器人。虽然我是一个机器人,但我还是会尽我所能来帮助你,同时等待人类维护者的回答。我正在查看你的问题,并将在不久的将来给你一个完整的答案。🐸
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
🤖
Hello @JackChanw! I'm Dosu, a bot that can help you solve problems, answer questions, and even become a contributor. Even though I'm a robot, I'll try my best to help you while waiting for answers from the human maintainers. I'm looking at your question and will give you a complete answer in the near future. 🐸
给你个参考,我是这么做的:
我在 internal/data
目录下创建了个 database.go
文件,
假设我接入的是 gorm
,我会定义一个结构体,大致如下:
代码做了适当删减,可能有误,但大意是这个意思
package data
import (
"time"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"example/internal/conf"
)
type DB struct {
*gorm.DB
One *gorm.DB
Two *gorm.DB
}
func NewDB() (*DB, error) {
def, err := gorm.New(....)
if err != nil {
return nil, err
}
one, err := gorm.New(...)
two, err := gorm.New(...)
return &DB{
DB: def,
One: one,
Two: two,
}
}
其他地方用的话,就直接可以引入这个 DB
结构体了.
db.Where(...)
db.One.Where(...)
db.Two.Where(...)
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
To give you a reference, this is what I did:
I created a database.go
file in the internal/data
directory.
Suppose I am connected to gorm
, I will define a structure, roughly as follows:
The code has been appropriately shortened. There may be errors, but the general idea is this.
package data
import (
"time"
"gorm.io/gorm" "gorm.io/gorm/logger"
"example/internal/conf" )
type DB struct {
*gorm.DB
One gorm.DB Two gorm.DB }
func NewDB() (*DB, error) {
def, err := gorm.New(....) if err != nil { return nil, err }
one, err := gorm.New(...) two, err := gorm.New(...)
return &DB{ DB:def, One: one, Two: two, } }
1. If used elsewhere, you can directly introduce this `DB` structure.
```go
db.Where(...)
db.One.Where(...)
db.Two.Where(...)
https://github.com/nextmicro/next-component/blob/main/gorm/option.go
//{
// "mysql": {
// "default": {
// "master": 'user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local',
// "slaves": [
// 'user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local',
// 'user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local'
// ]
// }
// }
//}
func (c *Component) Instance(name ...string) *gorm.DB {
group := defaultName
if len(name) > 0 && name[0] != "" {
group = name[0]
}
value, ok := c.clients.Load(group)
if !ok {
panic("not found instance" + group)
}
return value.(*gorm.DB)
}
Based on the information provided, your approach to handling multiple database instances seems to be on the right track. You've encapsulated the database instances within a struct (DB
) and are using methods to interact with each instance. This is a good practice as it promotes encapsulation and makes your code more organized and maintainable.
However, there are a few things you might want to consider:
Error Handling: In your NewDB()
function, you're creating three instances of gorm.DB
(default, one, and two). However, you're not handling errors that might occur when creating the second and third instances. If an error occurs when creating one
or two
, it will be ignored and the function will return a DB
instance with a nil
value for one
or two
. This could lead to a runtime panic when you try to use db.One.Where(...)
or db.Two.Where(...)
elsewhere in your code. Make sure to handle these errors appropriately.
Dependency Injection: Instead of creating the gorm.DB
instances within the NewDB()
function, consider passing them as arguments to the function. This makes your code more flexible and testable, as you can pass different gorm.DB
instances depending on the context (e.g., a real instance for production code, a mock instance for testing).
Interface Abstraction: Consider defining an interface for the operations you want to perform on the database (e.g., Read
, Write
). Then, make sure your DB
struct implements this interface. This allows you to abstract away the specific database technology (in this case, GORM) and makes your code more modular and easier to test.
Here's how you might modify your code to incorporate these suggestions:
package data
import (
"errors"
"time"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"example/internal/conf"
)
type DB struct {
*gorm.DB
One *gorm.DB
Two *gorm.DB
}
type DBHandler interface {
Where(...interface{}) *gorm.DB
}
func NewDB(def, one, two *gorm.DB) (*DB, error) {
if def == nil || one == nil || two == nil {
return nil, errors.New("nil database instance")
}
return &DB{
DB: def,
One: one,
Two: two,
}, nil
}
In your code where you use the DB
struct, you can now do something like this:
var dbHandler data.DBHandler = db
dbHandler.Where(...)
dbHandler.One.Where(...)
dbHandler.Two.Where(...)
This way, you're programming against an interface (DBHandler
), not a concrete implementation (DB
), which is a good practice in Go and in programming in general.
Remember, these are just suggestions and the actual implementation might vary based on your specific use case and requirements. I hope this helps! If you have any more questions, feel free to ask.
如果要对多个DB进行操作的话,如何比较方便的添加进去,是通过不同的配置,还是实现一个配置列表,如果是配置列表,在使用上怎么用呢,DB.Use("xxx") 怎么兼容?