Привет, мне нужно загрузить огромное количество мелкой текстовой информации в MySQL.К сожалению, в MySQL нет BulkOp, поэтому я пытаюсь использовать go-рутины для распараллеливания транзакций.Проблема в том, что все эти параллельные и гоночные вещи сводят меня с ума.
И я не уверен, хорошо ли то, к чему я прихожу.
Упрощенный код выглядит следующим образом: огромный файл сканируется построчно, и строки добавляются к срезу, когда размер среза равен 1000
sem := make(chan int, 10) //Transactions pool
sem2 := make(chan int) // auxiliary blocking semaphore
for scanner.Scan() {
line := scanner.Text()
lines = append(lines, line)
if len(lines) > 1000 {
sem <- 1 //keep max 10 transactions
go func(mylines ...lineT) {
// I use variadic, to avoid issue with pointers
// I want to path data by values.
<-sem2 // all lines of slice copied, release the lock
gopher(mylines...) //gopher does the transaction by iterating
//every each line. And here I may use slice
//I think.
<-sem //after transaction done, release the lock
}(lines...)
sem2 <- 1 //this to ensure, that slice will be reset,
//after values are copied to func, otherwise
//lines could be nil before the goroutine fired.
lines = nil //reset slice
}
}
Как лучше решить проблему,Я знаю, что мог бы сделать что-то для массового импорта через утилиты MySQL, но это невозможно.Я также не могу сделать это как INSERT со многими значениями VALUES ("1", "2), ("3", "4")
, потому что он не экранирует должным образом, и я просто получаю ошибки.
Так выглядит странно, но не как мой первый подход
func gopher2(lines []lineT) {
q := "INSERT INTO main_data(text) VALUES "
var aur []string
var inter []interface{}
for _, l := range lines {
aur = append(aur, "(?)")
inter = append(inter, l)
}
q = q + strings.Join(aur, ", ")
if _, err := db.Exec(q, inter...); err != nil {
log.Println(err)
}
}