title | description | services | documentationcenter | author | manager | editor | ms.assetid | ms.service | ms.workload | ms.tgt_pltfrm | ms.devlang | ms.topic | ms.date | ms.author |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
How to use Table storage from Java | Microsoft Docs |
Store structured data in the cloud using Azure Table storage, a NoSQL data store. |
storage |
java |
mmacy |
timlt |
tysonn |
45145189-e67f-4ca6-b15d-43af7bfd3f97 |
storage |
storage |
na |
Java |
article |
12/08/2016 |
marsma |
[!INCLUDE storage-selector-table-include]
[!INCLUDE storage-try-azure-tools-queues]
This guide will show you how to perform common scenarios using the Azure Table storage service. The samples are written in Java and use the Azure Storage SDK for Java. The scenarios covered include creating, listing, and deleting tables, as well as inserting, querying, modifying, and deleting entities in a table. For more information on tables, see the Next steps section.
Note: An SDK is available for developers who are using Azure Storage on Android devices. For more information, see the Azure Storage SDK for Android.
[!INCLUDE storage-table-concepts-include]
[!INCLUDE storage-create-account-include]
In this guide, you will use storage features which can be run within a Java application locally, or in code running within a web role or worker role in Azure.
To do so, you will need to install the Java Development Kit (JDK) and create an Azure storage account in your Azure subscription. Once you have done so, you will need to verify that your development system meets the minimum requirements and dependencies which are listed in the Azure Storage SDK for Java repository on GitHub. If your system meets those requirements, you can follow the instructions for downloading and installing the Azure Storage Libraries for Java on your system from that repository. Once you have completed those tasks, you will be able to create a Java application which uses the examples in this article.
Add the following import statements to the top of the Java file where you want to use Microsoft Azure storage APIs to access tables:
// Include the following imports to use table APIs
import com.microsoft.azure.storage.*;
import com.microsoft.azure.storage.table.*;
import com.microsoft.azure.storage.table.TableQuery.*;
An Azure storage client uses a storage connection string to store endpoints and credentials for accessing data management services. When running in a client application, you must provide the storage connection string in the following format, using the name of your storage account and the Primary access key for the storage account listed in the Azure portal for the AccountName and AccountKey values. This example shows how you can declare a static field to hold the connection string:
// Define the connection-string with your values.
public static final String storageConnectionString =
"DefaultEndpointsProtocol=http;" +
"AccountName=your_storage_account;" +
"AccountKey=your_storage_account_key";
In an application running within a role in Microsoft Azure, this string can be stored in the service configuration file, ServiceConfiguration.cscfg, and can be accessed with a call to the RoleEnvironment.getConfigurationSettings method. Here's an example of getting the connection string from a Setting element named StorageConnectionString in the service configuration file:
// Retrieve storage account from connection-string.
String storageConnectionString =
RoleEnvironment.getConfigurationSettings().get("StorageConnectionString");
The following samples assume that you have used one of these two methods to get the storage connection string.
A CloudTableClient object lets you get reference objects for tables and entities. The following code creates a CloudTableClient object and uses it to create a new CloudTable object which represents a table named "people". (Note: There are additional ways to create CloudStorageAccount objects; for more information, see CloudStorageAccount in the Azure Storage Client SDK Reference.)
try
{
// Retrieve storage account from connection-string.
CloudStorageAccount storageAccount =
CloudStorageAccount.parse(storageConnectionString);
// Create the table client.
CloudTableClient tableClient = storageAccount.createCloudTableClient();
// Create the table if it doesn't exist.
String tableName = "people";
CloudTable cloudTable = tableClient.getTableReference(tableName);
cloudTable.createIfNotExists();
}
catch (Exception e)
{
// Output the stack trace.
e.printStackTrace();
}
To get a list of tables, call the CloudTableClient.listTables() method to retrieve an iterable list of table names.
try
{
// Retrieve storage account from connection-string.
CloudStorageAccount storageAccount =
CloudStorageAccount.parse(storageConnectionString);
// Create the table client.
CloudTableClient tableClient = storageAccount.createCloudTableClient();
// Loop through the collection of table names.
for (String table : tableClient.listTables())
{
// Output each table name.
System.out.println(table);
}
}
catch (Exception e)
{
// Output the stack trace.
e.printStackTrace();
}
Entities map to Java objects using a custom class implementing TableEntity. For convenience, the TableServiceEntity class implements TableEntity and uses reflection to map properties to getter and setter methods named for the properties. To add an entity to a table, first create a class that defines the properties of your entity. The following code defines an entity class which uses the customer's first name as the row key, and last name as the partition key. Together, an entity's partition and row key uniquely identify the entity in the table. Entities with the same partition key can be queried faster than those with different partition keys.
public class CustomerEntity extends TableServiceEntity {
public CustomerEntity(String lastName, String firstName) {
this.partitionKey = lastName;
this.rowKey = firstName;
}
public CustomerEntity() { }
String email;
String phoneNumber;
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhoneNumber() {
return this.phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
Table operations involving entities require a TableOperation object. This object defines the operation to be performed on an entity, which can be executed with a CloudTable object. The following code creates a new instance of the CustomerEntity class with some customer data to be stored. The code next calls TableOperation.insertOrReplace to create a TableOperation object to insert an entity into a table, and associates the new CustomerEntity with it. Finally, the code calls the execute method on the CloudTable object, specifying the "people" table and the new TableOperation, which then sends a request to the storage service to insert the new customer entity into the "people" table, or replace the entity if it already exists.
try
{
// Retrieve storage account from connection-string.
CloudStorageAccount storageAccount =
CloudStorageAccount.parse(storageConnectionString);
// Create the table client.
CloudTableClient tableClient = storageAccount.createCloudTableClient();
// Create a cloud table object for the table.
CloudTable cloudTable = tableClient.getTableReference("people");
// Create a new customer entity.
CustomerEntity customer1 = new CustomerEntity("Harp", "Walter");
customer1.setEmail("[email protected]");
customer1.setPhoneNumber("425-555-0101");
// Create an operation to add the new customer to the people table.
TableOperation insertCustomer1 = TableOperation.insertOrReplace(customer1);
// Submit the operation to the table service.
cloudTable.execute(insertCustomer1);
}
catch (Exception e)
{
// Output the stack trace.
e.printStackTrace();
}
You can insert a batch of entities to the table service in one write operation. The following code creates a TableBatchOperation object, then adds three insert operations to it. Each insert operation is added by creating a new entity object, setting its values, and then calling the insert method on the TableBatchOperation object to associate the entity with a new insert operation. Then the code calls execute on the CloudTable object, specifying the "people" table and the TableBatchOperation object, which sends the batch of table operations to the storage service in a single request.
try
{
// Retrieve storage account from connection-string.
CloudStorageAccount storageAccount =
CloudStorageAccount.parse(storageConnectionString);
// Create the table client.
CloudTableClient tableClient = storageAccount.createCloudTableClient();
// Define a batch operation.
TableBatchOperation batchOperation = new TableBatchOperation();
// Create a cloud table object for the table.
CloudTable cloudTable = tableClient.getTableReference("people");
// Create a customer entity to add to the table.
CustomerEntity customer = new CustomerEntity("Smith", "Jeff");
customer.setEmail("[email protected]");
customer.setPhoneNumber("425-555-0104");
batchOperation.insertOrReplace(customer);
// Create another customer entity to add to the table.
CustomerEntity customer2 = new CustomerEntity("Smith", "Ben");
customer2.setEmail("[email protected]");
customer2.setPhoneNumber("425-555-0102");
batchOperation.insertOrReplace(customer2);
// Create a third customer entity to add to the table.
CustomerEntity customer3 = new CustomerEntity("Smith", "Denise");
customer3.setEmail("[email protected]");
customer3.setPhoneNumber("425-555-0103");
batchOperation.insertOrReplace(customer3);
// Execute the batch of operations on the "people" table.
cloudTable.execute(batchOperation);
}
catch (Exception e)
{
// Output the stack trace.
e.printStackTrace();
}
Some things to note on batch operations:
- You can perform up to 100 insert, delete, merge, replace, insert or merge, and insert or replace operations in any combination in a single batch.
- A batch operation can have a retrieve operation, if it is the only operation in the batch.
- All entities in a single batch operation must have the same partition key.
- A batch operation is limited to a 4MB data payload.
To query a table for entities in a partition, you can use a TableQuery. Call TableQuery.from to create a query on a particular table that returns a specified result type. The following code specifies a filter for entities where 'Smith' is the partition key. TableQuery.generateFilterCondition is a helper method to create filters for queries. Call where on the reference returned by the TableQuery.from method to apply the filter to the query. When the query is executed with a call to execute on the CloudTable object, it returns an Iterator with the CustomerEntity result type specified. You can then use the Iterator returned in a for each loop to consume the results. This code prints the fields of each entity in the query results to the console.
try
{
// Define constants for filters.
final String PARTITION_KEY = "PartitionKey";
final String ROW_KEY = "RowKey";
final String TIMESTAMP = "Timestamp";
// Retrieve storage account from connection-string.
CloudStorageAccount storageAccount =
CloudStorageAccount.parse(storageConnectionString);
// Create the table client.
CloudTableClient tableClient = storageAccount.createCloudTableClient();
// Create a cloud table object for the table.
CloudTable cloudTable = tableClient.getTableReference("people");
// Create a filter condition where the partition key is "Smith".
String partitionFilter = TableQuery.generateFilterCondition(
PARTITION_KEY,
QueryComparisons.EQUAL,
"Smith");
// Specify a partition query, using "Smith" as the partition key filter.
TableQuery<CustomerEntity> partitionQuery =
TableQuery.from(CustomerEntity.class)
.where(partitionFilter);
// Loop through the results, displaying information about the entity.
for (CustomerEntity entity : cloudTable.execute(partitionQuery)) {
System.out.println(entity.getPartitionKey() +
" " + entity.getRowKey() +
"\t" + entity.getEmail() +
"\t" + entity.getPhoneNumber());
}
}
catch (Exception e)
{
// Output the stack trace.
e.printStackTrace();
}
If you don't want to query all the entities in a partition, you can specify a range by using comparison operators in a filter. The following code combines two filters to get all entities in partition "Smith" where the row key (first name) starts with a letter up to 'E' in the alphabet. Then it prints the query results. If you use the entities added to the table in the batch insert section of this guide, only two entities are returned this time (Ben and Denise Smith); Jeff Smith is not included.
try
{
// Define constants for filters.
final String PARTITION_KEY = "PartitionKey";
final String ROW_KEY = "RowKey";
final String TIMESTAMP = "Timestamp";
// Retrieve storage account from connection-string.
CloudStorageAccount storageAccount =
CloudStorageAccount.parse(storageConnectionString);
// Create the table client.
CloudTableClient tableClient = storageAccount.createCloudTableClient();
// Create a cloud table object for the table.
CloudTable cloudTable = tableClient.getTableReference("people");
// Create a filter condition where the partition key is "Smith".
String partitionFilter = TableQuery.generateFilterCondition(
PARTITION_KEY,
QueryComparisons.EQUAL,
"Smith");
// Create a filter condition where the row key is less than the letter "E".
String rowFilter = TableQuery.generateFilterCondition(
ROW_KEY,
QueryComparisons.LESS_THAN,
"E");
// Combine the two conditions into a filter expression.
String combinedFilter = TableQuery.combineFilters(partitionFilter,
Operators.AND, rowFilter);
// Specify a range query, using "Smith" as the partition key,
// with the row key being up to the letter "E".
TableQuery<CustomerEntity> rangeQuery =
TableQuery.from(CustomerEntity.class)
.where(combinedFilter);
// Loop through the results, displaying information about the entity
for (CustomerEntity entity : cloudTable.execute(rangeQuery)) {
System.out.println(entity.getPartitionKey() +
" " + entity.getRowKey() +
"\t" + entity.getEmail() +
"\t" + entity.getPhoneNumber());
}
}
catch (Exception e)
{
// Output the stack trace.
e.printStackTrace();
}
You can write a query to retrieve a single, specific entity. The following code calls TableOperation.retrieve with partition key and row key parameters to specify the customer "Jeff Smith", instead of creating a TableQuery and using filters to do the same thing. When executed, the retrieve operation returns just one entity, rather than a collection. The getResultAsType method casts the result to the type of the assignment target, a CustomerEntity object. If this type is not compatible with the type specified for the query, an exception will be thrown. A null value is returned if no entity has an exact partition and row key match. Specifying both partition and row keys in a query is the fastest way to retrieve a single entity from the Table service.
try
{
// Retrieve storage account from connection-string.
CloudStorageAccount storageAccount =
CloudStorageAccount.parse(storageConnectionString);
// Create the table client.
CloudTableClient tableClient = storageAccount.createCloudTableClient();
// Create a cloud table object for the table.
CloudTable cloudTable = tableClient.getTableReference("people");
// Retrieve the entity with partition key of "Smith" and row key of "Jeff"
TableOperation retrieveSmithJeff =
TableOperation.retrieve("Smith", "Jeff", CustomerEntity.class);
// Submit the operation to the table service and get the specific entity.
CustomerEntity specificEntity =
cloudTable.execute(retrieveSmithJeff).getResultAsType();
// Output the entity.
if (specificEntity != null)
{
System.out.println(specificEntity.getPartitionKey() +
" " + specificEntity.getRowKey() +
"\t" + specificEntity.getEmail() +
"\t" + specificEntity.getPhoneNumber());
}
}
catch (Exception e)
{
// Output the stack trace.
e.printStackTrace();
}
To modify an entity, retrieve it from the table service, make changes to the entity object, and save the changes back to the table service with a replace or merge operation. The following code changes an existing customer's phone number. Instead of calling TableOperation.insert like we did to insert, this code calls TableOperation.replace. The CloudTable.execute method calls the table service, and the entity is replaced, unless another application changed it in the time since this application retrieved it. When that happens, an exception is thrown, and the entity must be retrieved, modified, and saved again. This optimistic concurrency retry pattern is common in a distributed storage system.
try
{
// Retrieve storage account from connection-string.
CloudStorageAccount storageAccount =
CloudStorageAccount.parse(storageConnectionString);
// Create the table client.
CloudTableClient tableClient = storageAccount.createCloudTableClient();
// Create a cloud table object for the table.
CloudTable cloudTable = tableClient.getTableReference("people");
// Retrieve the entity with partition key of "Smith" and row key of "Jeff".
TableOperation retrieveSmithJeff =
TableOperation.retrieve("Smith", "Jeff", CustomerEntity.class);
// Submit the operation to the table service and get the specific entity.
CustomerEntity specificEntity =
cloudTable.execute(retrieveSmithJeff).getResultAsType();
// Specify a new phone number.
specificEntity.setPhoneNumber("425-555-0105");
// Create an operation to replace the entity.
TableOperation replaceEntity = TableOperation.replace(specificEntity);
// Submit the operation to the table service.
cloudTable.execute(replaceEntity);
}
catch (Exception e)
{
// Output the stack trace.
e.printStackTrace();
}
A query to a table can retrieve just a few properties from an entity. This technique, called projection, reduces bandwidth and can improve query performance, especially for large entities. The query in the following code uses the select method to return only the email addresses of entities in the table. The results are projected into a collection of String with the help of an EntityResolver, which does the type conversion on the entities returned from the server. You can learn more about projection in Azure Tables: Introducing Upsert and Query Projection. Note that projection is not supported on the local storage emulator, so this code runs only when using an account on the table service.
try
{
// Retrieve storage account from connection-string.
CloudStorageAccount storageAccount =
CloudStorageAccount.parse(storageConnectionString);
// Create the table client.
CloudTableClient tableClient = storageAccount.createCloudTableClient();
// Create a cloud table object for the table.
CloudTable cloudTable = tableClient.getTableReference("people");
// Define a projection query that retrieves only the Email property
TableQuery<CustomerEntity> projectionQuery =
TableQuery.from(CustomerEntity.class)
.select(new String[] {"Email"});
// Define a Entity resolver to project the entity to the Email value.
EntityResolver<String> emailResolver = new EntityResolver<String>() {
@Override
public String resolve(String PartitionKey, String RowKey, Date timeStamp, HashMap<String, EntityProperty> properties, String etag) {
return properties.get("Email").getValueAsString();
}
};
// Loop through the results, displaying the Email values.
for (String projectedString :
cloudTable.execute(projectionQuery, emailResolver)) {
System.out.println(projectedString);
}
}
catch (Exception e)
{
// Output the stack trace.
e.printStackTrace();
}
Often you want to add an entity to a table without knowing if it already exists in the table. An insert-or-replace operation allows you to make a single request which will insert the entity if it does not exist or replace the existing one if it does. Building on prior examples, the following code inserts or replaces the entity for "Walter Harp". After creating a new entity, this code calls the TableOperation.insertOrReplace method. This code then calls execute on the CloudTable object with the table and the insert or replace table operation as the parameters. To update only part of an entity, the TableOperation.insertOrMerge method can be used instead. Note that insert-or-replace is not supported on the local storage emulator, so this code runs only when using an account on the table service. You can learn more about insert-or-replace and insert-or-merge in this Azure Tables: Introducing Upsert and Query Projection.
try
{
// Retrieve storage account from connection-string.
CloudStorageAccount storageAccount =
CloudStorageAccount.parse(storageConnectionString);
// Create the table client.
CloudTableClient tableClient = storageAccount.createCloudTableClient();
// Create a cloud table object for the table.
CloudTable cloudTable = tableClient.getTableReference("people");
// Create a new customer entity.
CustomerEntity customer5 = new CustomerEntity("Harp", "Walter");
customer5.setEmail("[email protected]");
customer5.setPhoneNumber("425-555-0106");
// Create an operation to add the new customer to the people table.
TableOperation insertCustomer5 = TableOperation.insertOrReplace(customer5);
// Submit the operation to the table service.
cloudTable.execute(insertCustomer5);
}
catch (Exception e)
{
// Output the stack trace.
e.printStackTrace();
}
You can easily delete an entity after you have retrieved it. Once the entity is retrieved, call TableOperation.delete with the entity to delete. Then call execute on the CloudTable object. The following code retrieves and deletes a customer entity.
try
{
// Retrieve storage account from connection-string.
CloudStorageAccount storageAccount =
CloudStorageAccount.parse(storageConnectionString);
// Create the table client.
CloudTableClient tableClient = storageAccount.createCloudTableClient();
// Create a cloud table object for the table.
CloudTable cloudTable = tableClient.getTableReference("people");
// Create an operation to retrieve the entity with partition key of "Smith" and row key of "Jeff".
TableOperation retrieveSmithJeff = TableOperation.retrieve("Smith", "Jeff", CustomerEntity.class);
// Retrieve the entity with partition key of "Smith" and row key of "Jeff".
CustomerEntity entitySmithJeff =
cloudTable.execute(retrieveSmithJeff).getResultAsType();
// Create an operation to delete the entity.
TableOperation deleteSmithJeff = TableOperation.delete(entitySmithJeff);
// Submit the delete operation to the table service.
cloudTable.execute(deleteSmithJeff);
}
catch (Exception e)
{
// Output the stack trace.
e.printStackTrace();
}
Finally, the following code deletes a table from a storage account. A table which has been deleted will be unavailable to be recreated for a period of time following the deletion, usually less than forty seconds.
try
{
// Retrieve storage account from connection-string.
CloudStorageAccount storageAccount =
CloudStorageAccount.parse(storageConnectionString);
// Create the table client.
CloudTableClient tableClient = storageAccount.createCloudTableClient();
// Delete the table and all its data if it exists.
CloudTable cloudTable = tableClient.getTableReference("people");
cloudTable.deleteIfExists();
}
catch (Exception e)
{
// Output the stack trace.
e.printStackTrace();
}
Now that you've learned the basics of table storage, follow these links to learn how to do more complex storage tasks.
- Azure Storage SDK for Java
- Azure Storage Client SDK Reference
- Azure Storage REST API
- Azure Storage Team Blog
For more information, see also the Java Developer Center.