Working with DynamoDB Transactions
Tags: dynamodb, python, boto3, cloud9
Published: 2022-12-10 00:50:32

In this article, I am going to show you how DynamoDB transactions -  read and write APIs are used to provide ACID (atomicity, consistency, isolation, and durability) support which will help you maintain the data integrity in your business complex applications.

**Amazon DynamoDB transactions** applies to ONLY one account and in the same Region. 


- The read and write actions are completed so that either all of them succeed or none of them succeeds.


- There is no additional cost to enable transactions for your DynamoDB tables. 


- You pay only for the reads or writes that are part of your transaction.


- The aggregate size of the items in the transaction cannot exceed 4 MB.


- Transactions cannot be performed using indexes.



**TransactWriteItems API** is a synchronous write operation that groups up to 100 write actions in a single all-or-nothing operation. 


- You can group multiple Put, Update, Delete, and ConditionCheck actions in a single TransactWriteItems operation that either succeeds or fails. 

- No two actions can target the same item. For example, you cannot both ConditionCheck and Update the same item.

- These actions can include up to 100 distinct items in one or more DynamoDB tables. 

- All these actions include the name of the table, a field indicating whether to retrieve/update/delete/ConditionCheck the item's attributes if the condition is not met and an optional condition expression that must be satisfied for the write/update/delete/ConditionCheck to succeed.


**Put**  —   As the name indicates, it writes a new item which is the primary key of the item. It includes a list of the item's attributes

 

**Update**  —  As the name indicates, it updates an existing primary key of the item or adds a new item if it does not exist already. It includes a field defining which attributes to be updated



**Delete**  —   As the name indicates, it deletes the primary key of the existing item. 




**ConditionCheck**  —   As the name implies, it only checks a primary key of the item.



  
DynamoDB rejects the entire TransactWriteItems request if any of the following is true:

- A condition in one of the condition expressions is not met.

- When a transaction validation error (TransactionCanceledException) occurs because more than one action in the same TransactWriteItems operation targets the same item.


- There is insufficient provisioned capacity for the transaction to be completed.

- An item size becomes too large (bigger than 400 KB), a local secondary index (LSI) becomes too large, or a similar validation error occurs because of changes made by the transaction.

- There is a user error, such as an invalid data format.





**TransactGetItems API** is a synchronous read operation that groups up to 100 Get actions together. 
- You can group multiple Put, Update, Delete, and ConditionCheck actions in a single TransactWriteItems operation that either succeeds or fails. 

- No two actions can target the same item. For example, you cannot both ConditionCheck and Update the same item.

- These actions can include up to 100 distinct items in one or more DynamoDB tables. 




**Get** — As the name implies, it retrieves a set of attributes for the item with the given primary key. If no matching item is found, Get does not return any data.


- It includes an Error handling for reading


Please visit my **[GitHub Repository for DynamoDB articles](https://github.com/awsmine/DynamoDB_projects)** on various topics being updated on constant basis.





_**Let’s get started!**_



# Objectives:

**1.** Create a DynamoDB Table Primary key/Partition Key and a Sort Key using **create_table.py**

**2.** Create a python file - **transact_write_items.py** to write transactional items into the DynamoDB table

**3.** Create a python file - **transact_get_items.py** to get the items from the DynamoDB table

**4.** Validate some of the operations in the methods - transact_write_items() and transact_get_items()






# Pre-requisites:

Amazon DynamoDB can be integrated with other AWS services.

- AWS user account with admin access, not a root account.
- Cloud9 IDE comes with Python and boto3 installed OR
if it is not installed, Install boto3 python3 -m pip install boto3
- AWS Command Line Interface (AWS CLI) enables you to interact with AWS services using commands in your command-line shell.




# Resources Used:

I have used extensively the boto3 documentation for this session
Boto3 documentation — [Boto3 Docs 1.26.26 documentation](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/dynamodb.html)

[transact_write_items](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Client.transact_write_items)

[transact_get_items](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Client.transact_get_items)

Please refer to my previous article on how [DynamoDB table works with different methods using Python scripts and boto3](https://dev.to/aws-builders/create-and-manipulate-dynamodb-table-with-different-methods-using-python-scripts-and-boto3-37ef) 





# Steps for implementation to this project:

- Copy the corresponding code for the python scripts and save them in Cloud9 directory.


- Execute all the python files in the order starting from 1-3 


## 1. Create a DynamoDB Table Primary key/Partition Key and a Sort Key using **create_table.py**

```
#!/usr/bin/env python3.7

# create_table.py 

# Get the method create_table() to create table "movies", and print data from table


# To use Boto3, you must first import AWS Python SDK
import boto3


# A low-level client representing DynamoDB
dynamodb_client=boto3.client('dynamodb')


# use the DynamoDB.ServiceResource.create_table() method:
# then indicate which service or services you're going to use:
# Get the service resource.
dynamodb = boto3.resource('dynamodb')


# Create the DynamoDB table.
table = dynamodb.create_table(
    TableName='movies',
    KeySchema=[
        {
            'AttributeName': 'id',
            'KeyType': 'HASH'
        },
        {
            'AttributeName': 'director',
            'KeyType': 'RANGE'
        }
    ],
    AttributeDefinitions=[
        {
            'AttributeName': 'id',
            'AttributeType': 'S'
        },
        {
            'AttributeName': 'director',
            'AttributeType': 'S'
        },
    ],
    ProvisionedThroughput={
        'ReadCapacityUnits': 5,
        'WriteCapacityUnits': 5
    }
)

# Wait until the table exists.
table.wait_until_exists()

# Print out data about the table.
print('DynamoDB Table', '=> ', table.table_name, ' created.')

```



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b6tn1gf6unaixtj36182.png)




## 2. Create a python file - **transact_write_items.py** to write transactional items into the DynamoDB table

```
#!/usr/bin/env python3.7

# transact_write_items.py
 
from __future__ import print_function # Python 2/3 compatibility
import boto3, json
from botocore.exceptions import ClientError

client = boto3.client('dynamodb', region_name='us-east-1')

try:
    response = client.transact_write_items(
        TransactItems=[
            {
                'Put': {
                    'TableName': 'movies',
                    'Item': {
                        'id': {
                            'S': '1'
                        },
                        'director': {
                            'S': 'Yash'
                        },
                        'user': {
                            'S': 'Rev'
                        },
                        'other': {
                            'S': 'Fun working'
                        },
                    },
                    'ConditionExpression': 'attribute_not_exists(id)',
                }
            },
            {
                'Update': {
                    'TableName': 'movies',
                    'Key': {
                        'id': {
                            'S': '2'
                        },
                        'director': {
                            'S': 'Rishikesh'
                        }
                    },
                    'UpdateExpression': 'SET #o = :val',
                    'ExpressionAttributeValues': {
                        ':val': {
                            'S': 'updated value'
                        }
                    },
                    'ExpressionAttributeNames': {
                        '#o': 'Other'
                    }
                }
            }
        ]
    )
except ClientError as e:
    print(e)
    print(e.response['Error']['Message'])
else:
    print("Transact Write succeeded")
    
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rrk8tqjhlbyfq6kkg6dk.png)




## 3. Create a python file - **transact_get_items.py** to get the items from the DynamoDB table

```
#!/usr/bin/env python3.7

#transact_get_items.py

from __future__ import print_function # Python 2/3 compatibility
import boto3, json, decimal
from boto3.dynamodb.conditions import Key, Attr
from botocore.exceptions import ClientError

client = boto3.client('dynamodb', region_name='us-east-1')

try:
    response = client.transact_get_items(
        TransactItems=[
            {
                'Get': {
                    'TableName': "movies",
                    'Key': {
                        'id': {
                            'S': '1'
                        },
                        'director': {
                            'S': "Yash"
                        },
                    },
                },
            },
            {
                'Get': {
                    'TableName': "movies",
                    'Key': {
                        'id': {
                            'S': "2"
                        },
                        'director': {
                            'S': "Rishikesh"
                        },
                    },
                },
            },
        ]
    )

    print(json.dumps(response))

except ClientError as e:
    print(e.response['Error']['Message'])
    
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/to54dxvbmk8iq8hsgfos.png)




## 4. Validate some of the operations in both the methods - transact_write_items() and transact_get_items()

### the method - **transact_write_items()**

- When a condition in one of the condition expressions is not met.



- When a transaction validation error occurs because more than one action in the same TransactWriteItems operation targets the same item.



Run the same file - transact_write_items.py again



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/btrjnlnmxjbra6ukyr27.png)









### the method transact_get_items()

- When there is a user error, such as an invalid data format - Modify the spelling of the table 'movies' to 'Movies'

```
#!/usr/bin/env python3.7

#transact_get_items.py

# Modify the spelling of the table 'movies' to 'Movies'

from __future__ import print_function # Python 2/3 compatibility
import boto3, json, decimal
from boto3.dynamodb.conditions import Key, Attr
from botocore.exceptions import ClientError

client = boto3.client('dynamodb', region_name='us-east-1')

try:
    response = client.transact_get_items(
        TransactItems=[
            {
                'Get': {
                    'TableName': "Movies", 
                    'Key': {
                        'id': {
                            'S': '1'
                        },
                        'director': {
                            'S': "Yash"
                        },
                    },
                },
            },
            {
                'Get': {
                    'TableName': "movies",
                    'Key': {
                        'id': {
                            'S': "2"
                        },
                        'director': {
                            'S': "Rishikesh"
                        },
                    },
                },
            },
        ]
    )

    print(json.dumps(response))

except ClientError as e:
    print(e.response['Error']['Message'])
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uru0hzd1j84dwguz6lz9.png)







# Cleanup

**`delete_table.py`**



```
#!/usr/bin/env python3.7


# delete_table.py
# delete the table - movies


# To use Boto3, you must first import AWS Python SDK
import boto3


# A low-level client representing DynamoDB
dynamodb = boto3.client('dynamodb')


# delete the table movies
response = dynamodb.delete_table(
    TableName='movies'
)

```


**`rm transact_write_items.py`**


**`rm transact_get_items.py`**


# What we have done so far

We have successfully shown how DynamoDB transactions -  read and write APIs are used to keep the integrity of data by running the operations at the same time, so that either all of them succeed or none of them succeeds.