предисловие
Seata
Это промежуточное ПО распределенных транзакций Alibaba с открытым исходным кодом, которое решает проблемы распределенных транзакций, возникающие в сценарии микросервиса, эффективным и ненавязчивым способом.
На самом деле официальныйGitHub
были даны в различных контекстахSeata
Пример проекта приложения, адрес:https://github.com/seata/seata-samples
.
Есть две основные причины, по которым я хочу переписать его снова:
- В примере кода официального сайта слишком много зависимостей, и непонятно, какие из них за что отвечают.
- Про Seata информации меньше.В процессе сборки автор столкнулся с ямами,запишите
1. Подготовка окружающей среды
Программная среда, рассматриваемая в этой статье, выглядит следующим образом:
- SpringBoot 2.1.6.RELEASE
- Dubbo 2.7.1
- Mybatis 3.5.1
- Seata 0.6.1
- Zookeeper 3.4.10
1. Бизнес-сценарии
Чтобы упростить процесс, нам нужны только два сервиса Order и Inventory. При создании заказа позвоните в службу инвентаризации для вычета запасов.
Используемые таблицы устроены следующим образом:
CREATE TABLE `t_order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_no` varchar(255) DEFAULT NULL,
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT '0',
`amount` double(14,2) DEFAULT '0.00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8;
CREATE TABLE `t_storage` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `commodity_code` (`commodity_code`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
Кроме того, требуется таблица журнала отката:
CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
`ext` varchar(100) DEFAULT NULL,
`context` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=67 DEFAULT CHARSET=utf8;
2. Загрузите и установите Seata.
Открытымhttps://github.com/seata/seata/releases
На данный момент последняя версияv0.6.1
.
После загрузки и распаковки перейдите наseata-server-0.6.1\distribution\bin
можно посмотреть в каталогеseata-server.bat和seata-server.sh
, выберите двойной щелчок для выполнения.
Неудивительно, когда вы видите-Server started ...
Подождите, пока слова начнутся нормально.
3, Maven полагается
Поскольку это проект Dubbo, впервые введем зависимости, связанные с DUBBO.
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.1</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.1</version>
</dependency>
Сервис Dubbo необходимо зарегистрировать в Zookeeper, а также внедрить кураторский клиент.
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.13.0</version>
</dependency>
Наконец, представьте Seata.
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>0.6.1</version>
</dependency>
Конечно, есть и другиеMybatis、mysql-connector
Когда он не станет липким, вы можете ввести его самостоятельно.
Во-вторых, конфигурация проекта
1. свойства приложения
Здесь вам нужно только настроить информацию о подключении к базе данных и информацию, связанную с Dubbo.
server.port=8011
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/seata
spring.datasource.username=root
spring.datasource.password=root
dubbo.application.name=order-service
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=20881
dubbo.consumer.timeout=9999999
dubbo.consumer.check=false
2. Источник данных
Seata реализует ветвление транзакций через прокси-источники данных, поэтому сначала нужно настроить прокси-сервер источника данных, иначе транзакция не будет откатана.
@Bean
public DataSourceProxy dataSourceProxy(DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
Обратите внимание, что здесьDataSourceProxy
Класс находится вio.seata.rm.datasource
внутри сумки.
3, конфигурация СЕАТА
Также необходимо настроить глобальный сканер транзакций. Есть два параметра: один — имя приложения, а другой — группа транзакций.
@Bean
public GlobalTransactionScanner globalTransactionScanner() {
return new GlobalTransactionScanner("springboot-order", "my_test_tx_group");
}
Фактически, здесь выполняется ряд работ по инициализации транзакций Seata.
4. Настройте реестр
Seata
Некоторые элементы конфигурации необходимы при подключении к серверу.registry.conf
Файл может указать, что такое реестр и файл конфигурации.
Здесь есть много вариантов, напримерfile、nacos 、apollo、zk、consul
.
Последние четыре являются зрелыми продуктами реестра конфигурации в отрасли, зачем файл?
Официальное первоначальное намерение состоит в том, чтобы быстро интегрировать тестирование, не полагаясь на сторонний реестр конфигурации.seata
функция, ноfile
Сам тип не имеет функций динамического обнаружения и динамической настройки реестра.
registry.conf
Содержимое файла следующее:
registry {
type = "file"
file {
name = "file.conf"
}
}
config {
# file、nacos 、apollo、zk、consul
type = "file"
file {
name = "file.conf"
}
}
если вы выберетеfile
Тип, заданный атрибутом имениfile.conf
, который указывает информацию о конфигурации клиента или сервера. Например, протокол передачи, адрес сервера и т. д.
service {
#vgroup->rgroup
vgroup_mapping.my_test_tx_group = "default"
#only support single node
default.grouplist = "127.0.0.1:8091"
#degrade current not support
enableDegrade = false
#disable
disable = false
}
3. Бизнес-код
1. Служба инвентаризации
В сервисе инвентаризации получите код товара и общее количество покупок, а затем вычтите его.
<update id="decreaseStorage">
update t_storage set count = count-${count} where commodity_code = #{commodityCode}
</update>
Затем используйте Dubbo, чтобы открыть интерфейс вычета службы инвентаризации.
2. Заказать услугу
В службе заказов запасы вычитаются перед созданием заказа. Наконец, сгенерируйте исключение, затем перейдите в базу данных, чтобы проверить, откатывается ли транзакция.
@GlobalTransactional
public void createOrder(OrderDTO orderDTO) {
System.out.println("开始全局事务。XID="+RootContext.getXID());
StorageDTO storageDTO = new StorageDTO();
storageDTO.setCount(orderDTO.getCount());
storageDTO.setCommodityCode(orderDTO.getCommodityCode());
//1、扣减库存
storageDubboService.decreaseStorage(storageDTO);
//2、创建订单
orderDTO.setId(order_id.incrementAndGet());
orderDTO.setOrderNo(UUID.randomUUID().toString());
Order order = new Order();
BeanUtils.copyProperties(orderDTO,order);
orderMapper.createOrder(order);
throw new RuntimeException("分布式事务异常..."+orderDTO.getOrderNo());
}
Стоит отметить, что на способе запуска операции обслуживания заказа необходимо отметить@GlobalTransactional
. Кроме того, в методе службы инвентаризации эта аннотация не требуется, и транзакция будет распространяться через Dubbo.
В-четвертых, вопросы, требующие внимания
1. Источник данных
Помните, что Seata реализует ветвление транзакций через прокси-источники данных, и вы не должны забывать настраивать прокси-источники данных.
2. Первичный ключ увеличивается
В базе данных поле идентификатора первичного ключа в таблице самоувеличивается. Если ваше поле не является самоинкрементным, то в Mybatisinsert SQL
, завершите имена столбцов.
Например, мы можем написать SQL следующим образом:
INSERT INTO table_name VALUES (值1, 值2,....)
Тогда это должно быть записано так:
INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)
3. Проблема сериализации
В форме заказа,amount
Тип поляdouble
. существуетseata0.6.1
версия, метод сериализации по умолчаниюfastjson
, но он будет сериализовать поле какbigdecimal
типа, что приведет к несоответствию следующих типов.
Но в последующемseata0.7.0
В версии (еще не выпущенной) метод сериализации по умолчанию был изменен наjackson
.
Но не волнуйтесь, эта проблема обычно не возникает. Автор обнаружил эту проблему из-за неправильного пакета.
4. Код этой статьи
Пример кода для этой статьи находится по адресу:https://github.com/taoxun/springboot-dubbo-zookeeper-seata
.
5. Другие
Приветствуем любые вопросы, чтобы общаться вовремя ~