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.
Artikelverzeichnis
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 , SQL
z. B. SQL-92
.SQL-99
Die tatsächlichen Unterschiede zwischen den einzelnen Datenbankherstellern sind jedoch SQL
gering, d. h. der Datenbankdialekt. Am bekanntesten ist MySQL
die Verwendung von Paging limit
und Oracle
die Verwendung von Paging rownum
.
MyBatis-Plus
Unterstützt verschiedene Standarddatenbanken SQL
. Als Nächstes zeigen wir Ihnen, wie Sie MyBatis-Plus
verschiedene Datenbanken verwenden und an sie anpassen.
Fall Analyse
1. Paginierung
Viele Datenbanken SQL
nutzen Paging auf unterschiedliche Weise. MyBatis-Plus
Das integrierte Paging-Plug-in PaginationInnerInterceptor
unterstützt eine Vielzahl von Datenbanken. Auf der offiziellen Website wird erklärt:
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 .
In der Paging-Dialekt-Factory-KlasseDialectFactory
können Sie die spezifische Dialekt-Erfassungslogik sehen. Datenbanken wie mysql
, mariadb
, clickhouse
usw. oceanbase
verwenden alle mysql
Dialekte.
oracle
, 达梦数据库
mit oracle
Dialekt:
MYSQL
Datenbank-Paging-Anweisung verwendet LIMIT
Assembly:
ORACLE
Datenbank-Paging-Anweisung verwendet ROWNUM、ROW_ID
Assembly:
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 , MP
Löschen API
, Ändern oder Überprüfen xxMpper.selectList()
, da beim MP
Erstellen SQL
die Grundstandards verwendet werden , gibt es im Allgemeinen kein Kompatibilitätsproblem. Aber wenn wir XML
es selbst in die Datei schreiben SQL
, müssen wir auf verschiedene Datenbankabgleichs- und Kompatibilitätsprobleme achten.
Mybatis
Es 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.
Mybatis
Die 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;
}
Mybatis
VendorDatabaseIdProvider
Es 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();
}
}
}
Mybatis
Beim XML
Schreiben SQL
gibt es ein Attribut , databaseId
das 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 XML
Abfrageanweisungen für jeden Datenbankdialekt in der Datenbank schreiben und databaseId
Attribute hinzufügen. Mybatis
Wir 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 MP
Integrieren eines Projekts ist sehr einfach, daher werde ich hier nicht auf Details eingehen.Oracle
Mysql
Fügen Sie in der Konfigurationsdatei die entsprechende Oracle
Verbindungsadresse 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-Plus
das 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 SQL
wird 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 Mysql
und die Testanweisung SQL
wird 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.
Oracle
Die Funktion wird zum aktuellen Zeitpunkt verwendet sysdate
, und die Funktion Mysql
wird 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 if
Anweisungen 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 Oracle
und 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 |