# Spring Data JPA Auditing using Spring Boot and MySQL

By Atta Ur Rehman Shah (https://attacomsian.com/about). Published Oct 20, 2019, updated Sep 25, 2022. Topics: Spring Boot, Spring Data JPA, MySQL.
Canonical URL: https://attacomsian.com/blog/spring-data-jpa-auditing

> A complete guide to learning what is Spring Data JPA auditing feature and how to enable it in a Spring Boot and MySQL application.

Auditing helps us track and log the persistence layer changes made by the user in an application. By using auditing, we can determine who created or updated the entity record or when it happened. In short, we keep track of every action that changes the entity state, like insert, update, and delete operations.

[Spring Data JPA](https://attacomsian.com/blog/getting-started-spring-data-jpa) provides excellent support to track who created or changed an entity and the time this happened.

To enable the auditing feature in Spring Boot, we can make use of Spring Data JPA's `@CreateDate`, `@CreatedBy`, `@LastModifiedDate`, and `@LastModifiedBy` annotations. You can add these annotations directly to your entity classes or by extending an abstract class that defines annotated audit fields.

Since we need an auditing feature for most entities, in this article, we will create a generic `Auditable` abstract class with audit fields. Any entity can later extend this abstract class to enable the auditing functionality.

## Dependencies

 To use [Spring Data JPA with the MySQL database](https://attacomsian.com/blog/accessing-data-spring-data-jpa-mysql) in a Spring Boot application, `spring-data-starter-data-jpa` and `mysql-connector-java` dependencies are required. 

Add the following dependencies to your Gradle project's `build.gradle` file:

```groovy
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'mysql:mysql-connector-java'
```

For Maven, include the following dependencies to your `pom.xml` file:

```xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
```

If you are starting a new Spring Boot project, just use [Spring Initializr](https://start.spring.io) web tool to bootstrap a new application with the above dependencies.

## Configure MySQL Database

Spring Boot automatically configures the `DataSource` bean for in-memory databases like [H2 database](https://attacomsian.com/blog/spring-data-jpa-h2-database#configure-h2-database), HSQLDB, and Apache Derby. For a MySQL database, you need to specify the database connection details in a properties file.

Open the `application.properties` file and copy and paste the following properties:

```properties
# MySQL connection properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=mypass
spring.datasource.url=jdbc:mysql://localhost:3306/testdb?createDatabaseIfNotExist=true&useSSL=false

# Log JPA queries
# Comment this in production
spring.jpa.show-sql=true

# Drop and create new tables (create, create-drop, validate, update)
# Only for testing purposes - comment this in production
spring.jpa.hibernate.ddl-auto=create

# Hibernate SQL dialect
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
```

Spring Boot will automatically configure `DataSource` based on the above properties. Make sure you change the `spring.datasource.username` and `spring.datasource.password` properties per your MySQL database installation.

The hibernate property `spring.jpa.hibernate.ddl-auto = create` will automatically create database tables based on the entity classes when the application starts.

The `createDatabaseIfNotExist=true` configuration property, included in `spring.datasource.url`, automatically creates the database schema if it doesn't already exist.

## Create `Auditable` Abstract Class

Let us now create an abstract `Auditable` class with the `createdBy`, `createdDate`, `lastModifiedBy`, and `lastModifiedDate` properties. This generic class acts as a base class with all the common auditing fields for the child entities.

To let the Spring Boot know about these audit fields, you have to annotate the fields with `@CreatedBy` and `@LastModifiedBy` to track the user who created or updated the entity, `@CreatedDate` and `@LastModifiedDate` to log the time when these changes were made.

Here is what our `Auditable` abstract class looks like:

<p class="file-desc"><span>Auditable.java</span></p>

```java
package com.attacomsian.jpa.domains;

import org.springframework.data.annotation.*;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.util.Date;

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class Auditable<T> {

    @CreatedBy
    protected T createdBy;

    @Temporal(TemporalType.TIMESTAMP)
    @CreatedDate
    protected Date createdDate;

    @LastModifiedBy
    protected T lastModifiedBy;

    @Temporal(TemporalType.TIMESTAMP)
    @LastModifiedDate
    protected Date lastModifiedDate;

    public T getCreatedBy() {
        return createdBy;
    }

    public void setCreatedBy(T createdBy) {
        this.createdBy = createdBy;
    }

    public Date getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(Date createdDate) {
        this.createdDate = createdDate;
    }

    public T getLastModifiedBy() {
        return lastModifiedBy;
    }

    public void setLastModifiedBy(T lastModifiedBy) {
        this.lastModifiedBy = lastModifiedBy;
    }

    public Date getLastModifiedDate() {
        return lastModifiedDate;
    }

    public void setLastModifiedDate(Date lastModifiedDate) {
        this.lastModifiedDate = lastModifiedDate;
    }
}
```

As you can see above, the `Auditable` class is also annotated with the `@MappedSuperclass` and `@EntityListeners` annotations. The `@MappedSuperclass` annotation indicates that the `Auditable` is only a superclass and is not a JPA entity. 

The `@EntityListeners` annotation is used to configure a JPA entity listener `AuditingEntityListener` to capture auditing information on persisting and updating entities. This entity listener class contains callback methods (annotated with `@PrePersist` and `@PreUpdate`) to persist and update audit fields when there is any create or update activity on the entity.

Any entity that extends the `Auditable` abstract class will benefit from the JPA auditing feature. Spring Data JPA will automatically manage the `CreatedBy`, `CreatedDate`, `LastModifiedBy`, and `LastModifiedDate` columns when the entity is persisted or updated.

## Create an Entity

The next step is to create a `Todo` entity class and then extend it from the `Auditable` abstract class to add the auditing functionality:

<p class="file-desc"><span>Todo.java</span></p>

```java
package com.attacomsian.jpa.domains;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name = "todos")
public class Todo extends Auditable<String> implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;
    private boolean completed;

    public Todo() {
    }

    public Todo(String title, boolean completed) {
        this.title = title;
        this.completed = completed;
    }

    // getters and setters, equals(), toString() .... (omitted for brevity)
}
```

The `Todo` class is annotated with the `Entity` annotation to indicate that it is a JPA entity. The `@Table` annotation is used to specify the name of the database table that should be mapped to this entity.

The `id` attribute is annotated with both `@Id` and `@GeneratedValue` annotations. The former indicates that it is a primary key of the entity. The latter defines the primary key generation strategy. In the above case, we have declared the primary key as an `AUTO INCREMENT` field.

## Auditing Author with `AuditorAware`

We use the `@CreatedDate` and `@LastModifiedDate` annotations for tracking created and last modified dates. Spring Data JPA automatically updates these fields by taking the current system time.

But how to tell the auditing infrastructure about the author who made these changes? It needs to know this information since we have defined the `@CreatedBy` and `@LastModifiedBy` annotations in our `Auditable` abstract class.

To tell the auditing infrastructure about the currently logged-in user, we have to provide the implementation of `AuditorAware` and override its `getCurrentAuditor` method, as shown below:

<p class="file-desc"><span>EntityAuditorAware.java</span></p>

```java
package com.attacomsian.jpa.domains;

import org.springframework.data.domain.AuditorAware;

import java.util.Optional;

public class EntityAuditorAware implements AuditorAware<String> {

    @Override
    public Optional<String> getCurrentAuditor() {
        return Optional.of("Atta");
    }
}
```

> **Note:** For the sake of simplicity, I am returning a hard-coded auditor name in the `getCurrentAuditor()` method. For real-world applications with Spring Security, you need to [find the current logged-in user](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#auditing.interfaces) and return it back.   

## Create a Repository

Let us now create the `TodoRepository` interface to save and retrieve `Todo` entities from the database as follows:

<p class="file-desc"><span>TodoRepository.java</span></p>

```java
package com.attacomsian.jpa.repositories;

import com.attacomsian.jpa.domains.Todo;
import org.springframework.data.repository.CrudRepository;

public interface TodoRepository extends CrudRepository<Todo, Long> {

    // TODO: add queries
}
```

We're extending `TodoRepository` from Spring Data JPA's [CrudRepository](https://attacomsian.com/blog/spring-data-jpa-repositories#crudrepository-interface) interface to inherit the standard CRUD methods for creating, reading, updating, and deleting `Todo` entities.

## Enable JPA Auditing

Finally, we need to enable the JPA auditing feature by specifying `@EnableJpaAuditing` on one of our configuration classes. We also need to define a bean of type `AuditorAware` and return an instance of the `EntityAuditorAware` class.

You can create a separate configuration class or use the main application class to define these configurations. Let us create the `AuditConfiguration` class to let the Spring Data JPA knows we want to enable auditing:

<p class="file-desc"><span>AuditConfiguration.java</span></p>

```java
package com.attacomsian.jpa.config;

import com.attacomsian.jpa.domains.EntityAuditorAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@Configuration
@EnableJpaAuditing
public class AuditConfiguration {

    @Bean
    public AuditorAware<String> auditorAware() {
        return new EntityAuditorAware();
    }
}
```

That's all you need to do to enable Spring Data JPA auditing functionality in your Spring Boot and MySQL application. Let us now create the main application class to test our implementation.

## Testing the Application

It is time to create the main application class for our Spring Boot project. This class also exposes a bean of type `CommandLineRunner` that defines a `run()` method, which is invoked by Spring Boot after the application context has been loaded.

<p class="file-desc"><span>Application.java</span></p>

```java
package com.attacomsian.jpa;

import com.attacomsian.jpa.domains.Todo;
import com.attacomsian.jpa.repositories.TodoRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import java.util.Arrays;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public CommandLineRunner auditingDemo(TodoRepository todoRepository) {
        return args -> {

            // create new todos
            todoRepository.saveAll(Arrays.asList(
                    new Todo("Buy milk", false),
                    new Todo("Email John", false),
                    new Todo("Visit Emma", false),
                    new Todo("Call dad", true),
                    new Todo("Weekend walk", true),
                    new Todo("Write Auditing Tutorial", true)
            ));

            // retrieve all todos
            Iterable<Todo> todos = todoRepository.findAll();

            // print all todos
            todos.forEach(System.out::println);
        };
    }
}
```

As you can see above, we first saved several todos and then retrieved them using the `findAll()` method. The last statement prints all todos on the console.

To see the actual output, you need to run the application. If you are using Gradle, execute the following command to start the application:

```bash
$ ./gradlew bootRun
```

For Maven, type the following command to launch the application:

```bash
$ ./mvnw spring-boot:run
```

Once the application is started, you should see the following output:

```bash
Todo{id=1, title='Buy milk', completed=false, createdBy=Atta, createdDate=2019-10-21 03:01:25.0, lastModifiedBy=Atta, lastModifiedDate=2019-10-21 03:01:25.0}
Todo{id=2, title='Email John', completed=false, createdBy=Atta, createdDate=2019-10-21 03:01:25.0, lastModifiedBy=Atta, lastModifiedDate=2019-10-21 03:01:25.0}
Todo{id=3, title='Visit Emma', completed=false, createdBy=Atta, createdDate=2019-10-21 03:01:25.0, lastModifiedBy=Atta, lastModifiedDate=2019-10-21 03:01:25.0}
Todo{id=4, title='Call dad', completed=true, createdBy=Atta, createdDate=2019-10-21 03:01:25.0, lastModifiedBy=Atta, lastModifiedDate=2019-10-21 03:01:25.0}
Todo{id=5, title='Weekend walk', completed=true, createdBy=Atta, createdDate=2019-10-21 03:01:25.0, lastModifiedBy=Atta, lastModifiedDate=2019-10-21 03:01:25.0}
Todo{id=6, title='Write Auditing Tutorial', completed=true, createdBy=Atta, createdDate=2019-10-21 03:01:25.0, lastModifiedBy=Atta, lastModifiedDate=2019-10-21 03:01:25.0}
```

> **Source Code:** Download the complete source code from [GitHub](https://github.com/attacomsian/code-examples/tree/master/spring-data-jpa/jpa-auditing) available under MIT license.

## Conclusion

In this article, you have learned about Spring Data JPA auditing and how to enable it in a Spring Boot and MySQL application.

In short, all you need to do is the following to enable the JPA auditing feature:

1. Define the audit fields using the `@CreatedDate`, `@CreatedBy`, `@LastModifiedDate`, and `@LastModfiiedBy` annotations. The best way to do so is by creating a generic abstract class and extending the entities that need the auditing functionality.
2. Implement the `AuditorAware` interface to let Spring Data JPA auditing infrastructure know about the currently logged-in user making the changes.
3. Add the `@EnableJpaAuditing` annotation to any configuration class to enable JPA auditing.
4. Expose a bean of type `AuditorAware` (only required if you need an auditing author).

## Further Reading

To learn more about Spring Data JPA, check out the following articles:

* [Getting Started with Spring Data JPA](https://attacomsian.com/blog/getting-started-spring-data-jpa)
* [Spring Data JPA with H2 DataBase and Spring Boot](https://attacomsian.com/blog/spring-data-jpa-h2-database)
* [Accessing Data with Spring Data JPA and MySQL](https://attacomsian.com/blog/accessing-data-spring-data-jpa-mysql)
* [Derived Query Methods in Spring Data JPA](https://attacomsian.com/blog/derived-query-methods-spring-data-jpa)
* [Spring Data JPA Custom Queries using @Query Annotation](https://attacomsian.com/blog/spring-data-jpa-query-annotation)
* [How to Use Spring Data JPA Named Queries](https://attacomsian.com/blog/spring-data-jpa-named-queries)
* [Sorting Query Results in Spring Data JPA](https://attacomsian.com/blog/spring-data-jpa-sorting)
* [Pagination with Spring Data JPA](https://attacomsian.com/blog/spring-data-jpa-pagination)
* [Spring Data JPA One To One Relationship Mapping Example](https://attacomsian.com/blog/spring-data-jpa-one-to-one-mapping)
* [Spring Data JPA One To Many Relationship Mapping Example](https://attacomsian.com/blog/spring-data-jpa-one-to-many-mapping)
* [Spring Data JPA Many To Many Relationship Mapping Example](https://attacomsian.com/blog/spring-data-jpa-many-to-many-mapping)
* [Spring Data JPA Composite Primary Key Mapping Example](https://attacomsian.com/blog/spring-data-jpa-composite-primary-key)
* [Introduction to Spring Data JPA Repositories](https://attacomsian.com/blog/spring-data-jpa-repositories)
* [Dynamic Queries with Spring Data JPA Specifications](https://attacomsian.com/blog/spring-data-jpa-specifications)
