MVC three-tier architecture
When we are just becoming programmers, we are “taught” by our predecessors that system design should follow the MVC (Model-View-Controller) architecture. It divides the whole system into three layers: Model, View and Controller. That is, it separates the user View from the business process and connects the user View with the Controller, which well realizes the decoupling of performance and logic. It is a standard software layered architecture.
MVC layered architecture is the simplest way to layer architecture. To follow this hierarchical architecture, we often build projects with three directories: Controller, Service, and DAO, which correspond to the presentation layer, logical layer, and data access layer, respectively.
The functions of each layer are as follows:
- Controller layer: it mainly forwards access control, verifies all kinds of basic parameters, or simply processes services that do not need to be reused.
- Service layer: Mainly handles business logic and transactions
- Dao layer: Responsible for data interaction with the underlying databases, such as MySQL and Oracle
But as our business logic became more complex and we wrote more code, the problems with this simple three-tier architecture became more apparent.
Disadvantages of MVC Architecture
There are several obvious problems with traditional MVC layering:
-
Service layer code bloat
-
The Service layer is prone to large transactions and nested transactions, resulting in many problems and extremely difficult to troubleshoot
-
The DAO layer involves miscellaneous business logic
-
Dao layer SQL statement complex, associated query more
In order to solve this problem, we refer to “Alibaba Java Development Manual” and create an independent general business processing layer (Manager layer) under the Service layer.
In this hierarchical architecture, the Manager layer is mainly added. Its relationship with the Service layer is that the Manager layer provides the atomic Service interfaces, and the Service layer is responsible for arranging the atomic interfaces according to the business logic.
Characteristics of the Manager layer
The Manager layer is described in the Alibaba Java Development Manual as follows:
Manager layer: General business processing layer, which has the following characteristics:
- For the layer encapsulated by the third-party platform, the pre-processing returned results and abnormal information are converted to adapt the upper interface;
- The sinking of common capabilities of the Service layer, such as caching schemes, middleware common processing;
- Interacts with the DAO layer to reuse multiple DAOs in combination.
In real development we can use the Manager layer this way
-
For complex business, the service provides data to the Manager layer, takes care of the orchestration of the business, and then sinks the transaction into the Manager layer. The Manager layer does not allow calls to each other, and there is no transaction nesting.
-
Focusing on the NON-business SQL language, it is also possible to encapsulate the DAO layer of common business at the Manager layer.
-
Avoid complex join queries, the database pressure is much greater than Java, so it is necessary to strictly control SQL, so it can be split in the Manager layer, such as complex queries.
Of course, for simple businesses, the Manager layer can be dispensable.
Manager layer use cases
Here is an example to illustrate the use scenario of the Manager layer:
Suppose you have a User system that has an interface to getUser information. It calls the getUser method in the logical Service layer, which in turn interacts with the User DB to get data. The left part is shown below.
At this time, the product puts forward a requirement that when displaying the user information in the APP, if the user does not exist, it will automatically create a user for the user. At the same time, to make an HTML5 page, the HTML5 page should retain the previous logic, that is, it does not need to create users.
At this point, according to the traditional three-tier architecture, the boundary of the logical layer becomes unclear, and the presentation layer also assumes part of the business logic, because we tend to add business logic processing in the presentation layer Controller, choreographing the acquisition of users and the creation of user interfaces.
With the addition of the Manager layer, the Manager layer provides interfaces for creating users and getting user information, while the Service layer is responsible for assembling the two interfaces. This unifies the business logic that was previously scattered in the presentation layer into the Service layer, and the boundaries of each layer are clear.
Let’s look at some actual code and see how the Service layer and Manager layer are distinguished.
@Transactional(rollbackFor = Throwable.class)
public Result<String> upOrDown(Long departmentId, Long swapId) {
/ / 1
DepartmentEntity departmentEntity = departmentDao.selectById(departmentId);
if (departmentEntity == null) {
return Result.error("Department XXX does not exist");
}
/ / 2
DepartmentEntity swapEntity = departmentDao.selectById(swapId);
if (swapEntity == null) {
return Result.error("Department XXX does not exist");
}
/ / 3
Long count = employeeDao.countByDepartmentId(departmentId);
if(count ! =null && count > 0) {
return Result.error("The employee does not exist.");
}
// Run database 4
Long departmentSort = departmentEntity.getSort();
departmentEntity.setSort(swapEntity.getSort());
departmentDao.updateById(departmentEntity);
swapEntity.setSort(departmentSort);
departmentDao.updateById(swapEntity);
return Result.OK("success");
}
Copy the code
What is the problem with this code that we often encounter when we adopt a three-tier architecture?
The above code is a classic example of a long transaction problem (as well as invoking a third-party interface). The first three steps all use connection for validation, but because the method has the @Transactional annotation, all three use the same Connection.
For complex services and authentication logic, the connection may be occupied for a long time during the whole authentication process. The connection will be returned to the database connection pool only after the method ends.
For the unpredictable situation of complex business, it is not a good thing to occupy the same connection for a long time. It should be minimized.
Description: For the @Transactional annotation, when Spring encounters it, the connection is automatically fetched from the database connection pool, the transaction is opened and bound to ThreadLocal. If the Transactional annotation does not make it to the final Transactional database, There is no need to get a connection and start a transaction, and the connection should be returned directly to the database connection pool for other use.
So when we add the Manager layer, we can write:
DepartmentService.java
public Result<String> upOrDown(Long departmentId, Long swapId) {
/ / 1
DepartmentEntity departmentEntity = departmentDao.selectById(departmentId);
if (departmentEntity == null) {
return Result.error("Department XXX does not exist");
}
/ / 2
DepartmentEntity swapEntity = departmentDao.selectById(swapId);
if (swapEntity == null) {
return Result.error("Department XXX does not exist");
}
/ / 3
Long count = employeeDao.countByDepartmentId(departmentId);
if(count ! =null && count > 0) {
return Result.error("The employee does not exist.");
}
// Run database 4
departmentManager.upOrDown(departmentSort,swapEntity);
return Result.OK("success");
}
Copy the code
DepartmentManager.java
@Transactional(rollbackFor = Throwable.class)
public void upOrDown(DepartmentEntity departmentEntity ,DepartmentEntity swapEntity){
Long departmentSort = departmentEntity.getSort();
departmentEntity.setSort(swapEntity.getSort());
departmentDao.updateById(departmentEntity);
swapEntity.setSort(departmentSort);
departmentDao.updateById(swapEntity);
}
Copy the code
The data is prepared at the Service layer and passed to the Manager layer, which adds the @Transactional transaction annotation for database operations.