Skip to content

Commit ad9522b

Browse files
committed
Update docs for nestjs-transaction: feat: change to async storage
1 parent 020e742 commit ad9522b

1 file changed

Lines changed: 107 additions & 37 deletions

File tree

pages/nestjs-transaction/index.md

Lines changed: 107 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,64 +18,134 @@ npm install @hodfords/nestjs-transaction --save
1818

1919
## Usage 🚀
2020

21-
First, extend the `TransactionService` imported from the library in your service, and then use the `withTransaction`
22-
method within the transaction callback to call your service.
21+
First, you need to import the `TransactionModule` into your `AppModule` and
22+
23+
```typescript
24+
import { Module } from '@nestjs/common';
25+
import { TransactionModule } from '@hodfords/nestjs-transaction';
26+
27+
@Module({
28+
imports: [
29+
TransactionModule.forRoot({
30+
autoUseMasterNodeForChangeRequest: true
31+
}),
32+
// other modules
33+
],
34+
controllers: [],
35+
providers: [],
36+
})
37+
export class AppModule {}
38+
```
39+
#### Optional Configuration
40+
You can configure the `TransactionModule` with the following options:
41+
- `autoUseMasterNodeForChangeRequest`: If set to `true`, the module will automatically use the master node for change requests (except GET). This is useful for ensuring that write operations are always directed to the correct database node.
2342

2443
### How to use
2544

26-
##### your-service.service.ts
45+
#### Transactional
46+
47+
You can use the `@Transactional` decorator to mark a method as transactional. This means that all database operations within this method and child methods will be executed within a transaction context. If any operation fails, the entire transaction will be rolled back, ensuring data integrity.
48+
49+
In any service, you can use the `@Transactional` decorator to ensure that the method is executed within a transaction context:
50+
51+
> **Note**: We suggest using the `@Transactional` decorator on Controller/Task/Cron jobs methods, as it will automatically handle the transaction lifecycle for you. However, you can also use it in services if needed.
2752
2853
```typescript
29-
@Injectable()
30-
export class YourService extends TransactionService {
31-
public constructor(
32-
@InjectRepository(YourRepository) private repository: Repository<Entity>,
33-
private yourCustomRepository: CustomRepository,
34-
private yourService: Service,
35-
// Let's say you don't want to rebuild this service in the transaction
36-
private yourCacheService: CacheService,
37-
@Inject(forwardRef(() => ForwardService)) private yourForwardService: ForwardService
38-
) {
39-
super();
40-
}
54+
@Transactional()
55+
async myTransactionalMethod() {
56+
await this.myRepository.save(myEntity);
57+
}
58+
```
59+
60+
In controllers, you can also use the `@Transactional` decorator to ensure that the entire request is wrapped in a transaction:
61+
```typescript
4162

42-
async theMethodWillUseTransaction(payload: SomePayload) {
43-
// logic code here
63+
import { Controller, Post } from '@nestjs/common';
64+
import { Transactional } from '@hodfords/nestjs-transaction';
65+
import { MyService } from './my.service';
66+
67+
@Controller('my')
68+
export class MyController {
69+
constructor(private myService: MyService) {}
70+
71+
@Post('create')
72+
@Transactional()
73+
async create() {
74+
return this.myService.create();
4475
}
4576
}
4677
```
4778

48-
##### your-controller.controller.ts
79+
You also use the `@Transactional` decorator with options to control the transaction behavior, such as isolation level. For example:
80+
81+
```typescript
82+
@Transactional({ isolationLevel: 'SERIALIZABLE'})
83+
async myTransactionalMethod() {
84+
// This method will run in a transaction with SERIALIZABLE isolation level
85+
await this.myRepository.save(myEntity);
86+
}
87+
```
88+
89+
#### Replication
90+
You can use the `@UseMasterNode`/`@UseSlaveNode` decorator to ensure that a method is executed on the master/slave node. This is useful for write operations that need to be directed to the master/slave database node.
4991

5092
```typescript
51-
import { DataSource } from 'typeorm';
52-
53-
@Controller()
54-
export class SomeController {
55-
constructor(
56-
private readonly yourService: YourService,
57-
private dataSource: DataSource
58-
) {}
59-
60-
async method(payload: SomePayload): Promise<SomeResponse> {
61-
return this.dataSource.transaction(async (entityManager) => {
62-
return await this.yourService
63-
.withTransaction(entityManager, { excluded: [CacheService] })
64-
.theMethodWillUseTransaction(payload);
65-
});
93+
import { Controller, Post } from '@nestjs/common';
94+
import { UseMasterNode } from '@hodfords/nestjs-transaction';
95+
import { MyService } from './my.service';
96+
97+
@Controller('my')
98+
export class MyController {
99+
constructor(private myService: MyService) {}
100+
101+
@Post('create')
102+
@UseMasterNode()
103+
async create() {
104+
return this.myService.create();
66105
}
67106
}
68107
```
69108

70-
### Exclude services from transaction
109+
#### Hooks
71110

72-
You can configure services to be excluded from transactions by specifying them in `transactionConfig` and importing it
73-
into `AppModule`
111+
You can use the `@RunAfterTransactionCommit` decorator to run a method after a transaction has been successfully committed. This is useful for performing actions that should only occur if the transaction was successful.
74112

75113
```typescript
76-
export const transactionConfig = TransactionModule.forRoot([MailService, I18nService, StorageService, DataSource]);
114+
import { Injectable } from '@nestjs/common';
115+
import { RunAfterTransactionCommit } from '@hodfords/nestjs-transaction';
116+
import { PostRepository } from './post.repository';
117+
118+
@Injectable()
119+
export class MyService {
120+
121+
constructor(private postRepo: PostRepository) {
122+
}
123+
124+
@Transactional()
125+
async create() {
126+
// Perform some database operations
127+
await this.postRepo.createPost({ title: 'New Post', content: 'This is a new post.' });
128+
await this.emitEvent();
129+
}
130+
131+
@RunAfterTransactionCommit()
132+
async emitEvent() {
133+
// This method will be called after the transaction is committed
134+
console.log('Transaction committed successfully!');
135+
}
136+
}
77137
```
78138

139+
You also use it with method `runAfterTransactionCommit` without the decorator:
140+
141+
```typescript
142+
143+
this.postRepo.create(...);
144+
runAfterTransactionCommit(() => {
145+
// This code will run after the transaction is committed
146+
console.log('Transaction committed successfully!');
147+
});
148+
```
79149
## License 📝
80150

81151
This project is licensed under the MIT License

0 commit comments

Comments
 (0)