diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fed88f98..26a9d5409 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 6.0.0.M1 (2023-04-23) +# 6.0.0.M4 (2023-05-09) ### 计划实现 * 【poi 】 Markdown相关(如HTML转换等),基于commonmark-java @@ -14,5 +14,6 @@ ### ❌不兼容特性 ### 🐣新特性 +* 【db 】 优化count查询兼容informix(issue#I713XQ@Gitee) ### 🐞Bug修复 \ No newline at end of file diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/cache/impl/ReentrantCache.java b/hutool-core/src/main/java/org/dromara/hutool/core/cache/impl/ReentrantCache.java index 4886c4964..3c9b01b60 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/cache/impl/ReentrantCache.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/cache/impl/ReentrantCache.java @@ -144,8 +144,8 @@ public abstract class ReentrantCache extends AbstractCache { * @param withMissCount 是否计数丢失数 */ private void remove(final K key, final boolean withMissCount) { - lock.lock(); CacheObj co; + lock.lock(); try { co = removeWithoutLock(key, withMissCount); } finally { diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/tree/hierarchy/HierarchyIterator.java b/hutool-core/src/main/java/org/dromara/hutool/core/tree/hierarchy/HierarchyIterator.java index 0d7b41bad..738f27b54 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/tree/hierarchy/HierarchyIterator.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/tree/hierarchy/HierarchyIterator.java @@ -43,7 +43,7 @@ public interface HierarchyIterator { * * @param result 结果 * @param hierarchy 当前层级 - * @return 向容器中添加元素的方法 + * @return 下一需要遍历的层级 */ Collection nextHierarchies(R result, H hierarchy); diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/tree/hierarchy/HierarchyIteratorImpl.java b/hutool-core/src/main/java/org/dromara/hutool/core/tree/hierarchy/HierarchyIteratorImpl.java index 0362e0e9d..078402dad 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/tree/hierarchy/HierarchyIteratorImpl.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/tree/hierarchy/HierarchyIteratorImpl.java @@ -50,7 +50,7 @@ public class HierarchyIteratorImpl implements HierarchyIterator { * * @param result 结果 * @param hierarchy 当前层级 - * @return 向容器中添加元素的方法 + * @return 下一需要遍历的层级 */ @Override public Collection nextHierarchies(final R result, final H hierarchy) { diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/tree/hierarchy/HierarchyUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/tree/hierarchy/HierarchyUtil.java index 4e3a15561..8472075ad 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/tree/hierarchy/HierarchyUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/tree/hierarchy/HierarchyUtil.java @@ -35,11 +35,11 @@ import java.util.function.Predicate; * Node root = Tree.build(); * // 从树结构中通过深度优先查找某个节点 * Node target = HierarchyUtil.traverseByDepthFirst( - * root, HierarchyUtil.finder(Node::getChildren, node -> Objects.equals(node.getId(), "target") ? node : null) + * root, HierarchyIteratorUtil.find(Node::getChildren, node -> Objects.equals(node.getId(), "target") ? node : null) * ); * // 从树结构中通过广度优先获取其所有的子节点 * List nodes = HierarchyUtil.traverseByBreadthFirst( - * root, HierarchyUtil.collector(Node::getChildren) + * root, HierarchyIteratorUtil.collect(Node::getChildren) * ); * } * @@ -123,17 +123,15 @@ public class HierarchyUtil { Objects.requireNonNull(hierarchyIterator); // 遍历层级结构 - final Predicate hierarchyFilter = filter.negate(); final LinkedList queue = new LinkedList<>(); final Set accessed = new HashSet<>(); queue.add(hierarchy); while (!queue.isEmpty()) { // 跳过已经访问过或者被过滤的层级结构 final H curr = queue.removeFirst(); - if (accessed.contains(curr) || hierarchyFilter.test(curr)) { + if (!accessed.add(curr) || !filter.test(curr)) { continue; } - accessed.add(curr); // 若迭代器返回true,则结束遍历 if (hierarchyIterator.isBreak(curr)) { diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/tree/hierarchy/HierarchyUtilTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/tree/hierarchy/HierarchyUtilTest.java index 262b11f00..81dc97ee4 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/tree/hierarchy/HierarchyUtilTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/tree/hierarchy/HierarchyUtilTest.java @@ -12,13 +12,12 @@ package org.dromara.hutool.core.tree.hierarchy; +import lombok.Data; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; /** * test for {@link HierarchyUtil} @@ -27,63 +26,72 @@ import java.util.stream.Collectors; */ class HierarchyUtilTest { - private Map tree; + @Data + static class Node { + private String parent; + private String value; + private List children; + + public Node(final String parent, final String value) { + this.parent = parent; + this.value = value; + } + } + + private Node root; @BeforeEach void init() { - tree = new LinkedHashMap<>(); - // 根节点 - tree.put("0", null); + root = new Node(null, "0"); - // 第一层 - tree.put("0-1", "0"); - tree.put("0-2", "0"); - tree.put("0-3", "0"); + // 第二层 + final Node first1 = new Node(root.value, "0-1"); + final Node first2 = new Node(root.value, "0-2"); + final Node first3 = new Node(root.value, "0-3"); + root.setChildren(Arrays.asList(first1, first2, first3)); // 第三层 - tree.put("0-1-1", "0-1"); - tree.put("0-1-2", "0-1"); - tree.put("0-1-3", "0-1"); + final Node second11 = new Node(first1.value, "0-1-1"); + final Node second12 = new Node(first1.value, "0-1-2"); + final Node second13 = new Node(first1.value, "0-1-3"); + first1.setChildren(Arrays.asList(second11, second12, second13)); - tree.put("0-2-1", "0-2"); - tree.put("0-2-2", "0-2"); - tree.put("0-2-3", "0-2"); + final Node second21 = new Node(first2.value, "0-2-1"); + final Node second22 = new Node(first2.value, "0-2-2"); + final Node second23 = new Node(first2.value, "0-2-3"); + first2.setChildren(Arrays.asList(second21, second22, second23)); - tree.put("0-3-1", "0-3"); - tree.put("0-3-2", "0-3"); - tree.put("0-3-3", "0-3"); + final Node second31 = new Node(first3.value, "0-3-1"); + final Node second32 = new Node(first3.value, "0-3-2"); + final Node second33 = new Node(first3.value, "0-3-3"); + first3.setChildren(Arrays.asList(second31, second32, second33)); } @Test void testTraverseByBreadthFirst() { - // 按广度优先遍历所有节点 - final Set nodes = new LinkedHashSet<>(); - HierarchyUtil.traverseByBreadthFirst("0", HierarchyIteratorUtil.scan(t -> { - nodes.add(t); - return tree.entrySet().stream() - .filter(e -> Objects.equals(t, e.getValue())) - .map(Map.Entry::getKey) - .collect(Collectors.toList()); + // // 按广度优先遍历所有节点 + final List nodes = new ArrayList<>(); + HierarchyUtil.traverseByBreadthFirst(root, HierarchyIteratorUtil.scan(t -> { + nodes.add(t.getValue()); + return t.getChildren(); })); Assertions.assertEquals(13, nodes.size()); Assertions.assertEquals( - new LinkedHashSet<>(Arrays.asList("0", "0-1", "0-2", "0-3", "0-1-1", "0-1-2", "0-1-3", "0-2-1", "0-2-2", "0-2-3", "0-3-1", "0-3-2", "0-3-3")), - nodes + Arrays.asList("0", "0-1", "0-2", "0-3", "0-1-1", "0-1-2", "0-1-3", "0-2-1", "0-2-2", "0-2-3", "0-3-1", "0-3-2", "0-3-3"), + nodes ); // 按广度优先寻找 0-2-3 - final String target = HierarchyUtil.traverseByBreadthFirst("0", HierarchyIteratorUtil.find(parentFinder(), - t -> Objects.equals(t, "0-2-3") ? t : null + final String target = HierarchyUtil.traverseByBreadthFirst(root, HierarchyIteratorUtil.find(Node::getChildren, + t -> Objects.equals(t.getValue(), "0-2-3") ? t.getValue() : null )); Assertions.assertEquals("0-2-3", target); // 按广度优先获取 0-2 的所有子节点 - final List children = HierarchyUtil.traverseByBreadthFirst( - "0", HierarchyIteratorUtil.collect(parentFinder(), - t -> Objects.equals(tree.get(t), "0-2") ? t : null - ) - ); + final List children = HierarchyUtil.traverseByBreadthFirst(root, HierarchyIteratorUtil.collect(Node::getChildren, + t -> Objects.equals(t.getParent(), "0-2") ? t.getValue() : null + )); Assertions.assertEquals(3, children.size()); Assertions.assertEquals(new ArrayList<>(Arrays.asList("0-2-1", "0-2-2", "0-2-3")), children); } @@ -92,40 +100,28 @@ class HierarchyUtilTest { void testTraverseByDepthFirst() { // 按深度优先遍历所有节点 final Set nodes = new LinkedHashSet<>(); - HierarchyUtil.traverseByDepthFirst("0", HierarchyIteratorUtil.scan(t -> { - nodes.add(t); - return tree.entrySet().stream() - .filter(e -> Objects.equals(t, e.getValue())) - .map(Map.Entry::getKey) - .collect(Collectors.toList()); + HierarchyUtil.traverseByDepthFirst(root, HierarchyIteratorUtil.scan(t -> { + nodes.add(t.getValue()); + return t.getChildren(); })); Assertions.assertEquals(13, nodes.size()); Assertions.assertEquals( - new LinkedHashSet<>(Arrays.asList("0", "0-1", "0-1-1", "0-1-2", "0-1-3", "0-2", "0-2-1", "0-2-2", "0-2-3", "0-3", "0-3-1", "0-3-2", "0-3-3")), - nodes + new LinkedHashSet<>(Arrays.asList("0", "0-1", "0-1-1", "0-1-2", "0-1-3", "0-2", "0-2-1", "0-2-2", "0-2-3", "0-3", "0-3-1", "0-3-2", "0-3-3")), + nodes ); // 按深度优先寻找 0-2-3 - final String target = HierarchyUtil.traverseByDepthFirst("0", HierarchyIteratorUtil.find(parentFinder(), - t -> Objects.equals(t, "0-2-3") ? t : null + final String target = HierarchyUtil.traverseByDepthFirst(root, HierarchyIteratorUtil.find(Node::getChildren, + t -> Objects.equals(t.getValue(), "0-2-3") ? t.getValue() : null )); Assertions.assertEquals("0-2-3", target); // 按深度优先获取 0-2 的所有子节点 - final List children = HierarchyUtil.traverseByDepthFirst( - "0", HierarchyIteratorUtil.collect(parentFinder(), - t -> Objects.equals(tree.get(t), "0-2") ? t : null - ) - ); + final List children = HierarchyUtil.traverseByDepthFirst(root, HierarchyIteratorUtil.collect(Node::getChildren, + t -> Objects.equals(t.getParent(), "0-2") ? t.getValue() : null + )); Assertions.assertEquals(3, children.size()); Assertions.assertEquals(new ArrayList<>(Arrays.asList("0-2-1", "0-2-2", "0-2-3")), children); } - private Function> parentFinder() { - return t -> tree.entrySet() - .stream() - .filter(e -> Objects.equals(t, e.getValue())) - .map(Map.Entry::getKey) - .collect(Collectors.toList()); - } } diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/symmetric/SymmetricCrypto.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/symmetric/SymmetricCrypto.java index a71829dcb..4f843f933 100644 --- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/symmetric/SymmetricCrypto.java +++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/symmetric/SymmetricCrypto.java @@ -302,9 +302,8 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor, * @since 6.0.0 */ public byte[] encrypt(final byte[] data, final byte[] salt) { - lock.lock(); - byte[] result; + lock.lock(); try { final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, salt); result = cipher.doFinal(paddingDataWithZero(data, cipher.getBlockSize())); @@ -318,9 +317,8 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor, @Override public void encrypt(final InputStream data, final OutputStream out, final boolean isClose) throws IORuntimeException { - lock.lock(); - CipherOutputStream cipherOutputStream = null; + lock.lock(); try { final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, null); cipherOutputStream = new CipherOutputStream(out, cipher); @@ -358,10 +356,9 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor, public byte[] decrypt(final byte[] bytes) { final int blockSize; final byte[] decryptData; - lock.lock(); - final byte[] salt = SaltMagic.getSalt(bytes); try { + final byte[] salt = SaltMagic.getSalt(bytes); final Cipher cipher = initMode(Cipher.DECRYPT_MODE, salt); blockSize = cipher.getBlockSize(); decryptData = cipher.doFinal(SaltMagic.getData(bytes)); @@ -376,8 +373,8 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor, @Override public void decrypt(final InputStream data, final OutputStream out, final boolean isClose) throws IORuntimeException { - lock.lock(); CipherInputStream cipherInputStream = null; + lock.lock(); try { final Cipher cipher = initMode(Cipher.DECRYPT_MODE, null); cipherInputStream = new CipherInputStream(data, cipher); diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/Dialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/Dialect.java index 4e44f2e90..df8c15c74 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/Dialect.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/Dialect.java @@ -160,8 +160,10 @@ public interface Dialect extends Serializable { * @since 5.7.2 */ default PreparedStatement psForCount(final Connection conn, SqlBuilder sqlBuilder) throws SQLException { + // https://gitee.com/dromara/hutool/issues/I713XQ + // 为了兼容informix等数据库,此处使用count(*)而非count(1) sqlBuilder = sqlBuilder - .insertPreFragment("SELECT count(1) from(") + .insertPreFragment("SELECT count(*) from(") // issue#I3IJ8X@Gitee,在子查询时需设置单独别名,此处为了防止和用户的表名冲突,使用自定义的较长别名 .append(") hutool_alias_count_"); return psForPage(conn, sqlBuilder, null);