Irminsul
Example
Installation
The minimum required Java version is 17.
Usage
First, we need to initialize the database service. Then, we can define our entities and initialize the repositories. After that, we can use the repositories to interact with the database.
In the following sections, we will go through the steps to set up the database service, define entities, use repositories, perform transactions and more.
Initializing Database Service
Defining entities
Let's create entity called a
Company
entity:@Entity @Table(name = "company") public class Company { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, unique = true) private String name; // Getters and setters public static Company create(String name) { var company = new Company(); company.name = name; return company; } }We will need a corresponding repository to interact with the
Company
entity. We will extend theBaseRepository
abstract class so we can use some of its predefined methods. In the parameters, we specify the entity type and its ID type.public class CompanyRepository extends BaseRepository<Company, Long> { public CompanyRepository(IrminsulDatabaseService databaseService) { super(databaseService); } @Override protected Class<Company> getEntityClass() { return Company.class; } @Override protected boolean hasId(Company company) { // Determines if the entity has an ID // Used by the #save() and #saveAll() methods return company.getId() != null; } }Now we can initialize the database service with our entity and repository:
var databaseService = /* ... */; // Takes array of objects databaseService.initialize(Company.class); // Initializes the repository var companyRepository = new CompanyRepository(databaseService);Now you may use the
CompanyRepository
to interact with theCompany
entity.
Using repositories
Using repositories we can perform various operations on the entities, such as finding (querying), saving and deleting them. The BaseRepository
abstract class provides some basic methods for these operations.
There are other methods, such as #insert()
and #update()
. You may only insert an entity, which does not have an ID yet. Similarly, you may only update an entity that has an ID.
Adding additional methods to repositories
In practice, we often need more than just basic CRUD operations. You may simply add new methods into your repository to suit your needs. For example, let's say we want to find a company by its name:
But what if we need entirely different method that does not fit into the predefined methods? In that case, we can use the database service's runInThreadTransaction()
method to run a custom query. Using this method, you may access the Hibernate's Session
instance and create a custom query.
Transactions
All interactions with the database are done within a transaction by default. You can run a transaction using the runInThreadTransaction()
method of the IrminsulDatabaseService
. This method takes a lambda function that receives a Session
instance, which you can use to perform database operations, and returns the result of the transaction.
The repository methods use this method internally, so you don't have to worry about managing transactions yourself.
Any subsequent database operations within the same thread will use the same transaction. This means, if you throw an exception anywhere inside the transaction, the transaction will be rolled back and no changes will be committed to the database.
In the background, the #runInThreadTransaction()
method uses a IrminsulContext
to store the current session and transaction.
After commit and rollback actions
Within a transactions, you may define a callback that will be executed after the transaction is committed or rolled back.
IrminsulContext
is used to hold the current transaction context, including the session and transaction.
Extending the database service class
You may extend the IrminsulDatabaseService
class for extra configuration or functionality. There are some methods that allows you to easily customize the logic around transactions.
These methods are invoked as follows:
Method | Invoked when |
---|---|
| Before the transaction is started |
| After the transaction is started |
| Before the transaction is committed |
| After the transaction is committed |
| Before the transaction is rolled back |
| After the transaction is rolled back |
| After the transaction is processed (committed or rolled back) |