revision
- @Transaction and programmatic using the same example case. - XML format
This commit is contained in:
parent
33b65622a5
commit
9325f26b24
|
@ -0,0 +1,5 @@
|
|||
package com.baeldung.jta;
|
||||
|
||||
public class AuditService {
|
||||
|
||||
}
|
136
jta/pom.xml
136
jta/pom.xml
|
@ -1,46 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>jta-demo</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>jta-demo</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<description>JEE JTA demo</description>
|
||||
<description>JEE JTA demo</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.0.4.RELEASE</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.0.4.RELEASE</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jta-bitronix</artifactId>
|
||||
</dependency>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jta-bitronix</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
|
@ -49,40 +49,40 @@
|
|||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>autoconfiguration</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>integration-test</phase>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/*LiveTest.java</exclude>
|
||||
<exclude>**/*IntegrationTest.java</exclude>
|
||||
<exclude>**/*IntTest.java</exclude>
|
||||
</excludes>
|
||||
<includes>
|
||||
<include>**/AutoconfigurationTest.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<test.mime>json</test.mime>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>autoconfiguration</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>integration-test</phase>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/*LiveTest.java</exclude>
|
||||
<exclude>**/*IntegrationTest.java</exclude>
|
||||
<exclude>**/*IntTest.java</exclude>
|
||||
</excludes>
|
||||
<includes>
|
||||
<include>**/AutoconfigurationTest.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<test.mime>json</test.mime>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package com.baeldung.jtademo.services;
|
||||
|
||||
import com.baeldung.jtademo.dto.TransferLog;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
|
@ -18,8 +20,14 @@ public class AuditService {
|
|||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void log(String fromAccount, String toAccount, BigDecimal amount) {
|
||||
jdbcTemplate.update("insert into AUDIT_LOG(FROM_ACCOUNT, TO_ACCOUNT, AMOUNT) values ?,?,?", fromAccount, toAccount, amount);
|
||||
}
|
||||
|
||||
public TransferLog lastTransferLog() {
|
||||
return jdbcTemplate.query("select FROM_ACCOUNT,TO_ACCOUNT,AMOUNT from AUDIT_LOG order by ID desc", (ResultSetExtractor<TransferLog>) (rs) -> {
|
||||
if(!rs.next()) return null;
|
||||
return new TransferLog(rs.getString(1), rs.getString(2), BigDecimal.valueOf(rs.getDouble(3)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
package com.baeldung.jtademo.services;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.transaction.UserTransaction;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Component
|
||||
public class BankAccountManualTxService {
|
||||
@Resource
|
||||
UserTransaction userTransaction;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("jdbcTemplateAccount")
|
||||
JdbcTemplate jdbcTemplate;
|
||||
|
||||
public void transfer(String fromAccountId, String toAccountId, BigDecimal amount) throws Exception {
|
||||
userTransaction.begin();
|
||||
jdbcTemplate.update("update ACCOUNT set BALANCE=BALANCE-? where ID=?", amount, fromAccountId);
|
||||
jdbcTemplate.update("update ACCOUNT set BALANCE=BALANCE+? where ID=?", amount, toAccountId);
|
||||
userTransaction.commit();
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package com.baeldung.jtademo.services;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
|
@ -18,9 +19,15 @@ public class BankAccountService {
|
|||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void transfer(String fromAccountId, String toAccountId, BigDecimal amount) {
|
||||
jdbcTemplate.update("update ACCOUNT set BALANCE=BALANCE-? where ID=?", amount, fromAccountId);
|
||||
jdbcTemplate.update("update ACCOUNT set BALANCE=BALANCE+? where ID=?", amount, toAccountId);
|
||||
}
|
||||
|
||||
public BigDecimal balanceOf(String accountId) {
|
||||
return jdbcTemplate.query("select BALANCE from ACCOUNT where ID=?", new Object[] { accountId }, (ResultSetExtractor<BigDecimal>) (rs) -> {
|
||||
rs.next();
|
||||
return new BigDecimal(rs.getDouble(1));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,29 +4,42 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import javax.transaction.UserTransaction;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Service
|
||||
public class TellerService {
|
||||
private final BankAccountService bankAccountService;
|
||||
private final AuditService auditService;
|
||||
private final UserTransaction userTransaction;
|
||||
|
||||
@Autowired
|
||||
public TellerService(BankAccountService bankAccountService, AuditService auditService) {
|
||||
public TellerService(BankAccountService bankAccountService, AuditService auditService, UserTransaction userTransaction) {
|
||||
this.bankAccountService = bankAccountService;
|
||||
this.auditService = auditService;
|
||||
this.userTransaction = userTransaction;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void executeTransfer(String fromAccontId, String toAccountId, BigDecimal amount) {
|
||||
bankAccountService.transfer(fromAccontId, toAccountId, amount);
|
||||
auditService.log(fromAccontId, toAccountId, amount);
|
||||
BigDecimal balance = bankAccountService.balanceOf(fromAccontId);
|
||||
if(balance.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new RuntimeException("Insufficient fund.");
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void executeTransferFail(String fromAccontId, String toAccountId, BigDecimal amount) {
|
||||
public void executeTransferProgrammaticTx(String fromAccontId, String toAccountId, BigDecimal amount) throws Exception {
|
||||
userTransaction.begin();
|
||||
bankAccountService.transfer(fromAccontId, toAccountId, amount);
|
||||
auditService.log(fromAccontId, toAccountId, amount);
|
||||
throw new RuntimeException("Something wrong, rollback!");
|
||||
BigDecimal balance = bankAccountService.balanceOf(fromAccontId);
|
||||
if(balance.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
userTransaction.rollback();
|
||||
throw new RuntimeException("Insufficient fund.");
|
||||
} else {
|
||||
userTransaction.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,17 +43,5 @@ public class TestHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public TransferLog lastTransferLog() {
|
||||
return jdbcTemplateAudit.query("select FROM_ACCOUNT,TO_ACCOUNT,AMOUNT from AUDIT_LOG order by ID desc", (ResultSetExtractor<TransferLog>) (rs) -> {
|
||||
if(!rs.next()) return null;
|
||||
return new TransferLog(rs.getString(1), rs.getString(2), BigDecimal.valueOf(rs.getDouble(3)));
|
||||
});
|
||||
}
|
||||
|
||||
public BigDecimal balanceOf(String accountId) {
|
||||
return jdbcTemplateAccount.query("select BALANCE from ACCOUNT where ID=?", new Object[] { accountId }, (ResultSetExtractor<BigDecimal>) (rs) -> {
|
||||
rs.next();
|
||||
return new BigDecimal(rs.getDouble(1));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package com.baeldung.jtademo;
|
||||
|
||||
import com.baeldung.jtademo.dto.TransferLog;
|
||||
import com.baeldung.jtademo.services.BankAccountManualTxService;
|
||||
import com.baeldung.jtademo.services.TellerService;
|
||||
import com.baeldung.jtademo.services.TestHelper;
|
||||
import com.baeldung.jtademo.services.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
@ -25,7 +23,10 @@ public class JtaDemoUnitTest {
|
|||
TellerService tellerService;
|
||||
|
||||
@Autowired
|
||||
BankAccountManualTxService bankAccountManualTxService;
|
||||
BankAccountService accountService;
|
||||
|
||||
@Autowired
|
||||
AuditService auditService;
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
|
@ -34,14 +35,13 @@ public class JtaDemoUnitTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void whenNoException_thenAllCommitted() throws Exception {
|
||||
public void givenAnnotationTx_whenNoException_thenAllCommitted() throws Exception {
|
||||
tellerService.executeTransfer("a0000001", "a0000002", BigDecimal.valueOf(500));
|
||||
|
||||
BigDecimal result = testHelper.balanceOf("a0000001");
|
||||
assertThat(testHelper.balanceOf("a0000001")).isEqualByComparingTo(BigDecimal.valueOf(500));
|
||||
assertThat(testHelper.balanceOf("a0000002")).isEqualByComparingTo(BigDecimal.valueOf(2500));
|
||||
assertThat(accountService.balanceOf("a0000001")).isEqualByComparingTo(BigDecimal.valueOf(500));
|
||||
assertThat(accountService.balanceOf("a0000002")).isEqualByComparingTo(BigDecimal.valueOf(2500));
|
||||
|
||||
TransferLog lastTransferLog = testHelper.lastTransferLog();
|
||||
TransferLog lastTransferLog = auditService.lastTransferLog();
|
||||
assertThat(lastTransferLog).isNotNull();
|
||||
assertThat(lastTransferLog.getFromAccountId()).isEqualTo("a0000001");
|
||||
assertThat(lastTransferLog.getToAccountId()).isEqualTo("a0000002");
|
||||
|
@ -49,22 +49,39 @@ public class JtaDemoUnitTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void whenException_thenAllRolledBack() throws Exception {
|
||||
public void givenAnnotationTx_whenException_thenAllRolledBack() throws Exception {
|
||||
assertThatThrownBy(() -> {
|
||||
tellerService.executeTransferFail("a0000002", "a0000001", BigDecimal.valueOf(100));
|
||||
}).hasMessage("Something wrong, rollback!");
|
||||
tellerService.executeTransfer("a0000002", "a0000001", BigDecimal.valueOf(100000));
|
||||
}).hasMessage("Insufficient fund.");
|
||||
|
||||
assertThat(testHelper.balanceOf("a0000001")).isEqualByComparingTo(BigDecimal.valueOf(1000));
|
||||
assertThat(testHelper.balanceOf("a0000002")).isEqualByComparingTo(BigDecimal.valueOf(2000));
|
||||
|
||||
assertThat(testHelper.lastTransferLog()).isNull();
|
||||
assertThat(accountService.balanceOf("a0000001")).isEqualByComparingTo(BigDecimal.valueOf(1000));
|
||||
assertThat(accountService.balanceOf("a0000002")).isEqualByComparingTo(BigDecimal.valueOf(2000));
|
||||
assertThat(auditService.lastTransferLog()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenBMT_whenNoException_thenAllCommitted() throws Exception {
|
||||
bankAccountManualTxService.transfer("a0000001", "a0000002", BigDecimal.valueOf(100));
|
||||
public void givenProgrammaticTx_whenCommit_thenAllCommitted() throws Exception {
|
||||
tellerService.executeTransferProgrammaticTx("a0000001", "a0000002", BigDecimal.valueOf(500));
|
||||
|
||||
assertThat(testHelper.balanceOf("a0000001")).isEqualByComparingTo(BigDecimal.valueOf(900));
|
||||
assertThat(testHelper.balanceOf("a0000002")).isEqualByComparingTo(BigDecimal.valueOf(2100));
|
||||
BigDecimal result = accountService.balanceOf("a0000001");
|
||||
assertThat(accountService.balanceOf("a0000001")).isEqualByComparingTo(BigDecimal.valueOf(500));
|
||||
assertThat(accountService.balanceOf("a0000002")).isEqualByComparingTo(BigDecimal.valueOf(2500));
|
||||
|
||||
TransferLog lastTransferLog = auditService.lastTransferLog();
|
||||
assertThat(lastTransferLog).isNotNull();
|
||||
assertThat(lastTransferLog.getFromAccountId()).isEqualTo("a0000001");
|
||||
assertThat(lastTransferLog.getToAccountId()).isEqualTo("a0000002");
|
||||
assertThat(lastTransferLog.getAmount()).isEqualByComparingTo(BigDecimal.valueOf(500));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenProgrammaticTx_whenRollback_thenAllRolledBack() throws Exception {
|
||||
assertThatThrownBy(() -> {
|
||||
tellerService.executeTransferProgrammaticTx("a0000002", "a0000001", BigDecimal.valueOf(100000));
|
||||
}).hasMessage("Insufficient fund.");
|
||||
|
||||
assertThat(accountService.balanceOf("a0000001")).isEqualByComparingTo(BigDecimal.valueOf(1000));
|
||||
assertThat(accountService.balanceOf("a0000002")).isEqualByComparingTo(BigDecimal.valueOf(2000));
|
||||
assertThat(auditService.lastTransferLog()).isNull();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue