Mybatis-Plus-Einstiegsserie (20) – kompatibel mit mehreren Datenbanken

Wenn es einen Weg gibt, aber keine Technik, kann die Technik trotzdem gesucht werden; wenn es eine Technik gibt, aber keinen Weg, bleibt es bei der Technik stehen.

Vorwort

Bei der tatsächlichen Entwicklung von Softwareprodukten ist die Art der Datenbank möglicherweise nicht sicher, und einige Kunden benötigen möglicherweise die zu verwendende Datenbank. Beispielsweise verlangen viele Regierungsbehörden die Verwendung inländischer Datenbanken . Daher müssen wir uns an eine Vielzahl anpassen von Datenbanken während der Entwicklung.

MySQL, Oracle, PostgreSQL, Dameng und andere Datenbanken basieren auf den vom American National Bureau of Standards festgelegten Standards für die Durchführung von Hinzufügungen, Löschungen, Änderungen und Suchvorgängen , SQLz. B. SQL-92.SQL-99

Die tatsächlichen Unterschiede zwischen den einzelnen Datenbankherstellern sind jedoch SQLgering, d. h. der Datenbankdialekt. Am bekanntesten ist MySQLdie Verwendung von Paging limitund Oracledie Verwendung von Paging rownum.

MyBatis-PlusUnterstützt verschiedene Standarddatenbanken SQL. Als Nächstes zeigen wir Ihnen, wie Sie MyBatis-Plusverschiedene Datenbanken verwenden und an sie anpassen.
Fügen Sie hier eine Bildbeschreibung ein

Fall Analyse

1. Paginierung

Viele Datenbanken SQLnutzen Paging auf unterschiedliche Weise. MyBatis-PlusDas integrierte Paging-Plug-in PaginationInnerInterceptorunterstützt eine Vielzahl von Datenbanken. Auf der offiziellen Website wird erklärt:
Fügen Sie hier eine Bildbeschreibung ein

Wenn Sie das integrierte Paging-Plugin verwenden , können Sie den Datenbanktyp festlegen:

@Configuration
@MapperScan("com.pearl.pay.mapper") //持久层扫描
@EnableTransactionManagement //启用事务管理
public class MybatisPlusConfig {
    
    
    @Bean
    @ConditionalOnMissingBean(MybatisPlusInterceptor.class)
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
    
    
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        paginationInnerInterceptor.setDbType(DbType.MYSQL);
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }
}

Wenn das integrierte Paging-Plugin ausgeführt wird SQL, erhält es den Paging-Dialekt basierend auf dem aktuellen Datenbanktyp .
Fügen Sie hier eine Bildbeschreibung ein
In der Paging-Dialekt-Factory-KlasseDialectFactory können Sie die spezifische Dialekt-Erfassungslogik sehen. Datenbanken wie mysql, mariadb, clickhouseusw. oceanbaseverwenden alle mysqlDialekte.
Fügen Sie hier eine Bildbeschreibung ein
oracle, 达梦数据库mit oracleDialekt:
Fügen Sie hier eine Bildbeschreibung ein
MYSQLDatenbank-Paging-Anweisung verwendet LIMITAssembly:
Fügen Sie hier eine Bildbeschreibung ein
ORACLEDatenbank-Paging-Anweisung verwendet ROWNUM、ROW_IDAssembly:
Fügen Sie hier eine Bildbeschreibung ein
Zusammenfassend: Beim Paging müssen Sie zur Anpassung an mehrere Datenbanken nur den Datenbanktyp im Paging-Plug-In festlegen.

2. Benutzerdefiniertes XML-SQL

B. beim Hinzufügen , MPLöschen API, Ändern oder Überprüfen xxMpper.selectList(), da beim MPErstellen SQLdie Grundstandards verwendet werden , gibt es im Allgemeinen kein Kompatibilitätsproblem. Aber wenn wir XMLes selbst in die Datei schreiben SQL, müssen wir auf verschiedene Datenbankabgleichs- und Kompatibilitätsprobleme achten.

MybatisEs bietet bereits Unterstützung für mehrere Datenbanken. Sie müssen dem Framework nur mitteilen, welche Datenbank verwendet wird, und schon können je nach Datenbankanbieter unterschiedliche Anweisungen ausgeführt werden.

MybatisDie DatabaseIdProvider Schnittstelle (Database Vendor Identity Provider) deklariert eine Methode zum Erhalten der Anbieteridentität. Die Identität kann verwendet werden, um später verschiedene Abfragen für jeden Datenbanktyp zu erstellen. Dieser Mechanismus unterstützt mehrere Anbieter oder Versionen.

public interface DatabaseIdProvider {
    
    

  default void setProperties(Properties p) {
    
    
    // NOP
  }
  // 根据数据源获取数据库厂商标识
  String getDatabaseId(DataSource dataSource) throws SQLException;
}

MybatisVendorDatabaseIdProviderEs werden auch Implementierungsklassen bereitgestellt :

public class VendorDatabaseIdProvider implements DatabaseIdProvider {
    
    
  
  // 支持的数据库厂商(需要自己定义),比如: Oracle=》oracle
  private Properties properties;
  // 获取数据库厂商标识ID(databaseId),eg:oracle
  @Override
  public String getDatabaseId(DataSource dataSource) {
    
    
    if (dataSource == null) {
    
    
      throw new NullPointerException("dataSource cannot be null");
    }
    try {
    
    
      return getDatabaseName(dataSource);
    } catch (Exception e) {
    
    
      LogHolder.log.error("Could not get a databaseId from dataSource", e);
    }
    return null;
  }

  @Override
  public void setProperties(Properties p) {
    
    
    this.properties = p;
  }
  // 根据产品名称,获取对应的databaseId。
  private String getDatabaseName(DataSource dataSource) throws SQLException {
    
    
    String productName = getDatabaseProductName(dataSource);
    if (this.properties != null) {
    
    
      for (Map.Entry<Object, Object> property : properties.entrySet()) {
    
    
        if (productName.contains((String) property.getKey())) {
    
    
          return (String) property.getValue();
        }
      }
      // no match, return null
      return null;
    }
    return productName;
  }
  // 从数据源中获取数据库产品名称,比如: Oracle
  private String getDatabaseProductName(DataSource dataSource) throws SQLException {
    
    
    try (Connection con = dataSource.getConnection()) {
    
    
      DatabaseMetaData metaData = con.getMetaData();
      return metaData.getDatabaseProductName();
    }
  }
}

MybatisBeim XMLSchreiben SQLgibt es ein Attribut , databaseIddas angeben kann, zu welchem ​​Datenbanktyp der aktuelle Anweisungsblock gehört, wie zum Beispiel:

<mapper namespace="org.pearl.mybatis.demo.dao.UserMapper">
    <select id="selectOneById" resultType="org.pearl.mybatis.demo.pojo.entity.User" databaseId="mysql">
    select * from user where user_id = #{id}
  </select>
</mapper>

Zusammenfassend lässt sich sagen: Wir müssen nur konfigurieren, DatabaseIdProvider welche Datenbanken in der Datenbank unterstützt werden, und dann XMLAbfrageanweisungen für jeden Datenbankdialekt in der Datenbank schreiben und databaseIdAttribute hinzufügen. MybatisWir erhalten den Datenbanktyp, den die Datenquelle beim Start verwendet, und Führen Sie dann die Anweisung aus, die der aktuell konfigurierten Datenbank entspricht.

Falldarstellung

1. Konfiguration

Das Erstellen und MPIntegrieren eines Projekts ist sehr einfach, daher werde ich hier nicht auf Details eingehen.OracleMysql

Fügen Sie in der Konfigurationsdatei die entsprechende OracleVerbindungsadresse hinzu Mysql:

spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: oracle.jdbc.OracleDriver
    url: jdbc:oracle:thin:@127.0.0.1:1521:ORCL
    username: root
    password: root
    #driver-class-name: com.mysql.cj.jdbc.Driver
    #url: jdbc:mysql://127.0.0.1:3306/d_account?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    #username: root
    #password: root

Konfigurationsklasse hinzufügen in MP:

@Configuration
@MapperScan("com.pearl.pay.mapper") //持久层扫描
@EnableTransactionManagement //启用事务管理
public class MybatisPlusConfig {
    
    
     @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(DataSource dataSource,DatabaseIdProvider databaseIdProvider) throws SQLException {
    
    
        // MP插件
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        // 获取当前数据源对应的数据库类型,添加分页插件
        String databaseId = databaseIdProvider.getDatabaseId(dataSource);
        DbType dbType = DbType.getDbType(databaseId);
        paginationInnerInterceptor.setDbType(dbType);
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }

    @Bean
    public DatabaseIdProvider databaseIdProvider() {
    
    
        // 数据库厂商提供者
        DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
        Properties p = new Properties();
        p.setProperty("Oracle", "oracle");
        p.setProperty("Mysql", "mysql");
        databaseIdProvider.setProperties(p);
        return databaseIdProvider;
    }
}

2. Einfache Paging-Abfrage

Da MyBatis-Plusdas integrierte Paging-Plugin angepasst wurde, müssen einfache Paging-Abfragen (ohne Datenbankdialekt) nicht durch das Schreiben Ihres eigenen Codes angepasst werden.

Fügen Sie zunächst eine Paging-Abfrage hinzu:

    IPage<User> test(Page<User> page);    
    <select id="test" resultType="com.pearl.entity.User">
        select * from user
    </select>

Die Datenquelle ist konfiguriert Oracle, es gibt jedoch keine Konfiguration databaseId. Die Testanweisung SQLwird wie folgt gedruckt:

SELECT * FROM ( SELECT TMP.*, ROWNUM ROW_ID FROM ( select * from user) TMP WHERE ROWNUM <=10) WHERE ROW_ID > 0

Die Datenquelle wird wie folgt konfiguriert Mysqlund die Testanweisung SQLwird wie folgt gedruckt:

select * from user LIMIT 10

3. Paging-Abfrage mit Dialekten

Anforderung : Fragen Sie Daten ab, deren Zeitknoten kleiner als die aktuelle Zeit ist.

OracleDie Funktion wird zum aktuellen Zeitpunkt verwendet sysdate, und die Funktion Mysqlwird verwendet now(). Zu diesem Zeitpunkt müssen Sie die Kompatibilität manuell herstellen.

Schreiben Sie zwei Abfrageanweisungen mit demselben Namen, die für verschiedene Datenbankanbieter geschrieben wurden SQL, und konfigurieren Sie die entsprechendedatabaseId

    <select id="test" resultType="com.pearl.entity.User" databaseId="mysql">
        select * from user t <![CDATA[ where t.create_time <= now()]]>
    </select>
    
    <select id="test" resultType="com.pearl.entity.User" databaseId="oracle">
        select * from user t  <![CDATA[ where t.create_time  <=  sysdate ]]>
    </select>

Sie können ifAnweisungen auch verwenden, um den aktuellen Datenbanktyp zu ermitteln und verschiedene Anweisungen hinzuzufügen (empfohlen).

    <select id="test" resultType="com.pearl.entity.User">
        select * from user t
        <where>
            <if test="_databaseId == 'mysql'">
                <![CDATA[ AND t.create_time <= now()]]>
            </if>
            <if test="_databaseId == 'oracle'">
                <![CDATA[ AND t.create_time  <=  sysdate ]]>
            </if>
        </where>
    </select>

Um die Datenbank zu wechseln, führen Sie Folgendes aus:

select * from user t where t.create_time <= now() LIMIT 10
SELECT * FROM ( SELECT TMP.*, ROWNUM ROW_ID FROM ( select * from user t where t.create_time <= sysdate ) TMP WHERE ROWNUM <=10) WHERE ROW_ID > 0

Referenz

Lassen Sie uns als Nächstes kurz einige der Unterschiede zwischen Oracleund verstehen Mysql, um die Entwicklung zu erleichtern.

Datentypvergleich:

Datenbank Vergleichsartikel Typ
MySQL Art der Daten INTEGER, SMALLINT, TINYINT, MEDIUMINT, BIGINT
Orakel Art der Daten Nummer
MySQL Datum (und Uhrzeit Datum, Zeitstempel, Zeitstempel
Orakel Datum (und Uhrzeit Datum, Zeitstempel
MySQL Zeichentyp char、varchar
Orakel Zeichentyp char、varchar、varchar2、nvarchar、nvarchar2
MySQL großes Feld LANGTEXT
Orakel großes Feld Klopf

Häufig verwendeter Funktionsvergleich:

Datenbank Vergleichsartikel Funktion
MySQL Ermitteln Sie die Stringlänge char_length(str)
Orakel Ermitteln Sie die Stringlänge Länge(str)
MySQL Generieren Sie eine Zufallssequenz UUID()
Orakel Generieren Sie eine Zufallssequenz sys_guid()
MySQL Zeit in String umwandeln date_format(NOW(),'%Y-%m-%d')
Orakel Zeit in String umwandeln to_char(Systemdatum, 'JJJJ-MM-TT')
MySQL Konvertieren Sie die Zeichenfolgenzeit in die Zeit str_to_date('2019-01-01','%Y-%m-%d')
Orakel Konvertieren Sie die Zeichenfolgenzeit in die Zeit to_date('2019-01-01', 'JJJJ-MM-TT')
MySQL Funktionsumrechnung mit Stunden, Minuten und Sekunden date_format(NOW(),'%Y-%m-%d %H:%i:%s')
Orakel Funktionsumrechnung mit Stunden, Minuten und Sekunden str_to_date('2019-01-01','%Y-%m-%d %H:%i:%s')
MySQL aktuelle Uhrzeit Jetzt()
Orakel aktuelle Uhrzeit sysdate

andere:

Datenbank Vergleichsartikel Unterstützung
MySQL Anführungszeichen Doppelte und einfache Anführungszeichen
Orakel Anführungszeichen Es werden nur einfache Anführungszeichen erkannt
MySQL String-Verkettung concat()-Funktion
Orakel String-Verkettung Zur Verbindung von Saiten können doppelte vertikale Stäbe verwendet werden
MySQL Seitennummerierung Grenze
Orakel Seitennummerierung rownum

Supongo que te gusta

Origin blog.csdn.net/qq_43437874/article/details/129161055
Recomendado
Clasificación