001/* 002 * Copyright (c) 2022-2023, 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 java.util.EnumMap; 020import java.util.Map; 021 022import com.mybatisflex.core.exception.MybatisFlexException; 023import org.apache.ibatis.util.MapUtil; 024import com.mybatisflex.core.FlexGlobalConfig; 025import com.mybatisflex.core.dialect.impl.CommonsDialectImpl; 026import com.mybatisflex.core.dialect.impl.DB2105Dialect; 027import com.mybatisflex.core.dialect.impl.DmDialect; 028import com.mybatisflex.core.dialect.impl.OracleDialect; 029import com.mybatisflex.core.util.ObjectUtil; 030 031/** 032 * 方言工厂类,用于创建方言 033 */ 034public class DialectFactory { 035 036 private DialectFactory() { 037 } 038 039 /** 040 * 数据库类型和方言的映射关系,可以通过其读取指定的方言,亦可能通过其扩展其他方言 041 * 比如,在 mybatis-flex 实现的方言中有 bug 或者 有自己的独立实现,可以添加自己的方言实现到 042 * 此 map 中,用于覆盖系统的方言实现 043 */ 044 private static final Map<DbType, IDialect> dialectMap = new EnumMap<>(DbType.class); 045 046 /** 047 * 通过设置当前线程的数据库类型,以达到在代码执行时随时切换方言的功能 048 */ 049 private static final ThreadLocal<DbType> dbTypeThreadLocal = new ThreadLocal<>(); 050 private static DbType dbTypeGlobal = null ; 051 052 053 /** 054 * 获取方言 055 * 056 * @return IDialect 057 */ 058 public static IDialect getDialect() { 059 DbType dbType = ObjectUtil.requireNonNullElse(dbTypeThreadLocal.get(), FlexGlobalConfig.getDefaultConfig().getDbType()); 060 return MapUtil.computeIfAbsent(dialectMap, dbType, DialectFactory::createDialect); 061 } 062 063 /** 064 * 设置当前线程的 dbType 065 * 066 * @param dbType 067 */ 068 public static void setHintDbType(DbType dbType) { 069 dbTypeThreadLocal.set(dbType); 070 } 071 072 /** 073 * 获取当前线程的 dbType 074 * 075 * @return dbType 076 */ 077 public static DbType getHintDbType() { 078 return dbTypeThreadLocal.get(); 079 } 080 081 public static DbType getGlobalDbType() { 082 return dbTypeGlobal; 083 } 084 085 public static void setGlobalDbType(DbType dbType) { 086 if(dbTypeGlobal == null&&dbType!=null){ 087 dbTypeGlobal = dbType ; 088 }else if(dbTypeGlobal != null){ 089 throw new MybatisFlexException("dbTypeGlobal is only set once"); 090 }else if(dbType==null){ 091 throw new MybatisFlexException("dbType can not be null"); 092 } 093 } 094 095 /** 096 * 清除当前线程的 dbType 097 */ 098 public static void clearHintDbType() { 099 dbTypeThreadLocal.remove(); 100 } 101 102 103 /** 104 * 可以为某个 dbType 注册(新增或覆盖)自己的方言 105 * 106 * @param dbType 数据库类型 107 * @param dialect 方言的实现 108 */ 109 public static void registerDialect(DbType dbType, IDialect dialect) { 110 dialectMap.put(dbType, dialect); 111 } 112 113 114 private static IDialect createDialect(DbType dbType) { 115 switch (dbType) { 116 case MYSQL: 117 case H2: 118 case MARIADB: 119 case GBASE: 120 case OSCAR: 121 case XUGU: 122 case OCEAN_BASE: 123 case CUBRID: 124 case GOLDILOCKS: 125 case CSIIDB: 126 case HIVE: 127 case DORIS: 128 return new CommonsDialectImpl(KeywordWrap.BACK_QUOTE, LimitOffsetProcessor.MYSQL); 129 case CLICK_HOUSE: 130 case GBASE_8S: 131 return new CommonsDialectImpl(KeywordWrap.NONE, LimitOffsetProcessor.MYSQL); 132 case DM: 133 return new DmDialect(); 134 case ORACLE: 135 return new OracleDialect(); 136 case GAUSS: 137 return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.ORACLE); 138 case POSTGRE_SQL: 139 case SQLITE: 140 case HSQL: 141 case KINGBASE_ES: 142 case PHOENIX: 143 case SAP_HANA: 144 case IMPALA: 145 case HIGH_GO: 146 case VERTICA: 147 case REDSHIFT: 148 case OPENGAUSS: 149 case UXDB: 150 case LEALONE: 151 return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.POSTGRESQL); 152 case TDENGINE: 153 return new CommonsDialectImpl(KeywordWrap.BACK_QUOTE, LimitOffsetProcessor.POSTGRESQL); 154 case ORACLE_12C: 155 return new OracleDialect(LimitOffsetProcessor.DERBY); 156 case FIREBIRD: 157 case DB2: 158 return new CommonsDialectImpl(KeywordWrap.NONE, LimitOffsetProcessor.DERBY); 159 case DB2_1005: 160 return new DB2105Dialect(KeywordWrap.NONE, DB2105Dialect.DB2105LimitOffsetProcessor.DB2105); 161 case SQLSERVER: 162 return new CommonsDialectImpl(KeywordWrap.SQUARE_BRACKETS, LimitOffsetProcessor.SQLSERVER); 163 case SQLSERVER_2005: 164 return new CommonsDialectImpl(KeywordWrap.SQUARE_BRACKETS, LimitOffsetProcessor.SQLSERVER_2005); 165 case INFORMIX: 166 return new CommonsDialectImpl(KeywordWrap.NONE, LimitOffsetProcessor.INFORMIX); 167 case SINODB: 168 return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.SINODB); 169 case SYBASE: 170 return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.SYBASE); 171 default: 172 return new CommonsDialectImpl(); 173 } 174 } 175 176}