Before you begin
- .
- Start up a or local cluster.
- Choose the instructions that correspond to whether your cluster is secure or insecure:
The
--insecure flag used in this tutorial is intended for non-production testing only. To run CockroachDB in production, use a secure cluster instead.Step 1. Install JDK
Download and install a Java Development Kit. MyBatis-Spring supports Java versions 8+. In this tutorial, we use JDK 11 from OpenJDK.Step 2. Install Gradle
This example application uses Gradle to manage all application dependencies. Spring supports Gradle versions 6+. To install Gradle on macOS, run the following command:Step 3. Get the application code
To get the application code, download or clone themybatis-cockroach-demo repository.
Step 4. Create the maxroach user and bank database
Start the :
maxroach user and bank database:
bank user the necessary permissions:
Step 5. Generate a certificate for the maxroach user
Create a certificate and key for the maxroach user by running the following command. The code samples will run as this user.
client.maxroach.key.pk8.
Step 6. Run the application
To run the application:-
Open and edit the
src/main/resources/application.ymlfile so that theurlfield specifies the full to the running CockroachDB cluster. To connect to a secure cluster, this connection string must set thesslmodeconnection parameter torequire, and specify the full path to the client, node, and user certificates in the connection parameters. For example: -
Open a terminal, and navigate to the
mybatis-cockroach-demoproject directory: -
Run the Gradle script to download the application dependencies, compile the code, and run the application:
maxroach user and bank database:
bank user the necessary permissions:
Step 6. Run the application
To run the application:-
Open and edit the
src/main/resources/application.ymlfile so that theurlfield specifies the full to the running CockroachDB cluster. For example: -
Open a terminal, and navigate to the
mybatis-cockroach-demoproject directory: -
Run the Gradle script to download the application dependencies, compile the code, and run the application:
accounts table in the bank database.
For more details about the application code, see Application details.
Application details
This section guides you through the different components of the application project in detail.Main process
The main process of the application is defined insrc/main/java/com/example/cockroachdemo/CockroachDemoApplication.java:
SpringApplication.run call in the main method bootstraps and launches a Spring application. The @SpringBootApplication annotation on the CockroachDemoApplication class triggers Spring’s component scanning and auto-configuration features.
The BasicExample class, defined in src/main/java/com/example/cockroachdemo/BasicExample.java, is one of the components detected in the component scan:
BasicExample implements the Spring CommandLineRunner interface. Implementations of this interface automatically run when detected in a Spring project directory. BasicExample runs a series of test methods that are eventually executed as SQL queries in the data access layer of the application.
Configuration
All MyBatis-Spring applications need aDataSource, a SqlSessionFactory, and at least one mapper interface. The MyBatis-Spring-Boot-Starter module, built on MyBatis and MyBatis-Spring, and used by this application, greatly simplifies how you configure each of these required elements.
Applications that use MyBatis-Spring-Boot-Starter typically need just an annotated mapper interface and an existing DataSource in the Spring environment. The module detects the DataSource, creates a SqlSessionFactory from the DataSource, creates a thread-safe SqlSessionTemplate with the SqlSessionFactory, and then auto-scans the mappers and links them to the SqlSessionTemplate for injection. The SqlSessionTemplate automatically commits, rolls back, and closes sessions, based on the application’s Spring-based transaction configuration.
This sample application implements , a CockroachDB best practice for executing multiple INSERT and UPSERT statements. MyBatis applications that support batch operations require some additional configuration work, even if the application uses MyBatis-Spring-Boot-Starter:
- The application must define a specific mapper interface for batch query methods.
- The application must define a
SqlSessionTemplateconstructor, specifically for batch operations, that uses theBATCHexecutor type. - The batch mapper must be explicitly registered with the batch-specific
SqlSessionTemplate.
src/main/java/com/example/cockroachdemo/MyBatisConfiguration.java configures the application to meet these requirements:
SqlSessionTemplate (i.e., batchSqlSessionTemplate), and registers batchmapper, the batch mapper interface defined in src/main/java/com/example/cockroachdemo/batchmapper/BatchMapper.java with batchSqlSessionTemplate. To complete the MyBatis configuration, the class also declares a DataSource, and defines the remaining SqlSessionFactory and SqlSessionTemplate beans.
Note that a configuration class is not required for MyBatis-Spring-Boot-Starter applications that do not implement batch operations.
Data source
src/main/resources/application.yml contains the metadata used to create a connection to the CockroachDB cluster:
datasource property to auto-configure the database connection. This database connection configuration can be injected into the application’s SqlSessionFactoryBean, as is explicitly done in the MyBatisConfiguration configuration class definition.
Mappers
All MyBatis applications require at least one mapper interface. These mappers take the place of manually-defined data access objects (DAOs). They provide other layers of the application an interface to the database. MyBatis-Spring-Boot-Starter usually scans the project for interfaces annotated with@Mapper, links the interfaces to a SqlSessionTemplate, and registers them with Spring so they can be injected into the application’s Spring beans. As mentioned in the Configuration section, because the application supports batch writes, the two mapper interfaces in the application are registered and linked manually in the MyBatisConfiguration configuration class definition.
Account mapper
src/main/java/com/example/cockroachdemo/mapper/AccountMapper.java defines the mapper interface to the accounts table using the MyBatis Java API:
@Mapper annotation declares the interface a mapper for MyBatis to scan. The SQL statement annotations on each of the interface methods map them to SQL queries. For example, the first method, deleteAllAccounts() is marked as a DELETE statement with the @Delete annotation. This method executes the SQL statement specified in the string passed to the annotation, “delete from accounts”, which deletes all rows in the accounts table.
Batch account mapper
src/main/java/com/example/cockroachdemo/batchmapper/BatchAccountMapper.java defines a mapper interface for :
INSERT statement query method, along with a method for flushing (i.e., executing) a batch of statements.
Services
src/main/java/com/example/cockroachdemo/service/AccountService.java defines the service interface, with a number of methods for reading and writing to the database:
MyBatisAccountService.java implements the AccountService interface, using the mappers defined in AccountMapper.java and BatchAccountMapper.java, and the models defined in Account.java and BatchResults.java:
@Transactional methods. This ensures that all of the SQL statements executed in the data access layer are run within the context of a
@Transactional takes a number of parameters, including a propagation parameter that determines the transaction propagation behavior around an object (i.e., at what point in the stack a transaction starts and ends). propagation=REQUIRES_NEW for the methods in the service layer, meaning that a new transaction must be created each time a request is made to the service layer. With this propagation behavior, the application follows the entity-control-boundary (ECB) pattern, as the service boundaries determine where a starts and ends rather than the lower-level query methods of the mapper interfaces.
For more details on aspect-oriented transaction management in this application, see below.
Models
Instances of theAccount class, defined in src/main/java/com/example/cockroachdemo/model/Account.java, represent rows in the accounts table:
BatchResults class, defined in src/main/java/com/example/cockroachdemo/model/BatchResults.java, hold metadata about a batch write operation and its results:
Transaction management
MyBatis-Spring supports Spring’s declarative, aspect-oriented transaction management syntax, including the@Transactional annotation and AspectJ’s AOP annotations.
Transactions may require retries if they experience deadlock or that cannot be resolved without allowing anomalies. To handle transactions that are aborted due to transient serialization errors, we highly recommend writing into applications written on CockroachDB. In this application, transaction retry logic is written into the methods of the RetryableTransactionAspect class, defined in src/main/java/com/example/cockroachdemo/RetryableTransactionAspect.java:
@Aspect annotation declares RetryableTransactionAspect an aspect, with pointcut and advice methods.
Transactional pointcut
The@Pointcut annotation declares the anyTransactionBoundaryOperation method the pointcut for determining when to execute the aspect’s advice. The @annotation designator passed to the @Pointcut annotation limits the matches (i.e., join points) to method calls with a specific annotation, in this case, @Transactional.
Transaction retry advice
retryableOperation handles the application retry logic, with exponential backoff, as the advice to execute at an anyTransactionBoundaryOperation(transactional) join point. Spring supports several different annotations to declare advice. The @Around annotation allows an advice method to work before and after the join point. It also gives the advice method control over executing any other matching advisors.
retryableOperation first verifies that there is no active transaction. It then increments the retry count and attempts to proceed to the next advice method with the ProceedingJoinPoint.proceed() method. If the underlying data access layer method (i.e., the mapper interface method annotated with @Transactional) succeeds, the results are returned and the application flow continues. If the method fails, then the transaction is retried. The time between each retry grows with each retry until the maximum number of retries is reached.
Advice ordering
Spring automatically adds transaction management advice to all methods annotated with@Transactional. Because the pointcut for RetryableTransactionAspect also matches methods annotated with @Transactional, there will always be two advisors that match the same pointcut. When multiple advisors match at the same pointcut, an @Order annotation on an advisor’s aspect can specify the order in which the advice should be evaluated.
To control when and how often a transaction is retried, the transaction retry advice must be executed outside the context of a transaction (i.e., it must be evaluated before the primary transaction management advisor). By default, the primary transaction management advisor is given the lowest level of precedence. The @Order annotation on RetryableTransactionAspect is passed Ordered.LOWEST_PRECEDENCE-1, which places this aspect’s advice at a level of precedence above the primary transaction advisor, which results in the retry logic being evaluated before the transaction management advisor.
For more details about advice ordering in Spring, see Advice Ordering on the Spring documentation site.
See also
Spring documentation:- Spring Boot website
- Spring Framework Overview
- Spring Core documentation
- MyBatis documentation
- MyBatis Spring integration

