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