Quellcode durchsuchen

Merge branch 'dev' of https://git.oschina.net/baomidou/mybatis-plus into dev

= vor 8 Jahren
Ursprung
Commit
58f69a6adc

+ 2 - 2
mybatis-plus/src/main/java/com/baomidou/mybatisplus/annotations/KeySequence.java

@@ -40,8 +40,8 @@ public @interface KeySequence {
      * 序列名
      * </p>
      */
-    String value();
-    
+    String value() default "";
+
     /*
      * <p>
      * id的类型

+ 15 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/entity/GlobalConfiguration.java

@@ -24,6 +24,7 @@ import java.util.concurrent.ConcurrentSkipListSet;
 
 import javax.sql.DataSource;
 
+import com.baomidou.mybatisplus.mapper.IKeyGenerator;
 import org.apache.ibatis.logging.Log;
 import org.apache.ibatis.logging.LogFactory;
 import org.apache.ibatis.session.Configuration;
@@ -76,6 +77,8 @@ public class GlobalConfiguration implements Cloneable {
     private boolean dbColumnUnderline = false;
     // SQL注入器
     private ISqlInjector sqlInjector;
+    // 表关键词 key 生成器
+    private IKeyGenerator keyGenerator;
     // 元对象字段填充控制器
     private MetaObjectHandler metaObjectHandler = new DefaultMetaObjectHandler();
     // 字段验证策略
@@ -181,6 +184,10 @@ public class GlobalConfiguration implements Cloneable {
         return getGlobalConfig(configuration).getDbType();
     }
 
+    public static IKeyGenerator getKeyGenerator(Configuration configuration) {
+        return getGlobalConfig(configuration).getKeyGenerator();
+    }
+
     public static IdType getIdType(Configuration configuration) {
         return getGlobalConfig(configuration).getIdType();
     }
@@ -200,6 +207,14 @@ public class GlobalConfiguration implements Cloneable {
         return sqlInjector;
     }
 
+    public IKeyGenerator getKeyGenerator() {
+        return keyGenerator;
+    }
+
+    public void setKeyGenerator(IKeyGenerator keyGenerator) {
+        this.keyGenerator = keyGenerator;
+    }
+
     public static MetaObjectHandler getMetaObjectHandler(Configuration configuration) {
         return getGlobalConfig(configuration).getMetaObjectHandler();
     }

+ 35 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/entity/OracleKeyGenerator.java

@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2011-2016, hubin (jobob@qq.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.baomidou.mybatisplus.entity;
+
+import com.baomidou.mybatisplus.mapper.IKeyGenerator;
+
+/**
+ * <p>
+ * Oracle Key Sequence 生成器
+ * </p>
+ *
+ * @author hubin
+ * @Date 2017-05-08
+ */
+public class OracleKeyGenerator implements IKeyGenerator {
+
+    @Override
+    public String executeSql(TableInfo tableInfo) {
+        return String.format("SELECT %s.NEXTVAL FROM DUAL", tableInfo.getKeySequence().value());
+    }
+
+}

+ 13 - 1
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/AutoGenerator.java

@@ -92,6 +92,18 @@ public class AutoGenerator extends AbstractGenerator {
         logger.debug("==========================文件生成完成!!!==========================");
     }
 
+    /**
+     * <p>
+     * 开放表信息、预留子类重写
+     * </p>
+     *
+     * @param config 配置信息
+     * @return
+     */
+    protected List<TableInfo> getAllTableInfoList(ConfigBuilder config) {
+        return config.getTableInfoList();
+    }
+
     /**
      * 分析数据
      *
@@ -99,7 +111,7 @@ public class AutoGenerator extends AbstractGenerator {
      * @return 解析数据结果集
      */
     private Map<String, VelocityContext> analyzeData(ConfigBuilder config) {
-        List<TableInfo> tableList = config.getTableInfoList();
+        List<TableInfo> tableList = this.getAllTableInfoList(config);
         Map<String, String> packageInfo = config.getPackageInfo();
         Map<String, VelocityContext> ctxData = new HashMap<>();
         String superEntityClass = getSuperClassName(config.getSuperEntityClass());

+ 13 - 1
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/po/TableField.java

@@ -129,8 +129,20 @@ public class TableField {
         this.comment = comment;
     }
 
+    /**
+     * 按JavaBean规则来生成get和set方法
+     */
     public String getCapitalName() {
-        return propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
+        if (propertyName.length() <= 1) {
+            return propertyName.toUpperCase();
+        }
+        // 第一个字母 小写、 第二个字母 大写 ,特殊处理
+        String firstChar = propertyName.substring(0, 1);
+        if (Character.isLowerCase(firstChar.toCharArray()[0])
+                && Character.isUpperCase(propertyName.substring(1, 2).toCharArray()[0])) {
+            return firstChar.toLowerCase() + propertyName.substring(1);
+        }
+        return firstChar.toUpperCase() + propertyName.substring(1);
     }
 
 }

+ 14 - 10
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/AutoSqlInjector.java

@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import com.baomidou.mybatisplus.toolkit.CollectionUtils;
 import org.apache.ibatis.builder.MapperBuilderAssistant;
 import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
 import org.apache.ibatis.executor.keygen.KeyGenerator;
@@ -646,7 +647,6 @@ public class AutoSqlInjector implements ISqlInjector {
 		 * 普通查询
 		 */
         columns.append("<choose><when test=\"ew != null and ew.sqlSelect != null\">${ew.sqlSelect}</when><otherwise>");
-        List<TableFieldInfo> fieldList = table.getFieldList();
         // 主键处理
         if (StringUtils.isNotEmpty(table.getKeyProperty())) {
             if (table.isKeyRelated()) {
@@ -655,15 +655,19 @@ public class AutoSqlInjector implements ISqlInjector {
                 columns.append(sqlWordConvert(table.getKeyProperty()));
             }
         } else {
-            TableFieldInfo fieldInfo = fieldList.get(0);
-            // 匹配转换内容
-            String wordConvert = sqlWordConvert(fieldInfo.getProperty());
-            if (fieldInfo.getColumn().equals(wordConvert)) {
-                columns.append(wordConvert);
-            } else {
-                // 字段属性不一致
-                columns.append(fieldInfo.getColumn());
-                columns.append(" AS ").append(wordConvert);
+            // 表字段处理
+            List<TableFieldInfo> fieldList = table.getFieldList();
+            if (CollectionUtils.isNotEmpty(fieldList)) {
+                TableFieldInfo fieldInfo = fieldList.get(0);
+                // 匹配转换内容
+                String wordConvert = sqlWordConvert(fieldInfo.getProperty());
+                if (fieldInfo.getColumn().equals(wordConvert)) {
+                    columns.append(wordConvert);
+                } else {
+                    // 字段属性不一致
+                    columns.append(fieldInfo.getColumn());
+                    columns.append(" AS ").append(wordConvert);
+                }
             }
         }
         columns.append("</otherwise></choose>");

+ 41 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/IKeyGenerator.java

@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2011-2016, hubin (jobob@qq.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.baomidou.mybatisplus.mapper;
+
+
+import com.baomidou.mybatisplus.entity.TableInfo;
+
+/**
+ * <p>
+ * 表关键词 key 生成器接口
+ * </p>
+ *
+ * @author hubin
+ * @Date 2017-05-08
+ */
+public interface IKeyGenerator {
+
+    /**
+     * <p>
+     * 执行 key 生成 SQL
+     * </p>
+     *
+     * @param tableInfo 数据库表反射信息
+     * @return
+     */
+    String executeSql(TableInfo tableInfo);
+
+}

+ 8 - 31
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/LogicSqlInjector.java

@@ -15,17 +15,16 @@
  */
 package com.baomidou.mybatisplus.mapper;
 
-import java.util.List;
-import java.util.Map;
-
-import org.apache.ibatis.mapping.SqlSource;
-import org.apache.ibatis.scripting.defaults.RawSqlSource;
-
 import com.baomidou.mybatisplus.entity.TableFieldInfo;
 import com.baomidou.mybatisplus.entity.TableInfo;
 import com.baomidou.mybatisplus.enums.SqlMethod;
 import com.baomidou.mybatisplus.toolkit.SqlReservedWords;
 import com.baomidou.mybatisplus.toolkit.StringUtils;
+import org.apache.ibatis.mapping.SqlSource;
+import org.apache.ibatis.scripting.defaults.RawSqlSource;
+
+import java.util.List;
+import java.util.Map;
 
 /**
  * <p>
@@ -38,25 +37,12 @@ import com.baomidou.mybatisplus.toolkit.StringUtils;
  */
 public class LogicSqlInjector extends AutoSqlInjector {
 
-	/**
-	 * 是否用更新来替换删除,默认替换
-	 */
-	private boolean updateReplaceDelete = true;
-	
-	public LogicSqlInjector() {
-		
-	}
-	
-	public LogicSqlInjector(boolean updateReplaceDelete) {
-		this.updateReplaceDelete = updateReplaceDelete;
-	}
-
 	/**
 	 * 根据 ID 删除
 	 */
 	@Override
 	protected void injectDeleteByIdSql(boolean batch, Class<?> mapperClass, Class<?> modelClass, TableInfo table) {
-		if (table.isLogicDelete() && updateReplaceDelete) {
+		if (table.isLogicDelete()) {
 			// 逻辑删除注入
 			SqlMethod sqlMethod = SqlMethod.LOGIC_DELETE_BY_ID;
 			SqlSource sqlSource;
@@ -84,7 +70,7 @@ public class LogicSqlInjector extends AutoSqlInjector {
 	 */
 	@Override
 	protected void injectDeleteSql(Class<?> mapperClass, Class<?> modelClass, TableInfo table) {
-		if (table.isLogicDelete()  && updateReplaceDelete) {
+		if (table.isLogicDelete()) {
 			// 逻辑删除注入
 			SqlMethod sqlMethod = SqlMethod.LOGIC_DELETE;
 			String sql = String.format(sqlMethod.getSql(), table.getTableName(), sqlLogicSet(table),
@@ -102,7 +88,7 @@ public class LogicSqlInjector extends AutoSqlInjector {
 	 */
 	@Override
 	protected void injectDeleteByMapSql(Class<?> mapperClass, TableInfo table) {
-		if (table.isLogicDelete()  && updateReplaceDelete) {
+		if (table.isLogicDelete()) {
 			// 逻辑删除注入
 			SqlMethod sqlMethod = SqlMethod.LOGIC_DELETE_BY_MAP;
 			String sql = String.format(sqlMethod.getSql(), table.getTableName(), sqlLogicSet(table),
@@ -308,13 +294,4 @@ public class LogicSqlInjector extends AutoSqlInjector {
 		return super.sqlWhereByMap(table);
 	}
 
-	public boolean isUpdateReplaceDelete() {
-		return updateReplaceDelete;
-	}
-
-	public void setUpdateReplaceDelete(boolean updateReplaceDelete) {
-		this.updateReplaceDelete = updateReplaceDelete;
-	}
-
-	
 }

+ 17 - 6
mybatis-plus/src/main/java/com/baomidou/mybatisplus/toolkit/Sequence.java

@@ -127,15 +127,27 @@ public class Sequence {
 
     /**
      * 获取下一个ID
-     *
      * @return
      */
     public synchronized long nextId() {
         long timestamp = timeGen();
-        if (timestamp < lastTimestamp) {
-            throw new MybatisPlusException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",
-                    lastTimestamp - timestamp));
+        if (timestamp < lastTimestamp) {//闰秒
+            long offset = lastTimestamp - timestamp;
+            if (offset <= 5) {
+                try {
+                    wait(offset << 1);
+                    timestamp = timeGen();
+                    if (timestamp < lastTimestamp) {
+                        throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", offset));
+                    }
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            } else {
+                throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", offset));
+            }
         }
+
         if (lastTimestamp == timestamp) {
             sequence = (sequence + 1) & sequenceMask;
             if (sequence == 0) {
@@ -147,8 +159,7 @@ public class Sequence {
 
         lastTimestamp = timestamp;
 
-        return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift)
-                | sequence;
+        return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
     }
 
     protected long tilNextMillis(long lastTimestamp) {

+ 40 - 47
mybatis-plus/src/main/java/com/baomidou/mybatisplus/toolkit/TableInfoHelper.java

@@ -15,13 +15,17 @@
  */
 package com.baomidou.mybatisplus.toolkit;
 
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
+import com.baomidou.mybatisplus.annotations.KeySequence;
+import com.baomidou.mybatisplus.annotations.TableField;
+import com.baomidou.mybatisplus.annotations.TableId;
+import com.baomidou.mybatisplus.annotations.TableName;
+import com.baomidou.mybatisplus.entity.GlobalConfiguration;
+import com.baomidou.mybatisplus.entity.TableFieldInfo;
+import com.baomidou.mybatisplus.entity.TableInfo;
+import com.baomidou.mybatisplus.enums.IdType;
+import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.mapper.IKeyGenerator;
+import com.baomidou.mybatisplus.mapper.SqlRunner;
 import org.apache.ibatis.builder.MapperBuilderAssistant;
 import org.apache.ibatis.executor.keygen.KeyGenerator;
 import org.apache.ibatis.executor.keygen.NoKeyGenerator;
@@ -29,7 +33,6 @@ import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
 import org.apache.ibatis.logging.Log;
 import org.apache.ibatis.logging.LogFactory;
 import org.apache.ibatis.mapping.MappedStatement;
-import org.apache.ibatis.mapping.ResultSetType;
 import org.apache.ibatis.mapping.SqlCommandType;
 import org.apache.ibatis.mapping.SqlSource;
 import org.apache.ibatis.mapping.StatementType;
@@ -37,17 +40,12 @@ import org.apache.ibatis.scripting.LanguageDriver;
 import org.apache.ibatis.session.Configuration;
 import org.apache.ibatis.session.SqlSessionFactory;
 
-import com.baomidou.mybatisplus.annotations.KeySequence;
-import com.baomidou.mybatisplus.annotations.TableField;
-import com.baomidou.mybatisplus.annotations.TableId;
-import com.baomidou.mybatisplus.annotations.TableName;
-import com.baomidou.mybatisplus.entity.GlobalConfiguration;
-import com.baomidou.mybatisplus.entity.TableFieldInfo;
-import com.baomidou.mybatisplus.entity.TableInfo;
-import com.baomidou.mybatisplus.enums.DBType;
-import com.baomidou.mybatisplus.enums.IdType;
-import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
-import com.baomidou.mybatisplus.mapper.SqlRunner;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * <p>
@@ -137,13 +135,12 @@ public class TableInfoHelper {
             }
         }
         tableInfo.setTableName(tableName);
-        
-        /* Oracle 主键支持 */
-        KeySequence keySequence = clazz.getAnnotation(KeySequence.class);
-        if (keySequence != null) {
-            tableInfo.setKeySequence(keySequence);
+
+        // 开启了自定义 KEY 生成器
+        if (null != globalConfig.getKeyGenerator()) {
+            tableInfo.setKeySequence(clazz.getAnnotation(KeySequence.class));
         }
-        
+
         /* 表结果集映射 */
         if (table != null && StringUtils.isNotEmpty(table.resultMap())) {
             tableInfo.setResultMap(table.resultMap());
@@ -245,6 +242,7 @@ public class TableInfoHelper {
                     // 开启字段下划线申明
                     if (globalConfig.isDbColumnUnderline()) {
                         column = StringUtils.camelToUnderline(column);
+                        tableInfo.setKeyRelated(true);
                     }
                     // 全局大写命名
                     if (globalConfig.isCapitalMode()) {
@@ -385,35 +383,30 @@ public class TableInfoHelper {
         }
     }
 
-    public static KeyGenerator genKeyGenerator(TableInfo tableInfo, MapperBuilderAssistant builderAssistant, String baseStatementId, LanguageDriver languageDriver) {
-        DBType dbType = GlobalConfiguration.getDbType(builderAssistant.getConfiguration());
-        if (dbType != DBType.ORACLE)
-            throw new IllegalArgumentException("目前仅支持Oracle序列");
+    /**
+     * <p>
+     * 自定义 KEY 生成器
+     * </p>
+     */
+    public static KeyGenerator genKeyGenerator(TableInfo tableInfo, MapperBuilderAssistant builderAssistant,
+                                               String baseStatementId, LanguageDriver languageDriver) {
+        IKeyGenerator keyGenerator = GlobalConfiguration.getKeyGenerator(builderAssistant.getConfiguration());
+        if (null == keyGenerator) {
+            throw new IllegalArgumentException("not configure IKeyGenerator implementation class.");
+        }
         String id = baseStatementId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
         Class<?> resultTypeClass = tableInfo.getKeySequence().idClazz();
-        Class<?> parameterTypeClass = null;
         StatementType statementType = StatementType.PREPARED;
         String keyProperty = tableInfo.getKeyProperty();
         String keyColumn = tableInfo.getKeyColumn();
-        boolean executeBefore = true;
-        boolean useCache = false;
-        KeyGenerator keyGenerator = new NoKeyGenerator();
-        Integer fetchSize = null;
-        Integer timeout = null;
-        boolean flushCache = false;
-        String parameterMap = null;
-        String resultMap = null;
-        ResultSetType resultSetTypeEnum = null;
-        //上面已经判断是ORACLE这里直接获取即可无需再判断
-        String sql = "select " + tableInfo.getKeySequence().value() + ".nextval from dual";
-        SqlSource sqlSource = languageDriver.createSqlSource(builderAssistant.getConfiguration(), sql.trim(), null);
-        SqlCommandType sqlCommandType = SqlCommandType.SELECT;
-        builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap,
-                parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, false, keyGenerator,
-                keyProperty, keyColumn, null, languageDriver, null);
+        SqlSource sqlSource = languageDriver.createSqlSource(builderAssistant.getConfiguration(),
+                keyGenerator.executeSql(tableInfo), null);
+        builderAssistant.addMappedStatement(id, sqlSource, statementType, SqlCommandType.SELECT, null, null, null,
+                null, null, resultTypeClass, null, false, false, false,
+                new NoKeyGenerator(), keyProperty, keyColumn, null, languageDriver, null);
         id = builderAssistant.applyCurrentNamespace(id, false);
         MappedStatement keyStatement = builderAssistant.getConfiguration().getMappedStatement(id, false);
-        SelectKeyGenerator answer = new SelectKeyGenerator(keyStatement, executeBefore);
+        SelectKeyGenerator answer = new SelectKeyGenerator(keyStatement, true);
         builderAssistant.getConfiguration().addKeyGenerator(id, answer);
         return answer;
     }

+ 57 - 28
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/IdWorkerTest.java

@@ -1,8 +1,19 @@
 package com.baomidou.mybatisplus.test;
 
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.ExecutorCompletionService;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.baomidou.mybatisplus.test.plugins.RandomUtils;
 import com.baomidou.mybatisplus.toolkit.IdWorker;
 
 /**
@@ -31,34 +42,52 @@ import com.baomidou.mybatisplus.toolkit.IdWorker;
  */
 public class IdWorkerTest {
 
-    /**
-     * 测试
-     */
-    public static void main(String[] args) {
-        int count = 1000;
-        ExecutorService executorService = Executors.newFixedThreadPool(count);
-        for (int i = 0; i < count; i++) {
-            executorService.execute(new IdWorkerTest().new Task());
-        }
-        executorService.shutdown();
-        while (!executorService.isTerminated()) {
-            try {
-                Thread.sleep(10);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-        }
-    }
+	@Test
+	public void test() throws Exception {
+		double wucha = 0.05;
+		int count = 1000;
+		int wuchaNum = (int) (count * wucha);
+		int high = count + wuchaNum;
+		int low = count - wuchaNum;
+		System.err.println("共有" + count + "个数参与测试,误差系数为" + wucha + "误差值为" + wuchaNum);
 
-    public class Task implements Runnable {
+		ExecutorService executorService = Executors.newFixedThreadPool(20);
+		final List<Long> results = new ArrayList<>();
+		CompletionService<Long> cs = new ExecutorCompletionService<Long>(executorService);
+		for (int i = 1; i < count; i++) {
+			cs.submit(new Callable<Long>() {
+				public Long call() throws Exception {
+					Thread.sleep(RandomUtils.nextInt(1, 2000));
+					return IdWorker.getId();
+				}
+			});
+		}
+		for (int i = 0; i < count; i++) {
+			Future<Long> future = executorService.submit(new Callable<Long>() {
+				@Override
+				public Long call() throws Exception {
+					return IdWorker.getId();
+				}
+			});
+			results.add(future.get());
+		}
+		executorService.shutdown();
+		HashSet<Long> set = new HashSet<>(results);
+		// 判断是否有重复
+		Assert.assertEquals(count, set.size());
+		int odd = 0;
+		int even = 0;
+		for (Long id : results) {
+			if (id % 2 != 0) {
+				odd++;
+			} else {
+				even++;
+			}
+		}
+		System.err.println("奇数:" + odd);
+		System.err.println("偶数:" + even);
+		Assert.assertTrue(odd >= low && odd <= high);
+		Assert.assertTrue(even >= low && even <= high);
+	}
 
-        public void run() {
-            try {
-                long id = IdWorker.getId();
-                System.err.println(id);
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-    }
 }