001/* 002 * Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.dialect; 017 018 019import com.mybatisflex.core.FlexGlobalConfig; 020import com.mybatisflex.core.dialect.impl.*; 021import com.mybatisflex.core.util.MapUtil; 022import com.mybatisflex.core.util.ObjectUtil; 023 024import java.util.EnumMap; 025import java.util.Map; 026 027/** 028 * 方言工厂类,用于创建方言 029 */ 030public class DialectFactory { 031 032 private DialectFactory() { 033 } 034 035 /** 036 * 数据库类型和方言的映射关系,可以通过其读取指定的方言,亦可能通过其扩展其他方言 037 * 比如,在 mybatis-flex 实现的方言中有 bug 或者 有自己的独立实现,可以添加自己的方言实现到 038 * 此 map 中,用于覆盖系统的方言实现 039 */ 040 private static final Map<DbType, IDialect> dialectMap = new EnumMap<>(DbType.class); 041 /** 042 * 通过设置当前线程的数据库类型,以达到在代码执行时随时切换方言的功能 043 */ 044 private static final ThreadLocal<DbType> dbTypeThreadLocal = new ThreadLocal<>(); 045 046 /** 047 * 获取方言 048 * 049 * @return IDialect 050 */ 051 public static IDialect getDialect() { 052 DbType dbType = ObjectUtil.requireNonNullElse(dbTypeThreadLocal.get(), 053 FlexGlobalConfig.getDefaultConfig().getDbType()); 054 return MapUtil.computeIfAbsent(dialectMap, dbType, DialectFactory::createDialect); 055 } 056 057 /** 058 * 设置当前线程的 dbType 059 * 060 * @param dbType 061 */ 062 public static void setHintDbType(DbType dbType) { 063 dbTypeThreadLocal.set(dbType); 064 } 065 066 /** 067 * 获取当前线程的 dbType 068 * 069 * @return dbType 070 */ 071 public static DbType getHintDbType() { 072 return dbTypeThreadLocal.get(); 073 } 074 075 076 /** 077 * 清除当前线程的 dbType 078 */ 079 public static void clearHintDbType() { 080 dbTypeThreadLocal.remove(); 081 } 082 083 084 /** 085 * 可以为某个 dbType 注册(新增或覆盖)自己的方言 086 * 087 * @param dbType 数据库类型 088 * @param dialect 方言的实现 089 */ 090 public static void registerDialect(DbType dbType, IDialect dialect) { 091 dialectMap.put(dbType, dialect); 092 } 093 094 095 private static IDialect createDialect(DbType dbType) { 096 switch (dbType) { 097 case MYSQL: 098 case H2: 099 case MARIADB: 100 case GBASE: 101 case OSCAR: 102 case XUGU: 103 case OCEAN_BASE: 104 case CUBRID: 105 case GOLDILOCKS: 106 case CSIIDB: 107 case HIVE: 108 case DORIS: 109 return new CommonsDialectImpl(KeywordWrap.BACK_QUOTE, LimitOffsetProcessor.MYSQL); 110 case CLICK_HOUSE: 111 return new ClickhouseDialectImpl(KeywordWrap.NONE, LimitOffsetProcessor.MYSQL); 112 case GBASE_8S: 113 return new CommonsDialectImpl(KeywordWrap.NONE, LimitOffsetProcessor.MYSQL); 114 case DM: 115 return new DmDialect(); 116 case ORACLE: 117 return new OracleDialect(); 118 case GAUSS: 119 return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.ORACLE); 120 case POSTGRE_SQL: 121 case SQLITE: 122 case HSQL: 123 case KINGBASE_ES: 124 case PHOENIX: 125 case SAP_HANA: 126 case IMPALA: 127 case HIGH_GO: 128 case VERTICA: 129 case REDSHIFT: 130 case OPENGAUSS: 131 case UXDB: 132 case LEALONE: 133 return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.POSTGRESQL); 134 case TDENGINE: 135 return new CommonsDialectImpl(KeywordWrap.BACK_QUOTE, LimitOffsetProcessor.POSTGRESQL); 136 case ORACLE_12C: 137 return new OracleDialect(LimitOffsetProcessor.DERBY); 138 case FIREBIRD: 139 case DB2: 140 return new CommonsDialectImpl(KeywordWrap.NONE, LimitOffsetProcessor.DERBY); 141 case DB2_1005: 142 return new DB2105Dialect(KeywordWrap.NONE, DB2105Dialect.DB2105LimitOffsetProcessor.DB2105); 143 case SQLSERVER: 144 return new SqlserverDialectImpl(KeywordWrap.SQUARE_BRACKETS, LimitOffsetProcessor.SQLSERVER); 145 case SQLSERVER_2005: 146 return new Sqlserver2005DialectImpl(KeywordWrap.SQUARE_BRACKETS, LimitOffsetProcessor.SQLSERVER_2005); 147 case INFORMIX: 148 return new CommonsDialectImpl(KeywordWrap.NONE, LimitOffsetProcessor.INFORMIX); 149 case SINODB: 150 return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.SINODB); 151 case SYBASE: 152 return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.SYBASE); 153 default: 154 return new CommonsDialectImpl(); 155 } 156 } 157 158}