在事务中插入的当前行的ID是什么?

huangapple go评论146阅读模式
英文:

Need the ID of the current row inserted within a transaction

问题

在一个事务中,我正在插入一行

我如何访问并返回插入行的ID。如下所示的代码中(请参见注释// 返回最后插入的ID),我尝试使用**LastInsertedId()**函数,但它返回了一个错误。

顺便说一下,我正在使用Postgres。

我在这里漏掉了什么?
谢谢!

/**
 * 创建订单并返回其ID。
 */
func createOrder(w http.ResponseWriter, r *http.Request) (orderID int) {

	// 开始事务。
	tx, err := db.Begin()
	if err != nil {
		log.Fatal(err)
	}

	// 数据库查询。
	sqlQuery := `INSERT INTO ORDER_CUSTOMER
		(CUSTOMER_ID)
		VALUES ($1)
		RETURNING ID`

	// 准备语句。
	stmt, err := tx.Prepare(sqlQuery)
	if err != nil {
		log.Fatal(err)
		return
	}

	// 延迟关闭。
	defer stmt.Close()

	customerEmail := validateSession(r)
	ID := getIDFromCustomer(customerEmail)
	order := order{}
	order.CustomerID = ID

	// 执行。
	ret, err := stmt.Exec(order.CustomerID)

	// 回滚。
	if err != nil {
		tx.Rollback()
		e := errors.New(err.Error())
		msg.Warning = e.Error()
		tpl.ExecuteTemplate(w, "menu.gohtml", msg)
		return
	}

	// 返回最后插入的ID。
	lastID, err := ret.LastInsertId()
	if err != nil {
		orderID = 0
	} else {
		orderID = int(lastID)
	}

	// 提交。
	tx.Commit()

	return orderID
} // createOrder

这是一个目前可行的解决方案,欢迎进一步改进。

/**
 * 创建订单并返回其ID。
 */
func createOrder(w http.ResponseWriter, r *http.Request) (orderID int) {

	// 开始事务。
	tx, err := db.Begin()
	if err != nil {
		log.Fatal(err)
	}

	// 数据库查询。
	sqlQuery := `INSERT INTO ORDER_CUSTOMER
		(CUSTOMER_ID)
		VALUES ($1)
		RETURNING ID`

	// 准备语句。
	stmt, err := tx.Prepare(sqlQuery)
	if err != nil {
		log.Fatal(err)
		return
	}

	// 延迟关闭。
	defer stmt.Close()

	customerEmail := validateSession(r)
	ID := getIDFromCustomer(customerEmail)
	order := order{}
	order.CustomerID = ID

	// 执行。
	_, err = stmt.Exec(order.CustomerID)

	// 回滚。
	if err != nil {
		tx.Rollback()
		e := errors.New(err.Error())
		msg.Warning = e.Error()
		tpl.ExecuteTemplate(w, "menu.gohtml", msg)
		return
	}

	// 返回最后插入的ID。
	//lastID, err := ret.LastInsertId()
	err = stmt.QueryRow(order.CustomerID).Scan(&orderID)
	if err != nil {
		orderID = 0
	}

	// 提交。
	tx.Commit()

	return orderID
} // createOrder
英文:

Within a transaction I'm inserting a row.

How can I access and return the ID of the inserted row.
As you can see in the code below(See under comment // Return last Inserted ID.) I tried to use the LastInsertedId() function, but it gives me an error back.

Btw, I'm using Postgres.

What am I missing here?
Thx!

/**
* Creates order and returns its ID.
*/
func createOrder(w http.ResponseWriter, r *http.Request) (orderID int) {
// Begin.
tx, err := db.Begin()
if err != nil {
log.Fatal(err)
}
// Db query.
sqlQuery := `INSERT INTO ORDER_CUSTOMER
(CUSTOMER_ID)
VALUES ($1)
RETURNING ID`
// Prepare.
stmt, err := tx.Prepare(sqlQuery)
if err != nil {
log.Fatal(err)
return
}
// Defer Close.
defer stmt.Close()
customerEmail := validateSession(r)
ID := getIDFromCustomer(customerEmail)
order := order{}
order.CustomerID = ID
// Exec.
ret, err := stmt.Exec(order.CustomerID)
// Rollback.
if err != nil {
tx.Rollback()
e := errors.New(err.Error())
msg.Warning = e.Error()
tpl.ExecuteTemplate(w, "menu.gohtml", msg)
return
}
// Return last Inserted ID.
lastID, err := ret.LastInsertId()
if err != nil {
orderID = 0
} else {
orderID = int(lastID)
}
// Commit.
tx.Commit()
return orderID
} // createOrder

Here is a working solution for now, further improvement is welcomed.

/**
* Creates order and returns its ID.
*/
func createOrder(w http.ResponseWriter, r *http.Request) (orderID int) {
// Begin.
tx, err := db.Begin()
if err != nil {
log.Fatal(err)
}
// Db query.
sqlQuery := `INSERT INTO ORDER_CUSTOMER
(CUSTOMER_ID)
VALUES ($1)
RETURNING ID`
// Prepare.
stmt, err := tx.Prepare(sqlQuery)
if err != nil {
log.Fatal(err)
return
}
// Defer Close.
defer stmt.Close()
customerEmail := validateSession(r)
ID := getIDFromCustomer(customerEmail)
order := order{}
order.CustomerID = ID
// Exec.
_, err = stmt.Exec(order.CustomerID)
// Rollback.
if err != nil {
tx.Rollback()
e := errors.New(err.Error())
msg.Warning = e.Error()
tpl.ExecuteTemplate(w, "menu.gohtml", msg)
return
}
// Return last Inserted ID.
//lastID, err := ret.LastInsertId()
err = stmt.QueryRow(order.CustomerID).Scan(&orderID)
if err != nil {
orderID = 0
}
// Commit.
tx.Commit()
return orderID
} // createOrder

答案1

得分: 5

这是因为你在Go中使用的PostgreSQL驱动程序不支持LastInsertedId()函数。你没有提到你使用的是哪个驱动程序,但我在使用github.com/lib/pq时遇到过这个问题。

解决方法是在你的原始示例中使用QueryRow而不是Exec。只需确保在查询中使用RETURNING ID,并将其视为选择语句。

这是一个示例(我没有测试过,可能会漏掉一些东西,但你可以理解思路):

func createOrder(w http.ResponseWriter, r *http.Request) (orderID int) {

    // 开始事务。
    tx, err := db.Begin()
    if err != nil {
        log.Fatal(err)
    }

    // 数据库查询。
    sqlQuery := `INSERT INTO ORDER_CUSTOMER
        (CUSTOMER_ID)
        VALUES ($1)
        RETURNING ID`

    // 准备语句。
    stmt, err := tx.Prepare(sqlQuery)
    if err != nil {
        log.Fatal(err)
        return
    }

    // 延迟关闭。
    defer stmt.Close()

    customerEmail := validateSession(r)
    ID := getIDFromCustomer(customerEmail)
    order := order{}
    order.CustomerID = ID

    // 执行。
    var orderID int // 或者你使用的其他类型
    err := stmt.QueryRow(order.CustomerID).Scan(&orderID)

    // 回滚。
    if err != nil {
        // 如果出现错误,将orderID设置为0,就像你的原始代码中一样
        orderID = 0
        tx.Rollback()
        e := errors.New(err.Error())
        msg.Warning = e.Error()
        tpl.ExecuteTemplate(w, "menu.gohtml", msg)
        return
    }

    // 提交。
    tx.Commit()

    return orderID
} // createOrder

希望对你有帮助!

英文:

This happens because the postgresql driver you are using for go doesn't supports the LastInsertedId() function. You didn't say which driver you are using but I have had this issue working with github.com/lib/pq.

The answer to this is to use QueryRow insted of Exec in your original example. Just make sure you are using RETURNING ID on your query and treat it as if it was a select.

Here is an example (I didn't test this and I might be missing something but you get the idea):

func createOrder(w http.ResponseWriter, r *http.Request) (orderID int) {
// Begin.
tx, err := db.Begin()
if err != nil {
log.Fatal(err)
}
// Db query.
sqlQuery := `INSERT INTO ORDER_CUSTOMER
(CUSTOMER_ID)
VALUES ($1)
RETURNING ID`
// Prepare.
stmt, err := tx.Prepare(sqlQuery)
if err != nil {
log.Fatal(err)
return
}
// Defer Close.
defer stmt.Close()
customerEmail := validateSession(r)
ID := getIDFromCustomer(customerEmail)
order := order{}
order.CustomerID = ID
// Exec.
var orderID int // Or whatever type you are using
err := stmt.QueryRow(order.CustomerID).Scan(&orderID)
// Rollback.
if err != nil {
//if something goes wrong set the orderID to 0 as in your original code
orderID = 0
tx.Rollback()
e := errors.New(err.Error())
msg.Warning = e.Error()
tpl.ExecuteTemplate(w, "menu.gohtml", msg)
return
}
// Commit.
tx.Commit()
return orderID
} // createOrder

huangapple
  • 本文由 发表于 2017年8月15日 01:06:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/45679537.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定