Оригинальный адрес:Учебник по началу работы с ShardingSphere-JDBC
Введение
Последняя статья представила базу данныхПодбиблиотека и подтаблицаОсновная концепция и процесс развития базы данных, а также громоздкие проблемы, вызванные подбазой данных и подтаблицей. В этой статье будут представлены и объяснены решения проблем, описанных в предыдущей статье.
Главный герой этой статьиShardingSphere-JDBC.
2. Основное введение
Apache ShardingSphereЭто экосистема, состоящая из набора распределенных баз данных с открытым исходным кодом и состоящая из трех продуктов: JDBC, Proxy и Sidecar (в разработке), которые можно развертывать независимо и использовать в сочетании с гибридным развертыванием. Все они обеспечивают стандартизированное горизонтальное масштабирование данных, распределенные транзакции и распределенное управление и могут применяться к различным сценариям приложений, таким как изоморфизм Java, гетерогенные языки и облачные среды.
ShardingSphere-JDBCдаApache ShardingSphereПодмодуль в Java, позиционируемый как облегченная среда Java, предоставляет дополнительные услуги на уровне JDBC Java. Он использует клиент для прямого подключения к базе данных и предоставляет услуги в виде пакетов jar без дополнительного развертывания и зависимостей.Его можно понимать как расширенную версию драйвера JDBC, которая полностью совместима с JDBC и различными ORM-фреймворками.
Его особенности:
- Работает с любой инфраструктурой ORM на основе JDBC, такой как: JPA, Hibernate, Mybatis, Spring JDBC Template или с использованием JDBC напрямую.
- Поддержка любого стороннего пула подключений к базе данных, например: DBCP, C3P0, BoneCP, Druid, HikariCP и т. д.
- Поддерживает любую базу данных, реализующую спецификацию JDBC, в настоящее время поддерживает MySQL, Oracle, SQLServer, PostgreSQL и любую базу данных, соответствующую стандарту SQL92.
ShardingSphere-JDBCЕго основные функции — разделение данных и разделение чтения и записи. пройти черезShardingSphere-JDBC, приложение может прозрачно использовать JDBC для доступа к нескольким источникам данных, которые были разделены на базы данных и таблицы, отделенные от чтения и записи, не заботясь о количестве источников данных и о том, как данные распределяются.
2.1 Список функций
разделение данных
- Подбиблиотека и подтаблица
- разделение чтения-записи
- Настройка стратегии шардинга
- Децентрализованный распределенный первичный ключ
Распределенная транзакция
- Стандартизированный интерфейс транзакций
- Строго согласованные транзакции XA
- гибкие дела
Управление базой данных
- Распределенное управление
- Эластичное масштабирование
- Визуальное отслеживание ссылок
- шифрование данных
2.2 Основные концепции
Логическая таблица:Общий термин для таблиц с одинаковой логикой и структурой данных для горизонтально разделенной базы данных (таблицы). Пример: данные заказа разделены на 10 таблиц в соответствии с мантиссом первичного ключа, а именно от t_order_0 до t_order_9, и их логическое имя таблицы — t_order.
Реальная таблица:Физические таблицы, которые фактически существуют в сегментированной базе данных. Это от t_order_0 до t_order_9 в предыдущем примере.
узел данных:Наименьшая единица фрагментации данных. Он состоит из имени источника данных и таблицы данных, например: ds_0.t_order_0.
Таблица привязки:Относится к основной таблице и подтаблице с согласованными правилами сегментирования. Например, таблица t_order и таблица t_order_item сегментированы в соответствии с order_id, поэтому эти две таблицы связаны друг с другом. Запрос ассоциации с несколькими таблицами между таблицами привязки не будет отображаться декартовой ассоциацией продуктов, и эффективность запроса ассоциации будет значительно повышена.
Таблица трансляции:Ссылается на таблицу, которая существует во всех сегментированных источниках данных, а структура таблицы и данные в таблице абсолютно одинаковы во всех базах данных. Он подходит для сценариев, в которых объем данных невелик и требуются связанные запросы с таблицами с большими данными, такими как таблицы словаря.
Один стол:Это означает, что во всех сегментированных источниках данных есть только одна таблица. Он подходит для сценариев, когда объем данных невелик и не требует операций фрагментации.
Ключ осколка:Поле базы данных, используемое для сегментирования, является ключевым полем для горизонтального разделения базы данных (таблицы). Пример: если мантисса первичного ключа заказа в таблице заказов сегментирована по модулю, первичный ключ заказа является полем сегментирования. Если в SQL нет поля фрагментации, будет выполняться полная маршрутизация, и производительность будет низкой.
Алгоритм шардинга:Данные сегментируются с помощью алгоритма сегментирования для поддержки=
,>=
,<=
,>
,<
,BETWEEN
а такжеIN
Фрагментация. Алгоритм сегментирования должен быть реализован самими разработчиками приложений, и достижимая гибкость очень высока.
Стратегия разделения:Включая ключ сегментации и алгоритм сегментации, которые извлекаются независимо из-за независимости алгоритма сегментации. Что реально можно использовать для операций шардирования, так это ключ шардирования + алгоритм шардирования, то есть стратегию шардирования.
существуетShardingSphereВ , также определены многие понятия, и только некоторые из понятий перечислены выше, которые в основном используются для понятий, упомянутых в фактической конфигурации боевых учений ниже. Чтобы узнать больше, ознакомьтесь со ссылками, приведенными в конце статьи.
3. Практические занятия
В качестве примера возьмем горизонтальную подбиблиотеку, как простейший случай реального боя.
3.1 Создать базу данных и таблицу
CREATE TABLE `t_order_1` (
`order_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT '用户 id',
`total_price` DECIMAL(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单价格',
`state` TINYINT(4) NOT NULL DEFAULT '0' COMMENT '订单状态',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`order_id`),
INDEX `user_id` (`user_id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
CREATE TABLE `t_order_2` (
`order_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT '用户 id',
`total_price` DECIMAL(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单价格',
`state` TINYINT(4) NOT NULL DEFAULT '0' COMMENT '订单状态',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`order_id`),
INDEX `user_id` (`user_id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
Дополнение: t_order_1 и t_order_2 — настоящие таблицы, в последнемSQL
При записи мы используем t_order как логическую таблицу для записи.
3.2 Знакомство с зависимостями
Изменить элементpom.xmlдокумент:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- jdbc 驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!-- sharding-jdbc -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
3.3 Настройка правил фрагментации
Исправлятьapplication.propertiesдокумент
spring.application.name=sharding-jdbc
mybatis.config-location=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
# shardingsphere 配置开关,如果使用 java api 配置方式,需要修改为 false
spring.shardingsphere.enabled=true
# 定义数据源
spring.shardingsphere.datasource.names=m1
# 下边用到的 m1 就是上边定义的
spring.shardingsphere.datasource.m1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m1.jdbc-url=jdbc:mysql://localhost:3306/db_order?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&rewriteBatchedStatements=true&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=tiger
# 下边 t_order 是逻辑表,真实查询对应真实的 t_order_1 和 t_order_2
# 指定 t_order 表的主键生成策略为 SNOWFLAKE,order_id 就是 t_order 表的主键
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE
# 指定 t_order 表的数据分布情况,配置数据节点
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=m1.t_order_$->{1..2}
# 指定 t_order 表的分片策略,分片策略包括分片键和分片算法
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
# order_id 值为奇数插入到 t_order_2 表,为偶数插入到 t_order_1 表
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id%2+1}
# 打开 sql 输出日志
spring.shardingsphere.props.sql.show = true
logging.level.root=info
logging.level.org.springframework.web=info
logging.level.com.light.sharding.jdbc=debug
3.4 Реализация уровня сохраняемости
Определите интерфейс картографа:
@Mapper
public interface OrderMapper {
/**
* 插入
* @param order
*/
void insert(Order order);
/**
* 批量查询
* @param idList
* @return
*/
List<Order> selectListByIds(@Param("idList") List<Long> idList);
}
Файл сопоставления маппера:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.light.sharding.jdbc.mapper.OrderMapper">
<insert id="insert" parameterType="com.light.sharding.jdbc.model.Order">
INSERT INTO t_order(user_id, total_price, state, create_time, update_time)
VALUES(#{userId}, #{totalPrice}, #{state}, #{createTime}, #{updateTime})
</insert>
<select id="selectListByIds" resultType="com.light.sharding.jdbc.model.Order">
SELECT order_id, user_id, total_price, state FROM t_order WHERE order_id IN
<foreach collection="idList" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
</mapper>
Уведомление: SQL
написано с использованиемлогическая таблица.
3.5 Модульное тестирование
Протестируйте операцию вставки:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ShardingJdbcApplication.class)
public class OrderMapperTest {
@Autowired
private OrderMapper orderMapper;
@Test
public void testInsert() {
for (int i = 0 ; i < 10; i++){
Order order = new Order();
order.setUserId(1L);
order.setState(0);
order.setTotalPrice(new BigDecimal((i + 1) * 5));
order.setCreateTime(LocalDateTime.now());
order.setUpdateTime(order.getCreateTime());
this.orderMapper.insert(order);
}
}
}
Выполните вышеуказанный метод тестирования, окончательный результат выглядит следующим образом:
Как видно из рисунка выше, вставленный результат данных соответствует правилам конфигурации.
Операция тестового запроса:
@Test
public void testSelectList() {
List<Long> idList = Arrays.asList(593141944457101312L, 593141944922669057L);
List<Order> orderList = this.orderMapper.selectListByIds(idList);
System.out.println(orderList);
}
мы начинаем сt_order_1а такжеt_order_2Возьмите кусок данных для проверки запроса, и результат выполнения будет следующим:
Согласно журналу,ShardingSphere-JDBCотправить на оба столаSQLсделать запрос.
3.6 конфигурация Java-API
Этот раздел используется как дополнение к методу конфигурации.Если вам не нравится использовать описанный выше метод с файлом конфигурации, вы можете использовать следующую конфигурацию:
Создайте класс конфигурации:
@Configuration
public class ShardingJdbcConfig {
// sharding‐Jdbc 数据源
@Bean
public DataSource getShardingDataSource() throws SQLException {
// 定义数据源,此处我们定义数据源名称为 m2
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/db_order?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&rewriteBatchedStatements=true&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true");
dataSource.setUsername("root");
dataSource.setPassword("tiger");
Map<String, DataSource> dataSourceMap = new HashMap<>();
dataSourceMap.put("m2", dataSource);
// 分片规则
ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
// 其他配置
Properties properties = new Properties();
properties.put("sql.show","true");
return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, properties);
}
// 分片规则
private TableRuleConfiguration getOrderTableRuleConfiguration() {
// 指定 t_order 表的数据分布情况,配置数据节点
TableRuleConfiguration result = new TableRuleConfiguration("t_order","m2.t_order_$->{1..2}");
// 指定 t_order 表的分片策略,分片策略包括分片键和分片算法
result.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "t_order_$->{order_id%2+1}"));
result.setKeyGeneratorConfig(getKeyGeneratorConfiguration());
return result;
}
// 定义主键生成策略
private static KeyGeneratorConfiguration getKeyGeneratorConfiguration() {
return new KeyGeneratorConfiguration("SNOWFLAKE","order_id");
}
}
Мы определяем имя источника данных какm2.
Закройте файл конфигурации и измените файл application.properties:
spring.shardingsphere.enabled=false
Выполните запрос, и результат будет следующим:
Как видно из лога на рисунке, используется источник данных с именем m2, запрос запроса выполнен успешно.
4. Процесс исполнения
когдаSharding-JDBCполучилSQLКогда оператор выполняется, он будет выполняться последовательноSQL解析
=> 查询优化
=> SQL路由
=> SQL改写
=> SQL执行
=> 结果归并
и, наконец, вернуть результат выполнения.
4.1 Разбор SQL
Процесс синтаксического анализа делится на лексический анализ и синтаксический анализ. Лексер используется для преобразованияSQLразобраны на неделимые атомарные символы, называемыеToken. И в соответствии со словарем, предоставленным различными диалектами базы данных, они классифицируются на ключевые слова, выражения, литералы и операторы. Затем выходные данные лексера преобразуются в абстрактное синтаксическое дерево с помощью синтаксического анализатора.
Например, следующееSQLНапример:
SELECT id, name FROM t_user WHERE status = 'ACTIVE' AND age > 18
Для простоты понимания ключевые слова в абстрактном синтаксическом деревеTokenЗеленым цветом обозначена переменнаяTokenОбозначено красным, серый означает, что требуется дальнейшее разделение.
Наконец, поvisitorМодель предметной области создается путем обхода абстрактного синтаксического дерева, а контекст, необходимый для сегментирования, уточняется с помощью модели предметной области (SQLStatement), а места, которые, возможно, необходимо переписать, помечаются. Контекст синтаксического анализа для сегментирования включает в себя элементы выбора запроса (Выбор элементов), информацию таблицы (Таблица), условие сегментирования (Условие сегментирования), информацию о первичном ключе с автоинкрементом (Автоинкрементный первичный ключ), информацию о сортировке (Порядок), информацию о группировке (Группировать). By) и пейджинговой информации (Limit, Rownum, Top).SQLПроцесс разбора необратим, один за другимTokenсогласно сSQLИсходный порядок анализируется последовательно, и производительность очень высока. Рассмотрение различных баз данныхSQLСходства и различия диалектов предоставляются в модуле синтаксического анализа различных баз данных.SQLДиалектный словарь.
4.2 Оптимизация запросов
Слияние и оптимизация условий сегментирования, таких как ИЛИ и т. д.
4.3 SQL-маршрутизация
Сопоставьте политику сегментирования, настроенную пользователем, в соответствии с контекстом синтаксического анализа и сгенерируйте путь маршрутизации. Для тех, у кого есть осколочные ключиSQL, в соответствии с различными ключами сегментов, его можно разделить на однослойную маршрутизацию (оператор ключа сегмента — знак равенства), многослойную маршрутизацию (оператор ключа сегмента —IN) и маршрутизация диапазона (оператор ключа сегментаBETWEEN). без осколочного ключаSQLИспользуется широковещательная маршрутизация.
4.4 Перезапись SQL
Пишем для логики библиотеки и логические таблицыSQL, и не может быть выполнен непосредственно в реальной базе данных,SQLrewrite используется для преобразования логикиSQLПереписан для корректного выполнения в реальной базе данныхSQL. Он включает в себя переписывание корректности и переписывание оптимизации двух частей.
Следующий столбец является примером, если логический SQL:
SELECT order_id FROM t_order WHERE order_id = 1;
Предположим, чтоSQLКогда ключ осколка order_id настроен и order_id=1, он будет перенаправлен в таблицу осколков 1. Затем после перезаписиSQLДолжно быть:
SELECT order_id FROM t_order_1 WHERE order_id = 1;
4.5 Выполнение SQL
ShardingSphereПринять набор автоматических механизмов выполнения, отвечающих за маршрутизацию и перезапись реальногоSQLБезопасная и эффективная отправка в базовый источник данных для выполнения. это не простоSQLпройти черезJDBCОн отправляется непосредственно в источник данных для выполнения; он не помещает запрос на выполнение напрямую в пул потоков для параллельного выполнения. Это больше связано с балансировкой потребления создания соединения с источником данных и использованием памяти, а также с максимальным рациональным использованием параллелизма и другими проблемами.
4.6 Объединение результатов
Несколько наборов результатов данных, полученных от каждого узла данных, объединяются в набор результатов и правильно возвращаются запрашивающему клиенту, что называется слиянием результатов.
ShardingSphereПоддерживаемое слияние результатов функционально разделено на 5 типов: обход, сортировка, группировка, разбиение по страницам и агрегация, которые представляют собой комбинации, а не взаимоисключающие отношения. Из структурного разделения его можно разделить на слияние потоков, слияние памяти и слияние декораторов. Потоковое слияние и слияние памяти являются взаимоисключающими, и слияние декораторов может выполнять дальнейшую обработку поверх слияния потоков и слияния памяти.