1
0

PrimaryKeyUtil.java 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /**
  2. * DBSyncer Copyright 2020-2023 All Rights Reserved.
  3. */
  4. package org.dbsyncer.sdk.util;
  5. import org.dbsyncer.common.util.CollectionUtils;
  6. import org.dbsyncer.common.util.NumberUtil;
  7. import org.dbsyncer.common.util.StringUtil;
  8. import org.dbsyncer.sdk.SdkException;
  9. import org.dbsyncer.sdk.model.Field;
  10. import org.dbsyncer.sdk.model.Table;
  11. import java.sql.Types;
  12. import java.util.ArrayList;
  13. import java.util.Collections;
  14. import java.util.HashMap;
  15. import java.util.HashSet;
  16. import java.util.Iterator;
  17. import java.util.List;
  18. import java.util.Map;
  19. import java.util.Set;
  20. import java.util.concurrent.atomic.AtomicBoolean;
  21. import java.util.stream.Collectors;
  22. public abstract class PrimaryKeyUtil {
  23. /**
  24. * 返回主键名称
  25. *
  26. * @param table
  27. * @return
  28. */
  29. public static List<String> findTablePrimaryKeys(Table table) {
  30. if (null == table) {
  31. throw new SdkException("The table is null.");
  32. }
  33. // 获取表同步的主键字段
  34. List<String> primaryKeys = findPrimaryKeyFields(table.getColumn()).stream().map(Field::getName).collect(Collectors.toList());
  35. // 如果存在表字段映射关系,没有配置主键则抛出异常提示
  36. if (!CollectionUtils.isEmpty(table.getColumn()) && CollectionUtils.isEmpty(primaryKeys)) {
  37. throw new SdkException(String.format("表 %s 缺少主键.", table.getName()));
  38. }
  39. return primaryKeys;
  40. }
  41. /**
  42. * 返回主键属性字段集合
  43. *
  44. * @param fields
  45. * @return
  46. */
  47. public static List<Field> findExistPrimaryKeyFields(List<Field> fields) {
  48. List<Field> list = findPrimaryKeyFields(fields);
  49. if (CollectionUtils.isEmpty(list)) {
  50. throw new SdkException("主键为空");
  51. }
  52. return list;
  53. }
  54. /**
  55. * 返回主键属性字段集合
  56. *
  57. * @param fields
  58. * @return
  59. */
  60. public static List<Field> findPrimaryKeyFields(List<Field> fields) {
  61. List<Field> list = new ArrayList<>();
  62. if (!CollectionUtils.isEmpty(fields)) {
  63. Set<String> mark = new HashSet<>();
  64. fields.forEach(f -> {
  65. if (f.isPk() && !mark.contains(f.getName())) {
  66. list.add(f);
  67. mark.add(f.getName());
  68. }
  69. });
  70. }
  71. return Collections.unmodifiableList(list);
  72. }
  73. public static void buildSql(StringBuilder sql, List<String> primaryKeys, String quotation, String join, String value, boolean skipFirst) {
  74. AtomicBoolean added = new AtomicBoolean();
  75. primaryKeys.forEach(pk -> {
  76. // skip first pk
  77. if (!skipFirst || added.get()) {
  78. if (StringUtil.isNotBlank(join)) {
  79. sql.append(join);
  80. }
  81. }
  82. sql.append(quotation).append(pk).append(quotation);
  83. if (StringUtil.isNotBlank(value)) {
  84. sql.append(value);
  85. }
  86. added.set(true);
  87. });
  88. }
  89. /**
  90. * 游标主键必须为数字类型,否则会导致分页失效
  91. *
  92. * @param fields
  93. * @return
  94. */
  95. public static boolean isSupportedCursor(List<Field> fields) {
  96. if (CollectionUtils.isEmpty(fields)) {
  97. return false;
  98. }
  99. Map<String, Integer> typeAliases = new HashMap<>();
  100. fields.forEach(field -> {
  101. if (field.isPk()) {
  102. typeAliases.put(field.getName(), field.getType());
  103. }
  104. });
  105. for (Integer pkType : typeAliases.values()) {
  106. if (!isSupportedCursorType(pkType)) {
  107. return false;
  108. }
  109. }
  110. return !CollectionUtils.isEmpty(typeAliases);
  111. }
  112. /**
  113. * 是否支持游标类型(数字)
  114. *
  115. * @param type
  116. * @return
  117. */
  118. private static boolean isSupportedCursorType(Integer type) {
  119. return type == Types.NUMERIC || type == Types.BIGINT || type == Types.INTEGER || type == Types.TINYINT || type == Types.SMALLINT;
  120. }
  121. /**
  122. * 获取最新游标值
  123. *
  124. * @param data
  125. * @param primaryKeys
  126. * @return
  127. */
  128. public static Object[] getLastCursors(List<Map> data, List<String> primaryKeys) {
  129. if (CollectionUtils.isEmpty(data)) {
  130. return null;
  131. }
  132. Map last = data.get(data.size() - 1);
  133. Object[] cursors = new Object[primaryKeys.size()];
  134. Iterator<String> iterator = primaryKeys.iterator();
  135. int i = 0;
  136. while (iterator.hasNext()) {
  137. String pk = iterator.next();
  138. cursors[i] = last.get(pk);
  139. i++;
  140. }
  141. return cursors;
  142. }
  143. public static Object[] getLastCursors(String str) {
  144. Object[] cursors = null;
  145. if (StringUtil.isNotBlank(str)) {
  146. String[] split = StringUtil.split(str, StringUtil.COMMA);
  147. int length = split.length;
  148. cursors = new Object[length];
  149. for (int i = 0; i < length; i++) {
  150. String val = split[i];
  151. cursors[i] = NumberUtil.isCreatable(val) ? NumberUtil.toLong(val) : val;
  152. }
  153. }
  154. return cursors;
  155. }
  156. }