2016-04-19 2 views
1

У меня есть небольшое приложение Heroku, в котором я печатаю имя и возраст из каждой строки после выполнения запроса.Можно ли вывести golang db.Query() вывод в строку?

Я хочу избежать циклов rows.Next(), Scan() .. и просто хочу показать, какая база данных вернулась после выполнения запроса, которая может быть некоторыми данными или ошибкой.

Можем ли мы напрямую сбрасывать данные в строку для печати?

rows, err := db.Query("SELECT name FROM users WHERE age = $1", age) 

if err != nil { 
    log.Fatal(err) 
} 
for rows.Next() { 
    var name string 
    if err := rows.Scan(&name); err != nil { 
     log.Fatal(err) 
    } 
    fmt.Printf("%s is %d\n", name, age) 
} 
if err := rows.Err(); err != nil { 
    log.Fatal(err) 
} 

ответ

2

Довольно много: Нет

Метод запроса будет возвращать указатель на Ряды STRUCT:

func (db *DB) Query(query string, args ...interface{}) (*Rows, error) 

Если вы печатаете, что (fmt.Printf("%#v\n", rows)), вы увидите что-то такое как:

&sql.Rows{dc:(*sql.driverConn)(0xc8201225a0), releaseConn:(func(error)(0x4802c0), rowsi:(*pq.rows)(0xc820166700), closed:false, lastcols:[]driver.Value(nil), lasterr:error(nil), closeStmt:driver.Stmt(nil)}

... вероятно, не то, что вы хотите.

Те соответствуют рядам структуры из sql package (вы увидите поля не экспортируются):

type Rows struct { 
    dc   *driverConn // owned; must call releaseConn when closed to release 
    releaseConn func(error) 
    rowsi  driver.Rows 

    closed bool 
    lastcols []driver.Value 
    lasterr error  // non-nil only if closed is true 
    closeStmt driver.Stmt // if non-nil, statement to Close on close 
    } 

Вы увидите []driver.Value (интерфейс из пакета драйверов), который выглядит как где мы можем ожидать найти полезные, а может быть, и человекочитаемые данные. Но при прямом распечатке оно не кажется полезным, оно даже пустое ... Поэтому вам нужно как-то получить основную информацию. Пакет sql дает нам следующий метод, чтобы начать с:

Далее подготавливает следующую строку результатов для чтения методом сканирования. Он возвращает true при успешном завершении, или false, если нет следующей строки результата или ошибки, возникшей при ее подготовке. Для устранения различий между двумя случаями следует проконсультироваться с Err .

Каждому вызову сканирования, даже первому, должен предшествовать вызов Next.

Следующая собирается сделать [] driver.Value тот же размер, что и число столбцов, у меня есть, которая доступна (в пакете SQL) через driver.Rows (поле rowsi) и заполнить его значения из запроса.

После вызова rows.Next(), если вы сделали то же fmt.Printf("%#v\n", rows) теперь вы должны видеть, что [] diver.Value больше не пуст, но она по-прежнему не будет ничего, что вы можете прочитать, что более вероятно что-то напоминающее: []diver.Value{[]uint8{0x47, 0x65...

А поскольку поле не экспортируется, вы даже не можете попробовать его преобразовать в нечто более значимое. Но пакет sql дает нам возможность что-то делать с данными, которые являются Scan.

Метод сканирования довольно краткий, с длинными комментариями, которые я не буду вставлять сюда, но действительно важный бит заключается в том, что он пробегает столбцы в текущей строке, полученной из метода Next, и вызывает convertAssign(dest[i], sv), который вы можно увидеть здесь: https://golang.org/src/database/sql/convert.go

Это довольно длинный, но на самом деле относительно простой, он, по сути, включает тип источника и назначения и преобразует его там, где он может, и копирует из источника в пункт назначения; функция комментарии сообщают нам:

convertAssign копирует для уничтожения значения в src, конвертируя его, если это возможно. Ошибка возвращается, если копия приведет к потере информации. dest должен быть типом указателя.

Итак, теперь у вас есть метод (Сканирование), который вы можете вызывать напрямую и какие руки перевернули значения. Вышеприведенный пример кода отлично (за исключением, возможно, вызова Fatal() при ошибке сканирования).

Важно понимать, что пакет sql должен работать с определенным драйвером, который, в свою очередь, реализован для конкретного программного обеспечения базы данных, поэтому происходит некоторая работа за кулисами.

Я думаю, что ваша лучшая ставка, если вы хотите скрыть/обобщить весь запрос Query() ---> Next() ---> Scan() - это перебросить его в другую функцию, которая делает это за кулисами. .. напишите пакет, в котором вы абстрагируетесь от реализации более высокого уровня, так как пакет sql абстрагирует некоторые детали, относящиеся к драйверу, преобразование и копирование, заполнение строк и т. д.

+0

Спасибо, это было довольно хорошо анализ. – Mozfox

Смежные вопросы