neo4j / neo4j-go-driver

Neo4j Bolt Driver for Go
Apache License 2.0
485 stars 68 forks source link

In a manual transaction, the transaction rollback operation cannot be successfully executed after an error is encountered (manual), and the prompt message is the error message before rollback. #490

Closed ws-spring closed 1 year ago

ws-spring commented 1 year ago

Guidelines

The same link is under a manual transaction, after encountering an error, the transaction rollback operation cannot be performed (manual), and the prompt information is the error prompt before the rollback. java-driver can roll back in the same situation.

Example bug report

I got connection reset by peer errors.

Neo4j Version: 4.4 Community
Neo4j Mode: Single instance
Driver version: Go driver 4.4.5 Operating System: window 11

Steps to reproduce

  1. Start Neo4j on a AWS instance
  2. Run a query with the driver
  3. run("CREATE (marko:person{name: "marko", age: 29})")

    Execute an illegal statement

  4. run("CREATE (marko:personname: "marko", age: 29})")
  5. do rollback

    Expected behavior

  6. Rollback can be executed successfully

    Actual behavior

  7. Rollback is reported as an error message in step 5
fbiville commented 1 year ago

Hello @ws-spring, thanks for the report. This difference of behavior between drivers in 4.4 has already been identified.

The bad news is that the behavior cannot be changed in 4.4, as that would be a breaking change for some.

The good news is that the implementation has been much improved in 5.x so I would recommend upgrading as the best way forward.

If upgrading is not an option, you will have to work around 4.4 transaction unideal behavior and do something like this:

    tx, err := session.BeginTransaction()
    if err != nil {
        handle(err)
        return
    }
    result, err := tx.Run("<cypher query>", params)
    if err != nil {
        _ = tx.Rollback()
        handle(err)
        return
    }
    // will cause most query errors to show up here
    if _, err := result.Consume(); err != nil {
        _ = tx.Rollback()
        handle(err)
        return
    }
    // only at this point rollback-specific errors will show up (or commit-specific errors)
    if err = tx.Rollback(); err != nil { // or call tx.Commit()
        handle(err)
        return
    }