12 April 2018 · spring
Distributed Transactions with Spring
https://bitbucket.org/catchers/atomikos-distributed-transactions/src/master/
AppConfig.java
package org.catcher.sandbox.learningspring.config;
import javax.sql.DataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
@Primary
@ConfigurationProperties("sms.datasource")
DataSource createPostgresSqlDataSource() {
return new AtomikosDataSourceBean();
}
@Bean
@ConfigurationProperties("complaint.datasource")
DataSource createMySqlDataSource() {
return new AtomikosDataSourceBean();
}
@Bean
NamedParameterJdbcOperations smsJdbcTemplate() {
return new NamedParameterJdbcTemplate(createPostgresSqlDataSource());
}
@Bean
NamedParameterJdbcOperations complaintJdbcTemplate() {
return new NamedParameterJdbcTemplate(createMySqlDataSource());
}
}
package org.catcher.sandbox.learningspring.controller;
import org.catcher.sandbox.learningspring.service.ComplaintService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ComplaintController {
private static final Logger logger = LoggerFactory.getLogger(ComplaintController.class);
private final ComplaintService complaintService;
public ComplaintController(ComplaintService complaintService) {
this.complaintService = complaintService;
}
@RequestMapping("/complaint")
public String createComplaint(@RequestParam String firstName, @RequestParam String lastName,
@RequestParam String complaint, @RequestParam String phoneNumber) {
logger.info("Complaint creation entered FirstName: {}, LastName: {}, Complaint: {}, PhoneNumber: {}", firstName,
lastName, complaint, phoneNumber);
complaintService.newComplaint(firstName, lastName, complaint, phoneNumber);
return "OK";
}
}
package org.catcher.sandbox.learningspring.repository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.stereotype.Repository;
@Repository
public class ComplaintRepositoryImpl implements ComplaintRepository {
private static final Logger logger = LoggerFactory.getLogger(ComplaintRepositoryImpl.class);
private final NamedParameterJdbcOperations complaintJdbcTemplate;
public ComplaintRepositoryImpl(NamedParameterJdbcOperations complaintJdbcTemplate) {
this.complaintJdbcTemplate = complaintJdbcTemplate;
}
@Override
public void storeData(String firstName, String lastName, String complaint) {
logger.info("Storing Complaint Data, First Name: {}, Last Name: {}, Complaint {}", firstName, lastName,
complaint);
final String sql = "insert into complaint(firstname, lastname, complaint) values (:firstName, :lastName, :complaint)";
MapSqlParameterSource paramSource = new MapSqlParameterSource("firstName", firstName);
paramSource.addValue("lastName", lastName);
paramSource.addValue("complaint", complaint);
complaintJdbcTemplate.update(sql, paramSource);
//throw new RuntimeException(); // Uncomment this line to verify distributed transactions
}
}
package org.catcher.sandbox.learningspring.repository;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.stereotype.Repository;
@Repository
public class SmsRepositoryImpl implements SmsRepository {
private static final Logger logger = LoggerFactory.getLogger(SmsRepositoryImpl.class);
private final NamedParameterJdbcOperations smsJdbcTemplate;
SmsRepositoryImpl(NamedParameterJdbcOperations smsJdbcTemplate) {
this.smsJdbcTemplate = smsJdbcTemplate;
}
@Override
public void storeSMS(String phoneNumber, String smsText) {
logger.info("Storing SMS Data, Phone: {}, Text: {}", phoneNumber, smsText);
final String sql = "insert into sms(sms_text, phone_number, insert_date) values (:smsText, :phoneNumber, :insertDate)";
MapSqlParameterSource paramSource = new MapSqlParameterSource("smsText", smsText);
paramSource.addValue("phoneNumber", phoneNumber);
paramSource.addValue("insertDate", new Date());
smsJdbcTemplate.update(sql, paramSource);
}
}