JTA重点在于解决多个数据源之间的事务。如:保证DB操作和MQ操作在同一个事务下,要么一起提交,要么一起回滚。
XA为规范,JTA为java中的接口定义。
jta:Java Transaction API,即是java中对事务处理的api
atomikos:Atomikos TransactionsEssentials 是一个为Java平台提供增值服务的并且开源类事务管理器
单数据源实现:
POM.xml:
<?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.imooc.example</groupId>
<artifactId>spring-trans-jta</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging><name>spring-trans-jta</name>
<description>Demo project for Spring JTA transaction</description><parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</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><dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies><build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
web层:
package com.immoc.example.springtx.web;
import com.immoc.example.springtx.domain.Customer;
import com.immoc.example.springtx.service.CustomerServiceTxInCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;@RestController
@RequestMapping("/api/customer")
public class CustomerResource {
private static final Logger LOG = LoggerFactory.getLogger(CustomerResource.class);@Autowired
private CustomerServiceTxInCode customerServiceInCode;@PostMapping("/code")
public Customer createInCode(@RequestBody Customer customer) {
LOG.info("CustomerResource create in code create customer:{}", customer.getUsername());
return customerServiceInCode.create(customer);
}
}
service层:
package com.immoc.example.springtx.service;
import com.immoc.example.springtx.dao.CustomerRepository;
import com.immoc.example.springtx.domain.Customer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;@Service
public class CustomerServiceTxInCode {private static final Logger LOG = LoggerFactory.getLogger(CustomerServiceTxInCode.class);
@Autowired
private CustomerRepository customerRepository;
//事务管理器
@Autowired
private PlatformTransactionManager transactionManager;public Customer create(Customer customer) {
LOG.info("CustomerService In Code create customer:{}", customer.getUsername());
if (customer.getId() != null) {
throw new RuntimeException("用户已经存在");
}
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
//事务传播行为
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
//超时时间
def.setTimeout(15);
TransactionStatus status = transactionManager.getTransaction(def);
try {
customer.setUsername("Code:" + customer.getUsername());
customerRepository.save(customer);
//提交事务
transactionManager.commit(status);
return customer;
} catch (Exception e) {
//事务回滚
transactionManager.rollback(status);
throw e;
}
}
}
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
<include resource="org/springframework/boot/logging/logback/base.xml"/><logger name="com.imooc.example" level="DEBUG"/>
<logger name="com.atomikos" level="INFO"/>
<logger name="org.springframework.transaction" level="DEBUG"/>
<logger name="org.springframework.jms" level="DEBUG"/>
<logger name="org.springframework.jdbc" level="DEBUG"/>
<logger name="org.springframework.orm.jpa" level="DEBUG"/>
<logger name="javax.transaction" level="DEBUG"/>
<logger name="javax.jms" level="DEBUG"/>
<logger name="org.hibernate.jpa" level="DEBUG"/>
<logger name="org.hibernate.SQL" level="DEBUG"/>
<logger name="org.apache.activemq" level="DEBUG"/><root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
查看启动日志,可以看到JTA使用了atomikos的实现,管理分布式事务。
多数据源的JTA 项目:
POM.xml
<?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.imooc.example</groupId>
<artifactId>spring-trans-jta-multi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging><name>spring-trans-jta-multi</name>
<description>Demo project for Spring JTA transaction for DB and MQ resources.</description><parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</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><dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies><build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
web层:
package com.immoc.example.springtx.web;
import com.immoc.example.springtx.domain.Customer;
import com.immoc.example.springtx.service.CustomerServiceTxInCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;@RestController
@RequestMapping("/api/customer")
public class CustomerResource {
@Autowired
private CustomerServiceTxInCode customerServiceInCode;@PostMapping("/code")
public Customer createInCode(@RequestBody Customer customer) {
return customerServiceInCode.create(customer);
}
}
service层:
package com.immoc.example.springtx.service;
import com.immoc.example.springtx.dao.CustomerRepository;
import com.immoc.example.springtx.domain.Customer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;@Service
public class CustomerServiceTxInCode {private static final Logger LOG = LoggerFactory.getLogger(CustomerServiceTxInCode.class);
@Autowired
private CustomerRepository customerRepository;
@Autowired
private PlatformTransactionManager transactionManager;
@Autowired
private JmsTemplate jmsTemplate;public Customer create(Customer customer) {
LOG.info("CustomerService In Code create customer:{}", customer.getUsername());
if (customer.getId() != null) {
throw new RuntimeException("用户已经存在");
}
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
def.setTimeout(15);
TransactionStatus status = transactionManager.getTransaction(def);
try {
customer.setUsername("Code:" + customer.getUsername());
customerRepository.save(customer);
jmsTemplate.convertAndSend("customer:msg:reply", customer.getUsername() + " created.");
transactionManager.commit(status);
return customer;
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
}