func (t *Transaction) Delete(key *Key) error {
	err := t.DeleteMulti([]*Key{key})
	if me, ok := err.(MultiError); ok {
		return me[0]
	}
	return err
}
Delete is the transaction-specific version of the package function Delete.
Delete enqueues the deletion of the entity for the given key, to be
committed atomically upon calling Commit.
package datastore
import (
	"errors"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	pb "google.golang.org/genproto/googleapis/datastore/v1"
)
var ErrConcurrentTransaction = errors.New("datastore: concurrent transaction")
var errExpiredTransaction = errors.New("datastore: transaction expired")
type transactionSettings struct {
	attempts int
}
func newTransactionSettings(opts []TransactionOption) *transactionSettings {
	s := &transactionSettings{attempts: 3}
	for _, o := range opts {
		o.apply(s)
	}
	return s
}
type TransactionOption interface {
	apply(*transactionSettings)
}
func MaxAttempts(attempts int) TransactionOption {
	return maxAttempts(attempts)
}
type maxAttempts int
func (w maxAttempts) apply(s *transactionSettings) {
	if w > 0 {
		s.attempts = int(w)
	}
}
type Transaction struct {
	id        []byte
	client    *Client
	ctx       context.Context
	mutations []*pb.Mutation       
	pending   map[int]*PendingKey  
}
func (c *Client) NewTransaction(ctx context.Context, opts ...TransactionOption) (*Transaction, error) {
	for _, o := range opts {
		if _, ok := o.(maxAttempts); ok {
			return nil, errors.New("datastore: NewTransaction does not accept MaxAttempts option")
		}
	}
	req := &pb.BeginTransactionRequest{
		ProjectId: c.dataset,
	}
	resp, err := c.client.BeginTransaction(ctx, req)
	if err != nil {
		return nil, err
	}
	return &Transaction{
		id:        resp.Transaction,
		ctx:       ctx,
		client:    c,
		mutations: nil,
		pending:   make(map[int]*PendingKey),
	}, nil
}
func (c *Client) RunInTransaction(ctx context.Context, f func(tx *Transaction) error, opts ...TransactionOption) (*Commit, error) {
	settings := newTransactionSettings(opts)
	for n := 0; n < settings.attempts; n++ {
		tx, err := c.NewTransaction(ctx)
		if err != nil {
			return nil, err
		}
		if err := f(tx); err != nil {
			tx.Rollback()
			return nil, err
		}
		if cmt, err := tx.Commit(); err != ErrConcurrentTransaction {
			return cmt, err
		}
	}
	return nil, ErrConcurrentTransaction
}
func (t *Transaction) Commit() (*Commit, error) {
	if t.id == nil {
		return nil, errExpiredTransaction
	}
	req := &pb.CommitRequest{
		ProjectId:           t.client.dataset,
		TransactionSelector: &pb.CommitRequest_Transaction{Transaction: t.id},
		Mutations:           t.mutations,
		Mode:                pb.CommitRequest_TRANSACTIONAL,
	}
	t.id = nil
	resp, err := t.client.client.Commit(t.ctx, req)
	if err != nil {
		if grpc.Code(err) == codes.Aborted {
			return nil, ErrConcurrentTransaction
		}
		return nil, err
	}
	commit := &Commit{}
	for i, p := range t.pending {
		if i >= len(resp.MutationResults) || resp.MutationResults[i].Key == nil {
			return nil, errors.New("datastore: internal error: server returned the wrong mutation results")
		}
		key, err := protoToKey(resp.MutationResults[i].Key)
		if err != nil {
			return nil, errors.New("datastore: internal error: server returned an invalid key")
		}
		p.key = key
		p.commit = commit
	}
	return commit, nil
}
func (t *Transaction) Rollback() error {
	if t.id == nil {
		return errExpiredTransaction
	}
	id := t.id
	t.id = nil
	_, err := t.client.client.Rollback(t.ctx, &pb.RollbackRequest{
		ProjectId:   t.client.dataset,
		Transaction: id,
	})
	return err
}
func (t *Transaction) Get(key *Key, dst interface{}) error {
	opts := &pb.ReadOptions{
		ConsistencyType: &pb.ReadOptions_Transaction{Transaction: t.id},
	}
	err := t.client.get(t.ctx, []*Key{key}, []interface{}{dst}, opts)
	if me, ok := err.(MultiError); ok {
		return me[0]
	}
	return err
}
func (t *Transaction) GetMulti(keys []*Key, dst interface{}) error {
	if t.id == nil {
		return errExpiredTransaction
	}
	opts := &pb.ReadOptions{
		ConsistencyType: &pb.ReadOptions_Transaction{Transaction: t.id},
	}
	return t.client.get(t.ctx, keys, dst, opts)
}
func (t *Transaction) Put(key *Key, src interface{}) (*PendingKey, error) {
	h, err := t.PutMulti([]*Key{key}, []interface{}{src})
	if err != nil {
		if me, ok := err.(MultiError); ok {
			return nil, me[0]
		}
		return nil, err
	}
	return h[0], nil
}
func (t *Transaction) PutMulti(keys []*Key, src interface{}) ([]*PendingKey, error) {
	if t.id == nil {
		return nil, errExpiredTransaction
	}
	mutations, err := putMutations(keys, src)
	if err != nil {
		return nil, err
	}
	origin := len(t.mutations)
	t.mutations = append(t.mutations, mutations...)
	ret := make([]*PendingKey, len(keys))
	for i, key := range keys {
		p := &PendingKey{}
		if key.Incomplete() {
			t.pending[origin+i] = p
		} else {
			p.key = key
		}
		ret[i] = p
	}
	return ret, nil
}