0. Предварительное знание
0.1 Некоторые основные концепции транзакций
- В прошлой статье я рассказал о некоторых концепциях транзакций, некоторых определениях интерфейса в Spring и реализации транзакций с одним источником данных.nuggets.capable/post/684490…
Модель 0.2 X/OPEN DTP
- Полное название: Эталонная модель распределенной обработки транзакций X/Open, которая представляет собой модель распределенной обработки транзакций.
- Три компонента, определяемые DTP: AP (прикладная программа), RM (менеджер ресурсов, диспетчер ресурсов), TM (менеджер транзакций, диспетчер транзакций).
- AP: программа, использующая модель DTP.
- RM: диспетчер ресурсов (может пониматься как система базы данных, система очереди сообщений)
- ТМ: менеджер транзакций
0,3 X/OPEN XA Спецификация
- вики:Это.Wikipedia.org/wiki/X/open…
- Спецификация XA должна предоставить набор общих спецификаций интерфейса вызова, чтобы TM мог вызывать разные RM, а также позволял различным RM реализовывать свои собственные RM в соответствии со спецификацией XA.
- XA использует двухфазную фиксацию (2PC), чтобы гарантировать одновременную фиксацию или откат любой конкретной транзакции всеми ресурсами.
Механизм хранения MySQL InnoDB поддерживает спецификацию XA.
0.4 Двухфазная фиксация 2PC
- wiki: en.wikipedia.org/wiki/Двухэтапная фиксация
- Двухэтапная фиксация, как следует из названия, делит выполнение транзакции на две фазы.Первая фаза — это запрос на отправку или фаза голосования.Менеджер транзакций сообщает менеджеру ресурсов задачу, которую нужно выполнить, и спрашивает, может ли она быть выполнена. ? Несколько менеджеров ресурсов отвечают OK и не OK соответственно; второй этап — это этап выполнения: менеджер транзакций получает ответы от каждого менеджера ресурсов, если все в порядке, то сделайте это! Если это не нормально, не делайте этого.
- Подробности смотрите в вики
0.5 JTA API транзакций Java
- Полное название: API транзакций Java, предложенный спецификацией JSR 907 для обеспечения завершения интерфейсов программирования распределенных транзакций, охватывающих несколько ресурсов XA, включая интерфейсы пользовательских операций, JTATransactionManager и XAResource.
- Это реализация спецификации XA в Java.
- В следующем примере мы будем использовать диспетчер транзакций JTA для управления транзакциями двух операций базы данных.
1. Управление транзакциями с несколькими источниками данных
1.1 Описание окружающей среды
1.1.1 Описание компонентов
- DataSource: Alibaba Druid
- Database: MySQL 5.7
- SpringBoot: 2.2.2.RELEASE
- ORM: MyBatis
- JTA: Atomikos
- GitHub: GitHub.com/IMArtist/Вдруг…
1.1.2 Ключевые зависимости проекта
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!--atomikos transaction management-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.21</version>
</dependency>
1.1.3 Несколько источников данных
- Источник данных использует разные таблицы из двух баз данных.
- Все используют Druid в качестве пула соединений, а затем используют Atomikos для управления
1.1.4 Инструменты для JTA
- Официальный, который может использовать SpringBoot, говорит, что один из них — Atomikos, а другой — Bitronix, Кроме того, его также можно использовать на веб-серверах, поддерживающих JTA. (Не поддерживается Tomcat)
- Примечание из документации SpringBoot: при обнаружении среды JTA для управления транзакциями используется Spring JtaTransactionManager.JMS,DataSource,JPAОбновлен для поддержки транзакций XA. Можно участвовать в распределенных транзакциях, используя стандартное использование Spring (например, @Transactional). Если вы находитесь в среде JTA и по-прежнему хотите использовать локальные транзакции, вы можете отключить автоматическую настройку JTA, установив для свойства spring.jta.enabled значение false.
1.2 Описание бизнеса экземпляра
- Простая логика, две таблицы находятся в двух разных библиотеках, а затем сервисный метод работает с данными двух библиотек.
1.3 Конфигурация нескольких источников данных
1.3.1 Файл конфигурации
- Первая таблица: таблица счетов
- Таблица второй главы: это таблица заказов
spring:
application:
name: two-data-source
datasource:
account:
url: jdbc:mysql://127.0.0.1:3306/transaction_account?useSSL=false&characterEncoding=UTF-8
username: root
password: xxxxx
order:
url: jdbc:mysql://127.0.0.1:3306/transaction_order?useSSL=false&characterEncoding=UTF-8
username: root
password: xxxxx
#logging:
# level:
# root: DEBUG
1.3.2 Регистрация компонента
- В основном включают следующие шаги
- Зарегистрируйте bean-компоненты, соответствующие DataSource, SqlSessionFactory и SqlSessionTemplate соответственно.
- Затем укажите расположение маппера таблицы и установите шаблон на тот, который вы зарегистрировали.
- Сходства библиотеки заказов здесь опущены.
- Обратите внимание:
- DataSource не может напрямую использовать DruidDataSource, предоставленный Druid, вам нужно использовать atomikos для переноса DruidXADataSource, предоставленного Druid, для поддержки спецификации XA.
- Если вы не хотите использовать Druid, рассмотрите возможность использования MysqlXADataSource (я не пробовал)
- Соответствующее отношение зарегистрированных бинов должно быть правильным
@Configuration
@MapperScan(basePackages = {"io.ilss.transaction.twodatasource.dao.account"}, sqlSessionTemplateRef = "accountSqlSessionTemplate")
public class AccountConfiguration {
@Value("${spring.datasource.account.url}")
private String url;
@Value("${spring.datasource.account.username}")
private String username;
@Value("${spring.datasource.account.password}")
private String password;
@Bean(name = "accountDataSource")
public DataSource accountDataSource() {
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
DruidXADataSource druidXADataSource = new DruidXADataSource();
druidXADataSource.setUrl(url);
druidXADataSource.setUsername(username);
druidXADataSource.setPassword(password);
druidXADataSource.setName("druidDataSource-account");
atomikosDataSourceBean.setXaDataSource(druidXADataSource);
atomikosDataSourceBean.setUniqueResourceName("accountResource");
return atomikosDataSourceBean;
}
@Bean(name = "accountSqlSessionFactory")
public SqlSessionFactory accountSqlSessionFactory(DataSource accountDataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(accountDataSource);
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mappers/account/*.xml"));
return factoryBean.getObject();
}
@Bean(name = "accountSqlSessionTemplate")
@Primary
public SqlSessionTemplate accountSqlSessionTemplate(@Qualifier("accountSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
- После правильной настройки будет отображаться следующая информация журнала.
c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'orderResource': poolSize equals default - this may cause performance problems!
com.alibaba.druid.pool.DruidDataSource : {dataSource-1,druidDataSource-order} inited
c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'accountResource': poolSize equals default - this may cause performance problems!
com.alibaba.druid.pool.DruidDataSource : {dataSource-2,druidDataSource-account} inited
c.a.icatch.provider.imp.AssemblerImp : Loaded jar:file:/Users/feng/.m2/repository/com/atomikos/transactions/4.0.6/transactions-4.0.6.jar!/transactions-defaults.properties
c.a.icatch.provider.imp.AssemblerImp : Thanks for using Atomikos! Evaluate http://www.atomikos.com/Main/ExtremeTransactions for advanced features and professional support...略
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.default_max_wait_time_on_shutdown = 9223372036854775807
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.allow_subtransactions = true
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.recovery_delay = 10000
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.automatic_resource_registration = true
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.oltp_max_retries = 5
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.client_demarcation = false
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.threaded_2pc = false
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.serial_jta_transactions = true
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.log_base_dir = /Users/feng/Projects/java/transaction-example/transaction-logs
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.rmi_export_class = none
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.max_actives = 50
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.checkpoint_interval = 500
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.enable_logging = true
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.log_base_name = tmlog
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.max_timeout = 300000
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.trust_client_tm = false
c.a.icatch.provider.imp.AssemblerImp : USING: java.naming.factory.initial = com.sun.jndi.rmi.registry.RegistryContextFactory
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.tm_unique_name = 10.11.11.11.tm
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.forget_orphaned_log_entries_delay = 86400000
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.oltp_retry_interval = 10000
c.a.icatch.provider.imp.AssemblerImp : USING: java.naming.provider.url = rmi://localhost:1099
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.force_shutdown_on_vm_exit = false
c.a.icatch.provider.imp.AssemblerImp : USING: com.atomikos.icatch.default_jta_timeout = 10000
c.a.icatch.provider.imp.AssemblerImp : Using default (local) logging and recovery...
c.a.d.xa.XATransactionalResource : orderResource: refreshed XAResource
c.a.d.xa.XATransactionalResource : accountResource: refreshed XAResource
-
Сначала инициализируйте два источника данных Druid, обернутых Atomikos,
-
Затем установите параметры атомикоса, которые все по умолчанию
-
Последнее обновление XAResource
-
На этом этапе, после завершения настройки, некоторым людям может быть любопытно, что нет кода JTA, потому что стартер, представленный, когда SpringBoot использует JTA, не
1.4 Примеры транзакций
- Просто смоделируйте формирование заказа и процесс оплаты, спишите деньги со счета, а затем добавьте новый заказ.
- Способ программирования точно такой же, как и способ транзакций Spring, ничем не отличается.
1.4.1 Код реализации
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderInfoDAO orderInfoDAO;
@Autowired
private AccountDAO accountDAO;
@Autowired
PlatformTransactionManager transactionManager;
@Override
@Transactional
public String createOrder(OrderInfoDO orderInfoDO) {
AccountDO accountDO = accountDAO.selectByPrimaryKey(orderInfoDO.getAccountId());
if (null == accountDO) {
log.error("createOrder user is not present, accountId: {}", orderInfoDO.getAccountId());
return "用户不存在!";
}
// 用户费用扣除
accountDO.setBalance(accountDO.getBalance().subtract(orderInfoDO.getAmount()));
accountDAO.updateByPrimaryKey(accountDO);
orderInfoDAO.insertSelective(orderInfoDO);
return "成功";
}
@Override
public String createOrderCode(OrderInfoDO orderInfoDO) {
TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
// 获取事务 开始业务执行
TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);
try {
AccountDO accountDO = accountDAO.selectByPrimaryKey(orderInfoDO.getAccountId());
if (null == accountDO) {
log.error("createOrder user is not present, accountId: {}", orderInfoDO.getAccountId());
return "用户不存在!";
}
// 用户费用扣除
accountDO.setBalance(accountDO.getBalance().subtract(orderInfoDO.getAmount()));
accountDAO.updateByPrimaryKey(accountDO);
orderInfoDAO.insertSelective(orderInfoDO);
error("createOrderCode error");
transactionManager.commit(transaction);
return "成功";
} catch (Exception e) {
log.error("create order failed, accountId: {}, errMsg: {}", orderInfoDO.getAccountId(), e.getMessage());
transactionManager.rollback(transaction);
}
return "失败";
}
public static void error(String msg) {
throw new RuntimeException(msg);
}
}
1.4.2 Процесс
- Параметры журнала установлены на:
logging.level.root=DEBUG
Если вы не установите его, вы вряд ли увидите журнал транзакций.
- вызов журнала успеха:http://localhost:8080/api/order/create
o.s.web.servlet.DispatcherServlet : GET "/api/order/create", parameters={}
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to io.ilss.transaction.twodatasource.web.OrderController#create()
o.s.t.jta.JtaTransactionManager : Creating new transaction with name [io.ilss.transaction.twodatasource.service.impl.OrderServiceImpl.createOrder]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
c.a.i.i.CompositeTransactionManagerImp : createCompositeTransaction ( 10000 ): created new ROOT transaction with id 10.11.11.11.tm157866358813800001
org.mybatis.spring.SqlSessionUtils : Creating a new SqlSession
org.mybatis.spring.SqlSessionUtils : Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1502ae81]
o.s.jdbc.datasource.DataSourceUtils : Fetching JDBC Connection from DataSource
c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'accountResource': getConnection()...
c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'accountResource': init...
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@73c7f762: calling getAutoCommit...
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@73c7f762: calling toString...
o.m.s.t.SpringManagedTransaction : JDBC Connection [com.mysql.jdbc.JDBC4Connection@73c7f762] will be managed by Spring
i.i.t.t.d.a.A.selectByPrimaryKey : ==> Preparing: select id, nickname, username, `password`, balance, create_time, update_time from account where id = ?
c.a.icatch.imp.CompositeTransactionImp : addParticipant ( XAResourceTransaction: 31302E31312E31312E31312E746D313537383636333538383133383030303031:31302E31312E31312E31312E746D31 ) for transaction 10.11.11.11.tm157866358813800001
c.a.datasource.xa.XAResourceTransaction : XAResource.start ( 31302E31312E31312E31312E746D313537383636333538383133383030303031:31302E31312E31312E31312E746D31 , XAResource.TMNOFLAGS ) on resource accountResource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@51af9ae0
c.a.icatch.imp.CompositeTransactionImp : registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@853ac8fa ) for transaction 10.11.11.11.tm157866358813800001
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@73c7f762: calling prepareStatement(select....略
i.i.t.t.d.a.A.selectByPrimaryKey : ==> Parameters: 1(Long)
i.i.t.t.d.a.A.selectByPrimaryKey : <== Total: 1
org.mybatis.spring.SqlSessionUtils : Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1502ae81]
org.mybatis.spring.SqlSessionUtils : Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1502ae81] from current transaction
i.i.t.t.d.a.A.updateByPrimaryKey : ==> Preparing: update account set nickname = ?, username = ?, `password` = ?, balance = ?, create_time = ?, update_time = ? where id = ?
c.a.icatch.imp.CompositeTransactionImp : registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@853ac8fa ) for transaction 10.11.11.11.tm157866358813800001
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@73c7f762: calling prepareStatement(update account
i.i.t.t.d.a.A.updateByPrimaryKey : ==> Parameters: 小一(String), xiaoyi(String), 123456(String), 600.00(BigDecimal), 2020-01-09T17:04:28(LocalDateTime), 2020-01-10T16:00:51(LocalDateTime), 1(Long)
i.i.t.t.d.a.A.updateByPrimaryKey : <== Updates: 1
org.mybatis.spring.SqlSessionUtils : Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1502ae81]
org.mybatis.spring.SqlSessionUtils : Creating a new SqlSession
org.mybatis.spring.SqlSessionUtils : Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@20a0ef33]
o.s.jdbc.datasource.DataSourceUtils : Fetching JDBC Connection from DataSource
c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'orderResource': getConnection()...
c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'orderResource': init...
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@22a176f4: calling getAutoCommit...
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@22a176f4: calling toString...
o.m.s.t.SpringManagedTransaction : JDBC Connection [com.mysql.jdbc.JDBC4Connection@22a176f4] will be managed by Spring
i.i.t.t.d.o.O.insertSelective : ==> Preparing: insert into order_info ( account_id, completed, order_state, detail, amount, create_time, update_time ) values ( ?, ?, ?, ?, ?, ?, ? )
c.a.icatch.imp.CompositeTransactionImp : addParticipant ( XAResourceTransaction: 31302E31312E31312E31312E746D313537383636333538383133383030303031:31302E31312E31312E31312E746D32 ) for transaction 10.11.11.11.tm157866358813800001
c.a.datasource.xa.XAResourceTransaction : XAResource.start ( 31302E31312E31312E31312E746D313537383636333538383133383030303031:31302E31312E31312E31312E746D32 , XAResource.TMNOFLAGS ) on resource orderResource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@473dd4ea
c.a.icatch.imp.CompositeTransactionImp : registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@853ac8fa ) for transaction 10.11.11.11.tm157866358813800001
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@22a176f4: calling prepareStatement(insert into order_info
i.i.t.t.d.o.O.insertSelective : ==> Parameters: 1(Long), 0(Integer), 1(Integer), 买衣服(String), 100(BigDecimal), 2020-01-10T21:39:48.134(LocalDateTime), 2020-01-10T21:39:48.134(LocalDateTime)
i.i.t.t.d.o.O.insertSelective : <== Updates: 1
org.mybatis.spring.SqlSessionUtils : Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@20a0ef33]
org.mybatis.spring.SqlSessionUtils : Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1502ae81]
org.mybatis.spring.SqlSessionUtils : Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@20a0ef33]
org.mybatis.spring.SqlSessionUtils : Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1502ae81]
org.mybatis.spring.SqlSessionUtils : Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1502ae81]
org.mybatis.spring.SqlSessionUtils : Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@20a0ef33]
org.mybatis.spring.SqlSessionUtils : Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@20a0ef33]
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@73c7f762: close()...
c.a.datasource.xa.XAResourceTransaction : XAResource.end ( 31302E31312E31312E31312E746D313537383636333538383133383030303031:31302E31312E31312E31312E746D31 , XAResource.TMSUCCESS ) on resource accountResource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@51af9ae0
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@22a176f4: close()...
c.a.datasource.xa.XAResourceTransaction : XAResource.end ( 31302E31312E31312E31312E746D313537383636333538383133383030303031:31302E31312E31312E31312E746D32 , XAResource.TMSUCCESS ) on resource orderResource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@473dd4ea
o.s.t.jta.JtaTransactionManager : Initiating transaction commit
c.a.icatch.imp.CompositeTransactionImp : commit() done (by application) of transaction 10.11.11.11.tm157866358813800001
c.a.datasource.xa.XAResourceTransaction : XAResource.prepare ( 31302E31312E31312E31312E746D313537383636333538383133383030303031:31302E31312E31312E31312E746D31 ) returning OK on resource accountResource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@51af9ae0
c.a.datasource.xa.XAResourceTransaction : XAResource.prepare ( 31302E31312E31312E31312E746D313537383636333538383133383030303031:31302E31312E31312E31312E746D32 ) returning OK on resource orderResource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@473dd4ea
c.a.datasource.xa.XAResourceTransaction : XAResource.commit ( 31302E31312E31312E31312E746D313537383636333538383133383030303031:31302E31312E31312E31312E746D31 , false ) on resource accountResource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@51af9ae0
c.a.datasource.xa.XAResourceTransaction : XAResource.commit ( 31302E31312E31312E31312E746D313537383636333538383133383030303031:31302E31312E31312E31312E746D32 , false ) on resource orderResource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@473dd4ea
m.m.a.RequestResponseBodyMethodProcessor : Using 'text/html', given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8] and supported [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json]
m.m.a.RequestResponseBodyMethodProcessor : Writing ["成功"]
o.s.web.servlet.DispatcherServlet : Completed 200 OK
- процесс:
- Приходит запрос, вызывается через OrderController, и JtaTransactionManager создает новую транзакцию.
- Atomikos начинает получать подключения к библиотеке учетных записей
- Запрос не обрабатывается, и последующие обновления, XAResource регистрирует транзакцию и генерирует XID
- Затем для обработки нового заказа тот же Атомикос регистрирует транзакцию и генерирует XID.
- Наконец подготовьте, а затем отправьте.
- Успешный запрос возвращает 200.
- вызов журнала сбоев:http://localhost:8080/api/order/create/code
o.s.web.servlet.DispatcherServlet : GET "/api/order/create/code", parameters={}
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to io.ilss.transaction.twodatasource.web.OrderController#createCode()
o.s.t.jta.JtaTransactionManager : Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
c.a.i.i.CompositeTransactionManagerImp : createCompositeTransaction ( 10000 ): created new ROOT transaction with id 10.11.11.11.tm157866420875900002
org.mybatis.spring.SqlSessionUtils : Creating a new SqlSession
org.mybatis.spring.SqlSessionUtils : Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@48f4fdff]
o.s.jdbc.datasource.DataSourceUtils : Fetching JDBC Connection from DataSource
c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'accountResource': getConnection()...
c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'accountResource': init...
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@73c7f762: calling getAutoCommit...
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@73c7f762: calling toString...
o.m.s.t.SpringManagedTransaction : JDBC Connection [com.mysql.jdbc.JDBC4Connection@73c7f762] will be managed by Spring
i.i.t.t.d.a.A.selectByPrimaryKey : ==> Preparing: select id, nickname, username, `password`, balance, create_time, update_time from account where id = ?
c.a.icatch.imp.CompositeTransactionImp : addParticipant ( XAResourceTransaction: 31302E31312E31312E31312E746D313537383636343230383735393030303032:31302E31312E31312E31312E746D33 ) for transaction 10.11.11.11.tm157866420875900002
c.a.datasource.xa.XAResourceTransaction : XAResource.start ( 31302E31312E31312E31312E746D313537383636343230383735393030303032:31302E31312E31312E31312E746D33 , XAResource.TMNOFLAGS ) on resource accountResource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@51af9ae0
c.a.icatch.imp.CompositeTransactionImp : registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@6bb297a ) for transaction 10.11.11.11.tm157866420875900002
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@73c7f762: calling prepareStatement(select....略
i.i.t.t.d.a.A.selectByPrimaryKey : ==> Parameters: 1(Long)
i.i.t.t.d.a.A.selectByPrimaryKey : <== Total: 1
org.mybatis.spring.SqlSessionUtils : Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@48f4fdff]
org.mybatis.spring.SqlSessionUtils : Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@48f4fdff] from current transaction
i.i.t.t.d.a.A.updateByPrimaryKey : ==> Preparing: update account set nickname = ?, username = ?, `password` = ?, balance = ?, create_time = ?, update_time = ? where id = ?
c.a.icatch.imp.CompositeTransactionImp : registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@6bb297a ) for transaction 10.11.11.11.tm157866420875900002
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@73c7f762: calling prepareStatement(update account... 略
i.i.t.t.d.a.A.updateByPrimaryKey : ==> Parameters: 小一(String), xiaoyi(String), 123456(String), 500.00(BigDecimal), 2020-01-09T17:04:28(LocalDateTime), 2020-01-10T16:00:51(LocalDateTime), 1(Long)
i.i.t.t.d.a.A.updateByPrimaryKey : <== Updates: 1
org.mybatis.spring.SqlSessionUtils : Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@48f4fdff]
org.mybatis.spring.SqlSessionUtils : Creating a new SqlSession
org.mybatis.spring.SqlSessionUtils : Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1901cd8f]
o.s.jdbc.datasource.DataSourceUtils : Fetching JDBC Connection from DataSource
c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'orderResource': getConnection()...
c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'orderResource': init...
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@22a176f4: calling getAutoCommit...
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@22a176f4: calling toString...
o.m.s.t.SpringManagedTransaction : JDBC Connection [com.mysql.jdbc.JDBC4Connection@22a176f4] will be managed by Spring
i.i.t.t.d.o.O.insertSelective : ==> Preparing: insert into order_info ( account_id, completed, order_state, detail, amount, create_time, update_time ) values ( ?, ?, ?, ?, ?, ?, ? )
c.a.icatch.imp.CompositeTransactionImp : addParticipant ( XAResourceTransaction: 31302E31312E31312E31312E746D313537383636343230383735393030303032:31302E31312E31312E31312E746D34 ) for transaction 10.11.11.11.tm157866420875900002
c.a.datasource.xa.XAResourceTransaction : XAResource.start ( 31302E31312E31312E31312E746D313537383636343230383735393030303032:31302E31312E31312E31312E746D34 , XAResource.TMNOFLAGS ) on resource orderResource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@473dd4ea
c.a.icatch.imp.CompositeTransactionImp : registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@6bb297a ) for transaction 10.11.11.11.tm157866420875900002
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@22a176f4: calling prepareStatement(insert into order_info...略
i.i.t.t.d.o.O.insertSelective : ==> Parameters: 1(Long), 0(Integer), 1(Integer), 买衣服(String), 100(BigDecimal), 2020-01-10T21:50:08.759(LocalDateTime), 2020-01-10T21:50:08.759(LocalDateTime)
i.i.t.t.d.o.O.insertSelective : <== Updates: 1
org.mybatis.spring.SqlSessionUtils : Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1901cd8f]
i.i.t.t.service.impl.OrderServiceImpl : create order failed, accountId: 1, errMsg: createOrderCode error
org.mybatis.spring.SqlSessionUtils : Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@48f4fdff]
org.mybatis.spring.SqlSessionUtils : Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@48f4fdff]
org.mybatis.spring.SqlSessionUtils : Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1901cd8f]
org.mybatis.spring.SqlSessionUtils : Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1901cd8f]
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@73c7f762: close()...
c.a.datasource.xa.XAResourceTransaction : XAResource.end ( 31302E31312E31312E31312E746D313537383636343230383735393030303032:31302E31312E31312E31312E746D33 , XAResource.TMSUCCESS ) on resource accountResource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@51af9ae0
c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.JDBC4Connection@22a176f4: close()...
c.a.datasource.xa.XAResourceTransaction : XAResource.end ( 31302E31312E31312E31312E746D313537383636343230383735393030303032:31302E31312E31312E31312E746D34 , XAResource.TMSUCCESS ) on resource orderResource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@473dd4ea
o.s.t.jta.JtaTransactionManager : Initiating transaction rollback
c.a.datasource.xa.XAResourceTransaction : XAResource.rollback ( 31302E31312E31312E31312E746D313537383636343230383735393030303032:31302E31312E31312E31312E746D33 ) on resource accountResource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@51af9ae0
c.a.datasource.xa.XAResourceTransaction : XAResource.rollback ( 31302E31312E31312E31312E746D313537383636343230383735393030303032:31302E31312E31312E31312E746D34 ) on resource orderResource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@473dd4ea
c.a.icatch.imp.CompositeTransactionImp : rollback() done of transaction 10.11.11.11.tm157866420875900002
c.a.icatch.imp.CompositeTransactionImp : rollback() done of transaction 10.11.11.11.tm157866420875900002
m.m.a.RequestResponseBodyMethodProcessor : Using 'text/html', given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8] and supported [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json]
m.m.a.RequestResponseBodyMethodProcessor : Writing ["失败"]
o.s.web.servlet.DispatcherServlet : Completed 200 OK
- Исключение выбрасывается перед окончательным выполнением транзакции
- процесс:
- Приходит запрос, вызывается через OrderController, и JtaTransactionManager создает новую транзакцию.
- Atomikos начинает получать подключения к библиотеке учетных записей
- Запрос не обрабатывается, и последующие обновления, XAResource регистрирует транзакцию и генерирует XID
- Затем для обработки нового заказа тот же Атомикос регистрирует транзакцию и генерирует XID.
- Затем сообщается об ошибке создать заказ не удалось, accountId: 1, errMsg: ошибка createOrderCode
- Затем два ресурса начинают откат и, наконец, возвращают «сбой».
- Ставьте палец вверх, если считаете, что сможете 👍 Спасибо!
обо мне
- Координатор Ханчжоу, специализирующийся в области компьютерных наук и технологий в общеобразовательных колледжах и университетах.
- Окончил 20 лет, в основном занимается внутренней разработкой стека технологий Java.
- GitHub: github.com/imyiren
- Blog : imyi.ren