Запись пошагового выполнения решения Mybatis plus с несколькими арендаторами
Старый проект компании нужно трансформировать в мультитенант, поэтому он попал в большую яму.В этой статье написано о встречавшихся ямах и решениях.Каждый раз, когда возникает проблема, ее долго ищут в интернете, и это записывается, чтобы предотвратить его забвение в будущем.
(1). Схема
Есть много онлайн-программ, мы пишем только последнее, а именно: увеличенный идентификатор таблицы арендатора, для достижения изоляции данных
Вариант 1. Увеличьте идентификатор арендатора и вручную добавьте идентификатор арендатора во все места, где вызывается картограф.
Например:
LambdaQueryWrapper<Entity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(Entity::getTenantId,"tenantId");
entityMapper.selectList(lambdaQueryWrapper);
Этот метод сложен, рабочая нагрузка велика, и его легко утечь. не принят
Вариант 2. Используйте официальный многопользовательский подключаемый модуль mp, код здесь опущен, перейдите к официальной документации, чтобы запросить
(2) Оптимизация и подводные камни официальной многопользовательской схемы
После принятия мультитенантного плагина официальной документации пуско-наладочные работы прошли очень гладко, а сырость прошла самотестирование.Я думал, что проблем нет, поэтому отправил тестовую среду, но с углублением тест, было обнаружено много проблем и нужно изменить. , перечисленные здесь:
1. Проанализируйте, что нужно арендаторам Cadogan, а что не добавляет
(1) Перезапись идентификатора арендатора Официальный метод переопределения по умолчанию:
@Override
public Expression getTenantId() {
return null;
}
Здесь вам нужно определить, как получить идентификатор арендатора.
(2) Определение поля арендатора
private static final String TENANT_ID = "tenant_id";
@Override
public String getTenantIdColumn() {
return TENANT_ID;
}
(3) Перехват арендатора
@Override
public boolean ignoreTable(String tableName) {
return TenantLineHandler.super.ignoreTable(tableName);
}
Решение, которое я использую здесь, это перехват имени таблицы, код выглядит следующим образом:
@Override
public boolean ignoreTable(String tableName) {
/**
* 此处的list,临时用作拦截
* 原因是:下面的表解析方法,用的是大驼峰转下划线,再跟sql拦截器拦截到的表名对比,如果匹配到了,则认为该表需要多租户拼接
* 但是有的表没有严格的按照大驼峰转下划线,所以这些表需要额外定义
* @TableName 这个注解能否完成该职责,目前还未测试,以后再说。
*/
List<String> list = new ArrayList<>();
list.add("das_standard_operation");
list.add("t_expert");
list.add("t_nominate_dict");
list.add("t_nominate_dict_history");
list.add("t_order");
list.add("t_standard_sort");
list.add("t_task");
list.add("t_task_confirm");
list.add("das_view");
if (list.contains(tableName)) {
return false;
}
EntityTableCache instance = EntityTableCache.getInstance();
if (null == instance || null == instance.getCacheData(tableName)) {
//如果未初始化到,不拼接租户id
return true;
}
String entityPath = EntityTableCache.getInstance().getCacheData(tableName).toString();
//该方法会将大驼峰转为下划线,并完成初始化
return !EntityUtils.isHaveAttr(entityPath, COLUMN_TENANTID);
}
Код метода EntityUtils выглядит следующим образом (написал молодой человек на github, свяжитесь со мной, чтобы удалить нарушение)
/**
* 判断实体是否有某个属性
*
* @param entityPath 实体全路径
* @param attrName 属性名字
* @return boolean
*/
public static boolean isHaveAttr(String entityPath, String attrName) {
Optional<String> epOptional = Optional.ofNullable(entityPath);
if (!epOptional.isPresent()) {
return false;
}
try {
Class<?> aClass = Thread.currentThread().getContextClassLoader().loadClass(epOptional.get());
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
if (attrName.equals(field.getName())) {
return true;
}
}
return false;
} catch (ClassNotFoundException e) {
// log.error("SystemSqlParser->isHaveAttr类加载异常:" + e.getMessage());
return false;
}
}
2.jsqlparser Этот пакет не так с версией PageHelper
Во время самопроверки я обнаружил, что оператор обновления не может быть остановлен.Оказалось, что номер версии jsqlparser был 1.2 и 1.2 и 2.0 (версия jspparser mp3.4.1 была 2.0).Посредством отладки я нашел что я ввел метод обновления 1.2. Как показано на рисунке:
Версия 1.2 — это getTables(), а 2.0 — это getTable(), как показано ниже.
Решение: родительский pom применяет версию
</dependencyManagement>
</dependencies>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
</dependencies>
</dependencyManagement>
3. Не удалось выполнить синтаксический анализ SQL
1.regexp
В настоящее время найден использовать RegexP> 0 SQL-заявление, парсер будет жаловаться
2.заменить в заявлении
Я обнаружил, что это утверждение пока не поддерживается.
Вышеуказанные две проблемы до сих пор не решены.Я читал некоторые материалы и спрашивал некоторых коллег.Я мало контактирую с этой темой.В настоящее время используемый в 3.4.3.4 com.github.jsqlparser используется последней версией mp:jsqlparser Версия 4.2, в настоящее время не поддерживает два вышеупомянутых (если какой-либо великий бог решил это, пожалуйста, прокомментируйте и направьте!)
Решение
Раз у вас не получается, то вы мне не нужны, склейка вручную, смотрите метод игнора ниже⬇️
4. Игнорирование мультитенантности не работает
Мы все знаем, что по аннотации: @interceptorignore (tenantline = "on") может получить оператор MAPPER без разрешения SQL и не выполняет многотенантное преобразование. Но в реальном сценарии приложения обнаруживается, что есть особая сцена, в которой эта аннотация не действует.
Например:
Page<Expert> page = PageHelper.startPage(param.getPageNumber(), param.getPageSize());
List<Expert> experts = expertMapper.queryExpertList(page);
Этот вопрос действительно долгое время отнимал у меня время впустую.Позже, ознакомившись с информацией, я обнаружил, что @InterceptorIgnore будет недействительным при наличии нумерации страниц, но я снова думаю, это все мп вещи, вы конфликтуете, ну и что? .
Потом я нашел штуку PageHelper, она выглядела очень странно. Затем я удалил его без подкачки, и это сработало! Аннотация вступает в силу. Отлично, в то же время mp уже предусмотрел пагинацию, зачем использовать com.github.
Затем преобразуйте следующим образом:
IPage<Expert> page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(param.getPageNumber(),param.getPageSize())
List<Expert> experts = expertMapper.queryExpertList(expertMapping.dtoToEntity(param));