Simple and Composite transactional services: Question about separation of concerns and transactions

I believe I know the answer to this but I’m looking for any holes or anything I may be missing.

This is focused on Spring and Java but could really apply to any programming stack.

Anyway, we have a typical service layer annotated with @Transactional in Spring. For example, we could have:

EmailService
OrderService
HistoryService

Now, the user performs an action that calls a RESTful service that does the following:

orderService.create(....);    // wrapped in @Transactional
historyService.create(....);  // wrapped in @Transactional
emailService.emailUser(....); // wrapped in @Transactional (also annotated with @Async)

While all of these are called from a controller (which is NOT @Transactional), if either the order service or the history service fail, I want both to be rolled back and the email service would abort.

I don’t like mixing the services. I think it would be ugly to have the order service call the history service just so that both of them are in the same transaction boundaries.

My first instinct was to create a hybrid service that would wrap both services together. Something like:

@Transactional
public void orderEntryService.create(....) {
    orderService.create(....);    // STILL wrapped in @Transactional
    historyService.create(....);  // STILL wrapped in @Transactional
}

This way, my controller could be:

public String create(...) {
    orderEntryService.create(...);

    emailService.emailUser(...);    // this is @Async 
                                    // and will never be called if previous 
                                    // orderEntryService.create fails
}

While I think this keeps my service layer cleaner, it can quickly start adding up to bulky and forgetful “aggregate” service classes. How to handle this?

I understand your doubts, because such service-mixins don’t look natural for me either.
But why? Strictly speaking, even in complete SOA architecture service composition is not forbidden. But your case is different. Your services are not independent units located in own processes with independent transaction management. Your services are just level in your single-process architecture, plus methods of your services are wrapped in database-transactions. So, service composition could lead to nested transactions which itself is not a problem for Spring, but still looks unnatural for me. Plus, such composition could lead to circular dependencies between your services which is evil without a doubt.

You could solve your problem by adding one more level(let’s say DataAccess) in your architecture, which will contain repositories: EmailRepository, OrderRepository, HistoryRepository. Here you will have methods for managing emails, orders, history etc: adding, updating, deleting, querying. And you could share these repositories in your different services, having transaction wrappers where they are now – around your services.

It’s just the simplest solution that could help you, not talking about more sophisticated approaches such as DDD.

2

I do not have a definitive answer but here are my points:

In favor:

  • I do not like business logic in the controller. They already have a lot of boilerplate code related to the view, format, transformations, bindings, mapping, etc. Three calls with its own error handling (and may be some specials cases) can become complex enough to bring bugs. The logic of how to create an order could be complex enough that that you want it separated from how do you call it.
  • Controllers are hard to test. Services are easy. You avoid mocking the WebApplicationContext, the json de/serialization, the controller error handling, SpringSecurityFilterChain, etc. You may even have to mock authorization. Of course you will try to test the controller anyway but those are heavier test that focus on the communication between server and client. With locale and input santiation they have enough complexity.

  • Task that need to be executed transactionally. Lets say that you need to execute two services: shipGoods and chargeCreditCard. shipGoods executes sucessfully and then chargeCreditCard fails. You would like to revert the shipping order. Alternative: You could create a “component” level between DAO and Service when only full business logic is called in services. And you do not want transactionall DAOs.

  • Allow smaller transactions when you do not need a big one. In the opossite case you may be calling a lot of functionallity like search services or webservices calls. If you do not need to rollback a transaction it is better to commit it as soon as possible. Open transactions can lock database records (or even full tables) reducing performance. Example: update entity in database, call slow remote webservice add create a different entity. In a big transation approach the entity won’t be committed until the last creation ends and nobody will be able to update the original record.

  • Code reuse: It is hard to reuse code without services calling another services. Lets say you have a very tested “chargeCreditCard” method. You may want to reuse it even in cases where “shipGoods” is changed to “preorderItem”. If you consider sending an email a service (and it seems so judging by emailService) then it seems that “forgottenPasswordService”, “newsLetterService”, “shippingService” could really benefit from reusing the funtionality.

Against:

  • Complex transactions: if you create a big transaction that includes the three services you will have to think about what happens when each one fails. Nothings forbids the creation of a non-transactional service that calls transactional ones. That is the easy case. Nested transactions and autonomous transactions can be powerfull but hard and dangerous.
  • Complexity: You can end with lots of services calling services calling services. Do you really have a business logic so complex? Beware of creating services like transactional DAOs with only CRUD operations but hardly any logic: For example: OrderService, HistoryService. In this case you can consider that OrderService should call historyDAO and include histories automatically when you create an order. (Avoid the Anemic Domain Model Antipattern).

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật