@SoftDelete
annotation, introduced in Hibernate version 6.4, provides first-class support for soft deletes, allowing to logically mark rows rows as deleted without actually removing them from the Database. In this tutorial we will see a proof of concept example of @SoftDelete
and its common configuration attributes.
What is a Soft Delete?
A Soft Delete marks a Database record as no longer active or valid without physically deleting it. In a nutshell, it adds metadata in your Table indicating which data should be considered deleted.
Soft deletes can be beneficial in several scenarios, such as:
- You want to be able to recover your data before you delete it permanently. This is especially useful in the testing phase.
- You want to audit Statements before you actually delete them
- To keep referential integrity between Tables
Let’s see in practice how to create a simple Maven project which uses Hibernate 6.4 and SoftDelete. To learn how to set up an Hibernate Project with Maven we recommend the following article: Hibernate 6 with Maven made simple
Implementing SoftDelete in Hibernate
Hibernate includes support for SoftDeletes since version 6.4, therefore you need to use this version or a newer one:
<dependency> <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-core</artifactId> <version>6.4.0.Final</version> </dependency>
Then, to use SoftDelete in Hibernate you can place the annotation @SoftDelete either on a Column or on an Entity as in the following example:
@Entity @SoftDelete(columnName = "removed") public class Customer implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Column private String email; @Column private String firstName; @Column private String lastName; // Omitted for brevity }
Please notice the optional attribute (columnName = "removed"
) which we can use to indicate the column name to mark the Row as Deleted. Later on we will also discuss other available options
Next, we will add a simple Class to insert and delete a row in the Customer Table that backs the above Entity.
public class SoftDeleteExample { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("persistence01"); Customer c = new Customer(); c.setFirstName("John"); c.setLastName("Doe"); c.setEmail("[email protected]"); EntityManager entityManager = emf.createEntityManager(); entityManager.getTransaction().begin(); entityManager.persist(c); entityManager.getTransaction().commit(); entityManager.getTransaction().begin(); entityManager.remove(c); entityManager.getTransaction().commit(); List<Customer> customers = entityManager.createQuery("SELECT c FROM Customer c", Customer.class) .getResultList(); for (Customer customer : customers) { System.out.println(customers); } List<Customer> nativeCustomers = entityManager.createNativeQuery("SELECT * FROM Customer c", Customer.class) .getResultList(); System.out.println("Native query"); for (Customer customer : nativeCustomers) { System.out.println(customer); } entityManager.close(); emf.close(); } }
The purpose of this Class is pretty simple. We will first add a Customer Entity. After that, we will delete it. Since the Entity uses @SoftDelete
for its rows, we should see a different outcome when using Hibernate Query and plain Native Query.
Running our example
Let’s run our example:
mvn exec:java
When we insert our Customer Entity, the following Data will be available in the Database:
As you can see, the Table Customer includes an extra column “removed” according to our annoation @SoftDelete(columnName = “removed”).
Then, if we remove the Entity, the Data will still be available in the DB, just the field removed
is not set to “t”:
Changing the SoftDelete Strategy
By default, when you use the @SoftDelete
annotation on your code, it will use the DELETE Strategy. It means that behind the hoods Hibernate will set the attribute (removed) to true when you perform a soft delete:
Hibernate: update Customer set removed=true where id=? and removed=true
Another possible approach is to use the ACTIVE strategy:
@SoftDelete(strategy= SoftDeleteType.ACTIVE)
This strategy works in the opposite way. When you soft delete an Entity, it will mark is as not active:
Hibernate: update Customer set active=false where id=? and active=true
The difference lies in the interpretation of the indicator values in the database. The ACTIVE
strategy interprets true
as an active row and false
as deleted, while the DELETED
strategy interprets true
as deleted and false
as an active row.
Finally, it is also possible to use a Custom Converter as Strategy to map a SoftDelete with a character. For example, you could use a YesNoConverter :
SoftDelete(converter = YesNoConverter.class)
Conclusion
By leveraging soft deletes in Hibernate, you can maintain data integrity, comply with regulations, improve data recovery processes, and implement various application-specific functionalities without permanently removing records from your database.
Source code for this article: https://github.com/fmarchioni/mastertheboss/tree/master/hibernate/soft-delete