Вы говорите, что используете аннотации, но я бы предложил использовать для этого XML. Я обычно нахожу это более понятным, особенно потому, что есть части запроса, которые вам все равно придется полностью изменить.
Вот пример DDL, где вы получаете два отдельных элемента XML для одного и того же метода, но с разными идентификаторами базы данных. Эти таблицы очень похожи, но из-за того, как вы проверяете, существует ли таблица и типы ли существенно различаются, вы не можете избежать отдельного кода SQL для этого:
<update id="createTables" databaseId="postgresql">
DO $$
BEGIN
CREATE TABLE IF NOT EXISTS item (
id SERIAL PRIMARY KEY,
content TEXT,
creation_datetime TIMESTAMPTZ DEFAULT NOW(),
modification_datetime TIMESTAMPTZ
);
END$$
</update>
<update id="createTables" databaseId="sqlserver">
IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'item')
BEGIN
CREATE TABLE item (
id INT IDENTITY PRIMARY KEY,
content NVARCHAR(MAX),
creation_datetime DATETIMEOFFSET DEFAULT SYSDATETIMEOFFSET(),
modification_datetime DATETIMEOFFSET
);
END
</update>
Вы также можете иметь запрос в элементе SQL, но различные разделы могут быть изменены с помощью <if>
(или <choose>
) в зависимости от идентификатора базы данных. Это работает нормально, если изменения невелики:
<delete id="deleteItem">
DELETE FROM my_item
WHERE gid=CAST(#{gid} AS <if test="_databaseId == 'postgresql'">UUID</if><if test="_databaseId == 'sqlserver'">UNIQUEIDENTIFIER</if>)
</delete>
<select id="getLatestSomething" resultType="test.Something">
SELECT <if test="_databaseId == 'sqlserver'">TOP 1</if> *
FROM something
ORDER BY creation_datetime DESC
<if test="_databaseId == 'postgresql'">
LIMIT 1
</if>
</select>
Выбор между наличием отдельных элементов запроса для разных идентификаторов базы данных или просто условных фрагментов в одном и том же элементе запроса зависит от удобства чтения. Это может быть весьма субъективно в зависимости от сложности запроса.
Например, я нахожу следующую "упущенную" с использованием PostgreSQL и SQL Server довольно трудной для чтения. Было бы лучше в отдельных элементах:
<insert id="insertStuff" parameterType="somestuff.Stuff">
<if test="_databaseId == 'postgresql'">
INSERT INTO my_stuff (...)
</if>
<if test="_databaseId == 'sqlserver'">
MERGE INTO my_stuff WITH (HOLDLOCK) AS t USING (
</if>
VALUES (#{...},
<if test="_databaseId == 'postgresql'">
CAST(#{jsonData} AS JSONB)
</if>
<if test="_databaseId == 'sqlserver'">
#{jsonData}
</if>
)
<if test="_databaseId == 'postgresql'">
ON CONFLICT DO NOTHING
</if>
<if test="_databaseId == 'sqlserver'">
)
AS s (...)
ON t....=s....
AND t....=s....
WHEN NOT MATCHED BY TARGET THEN
INSERT (...)
VALUES (s...., s....);
</if>
</insert>
Более подробная информация об этом содержится в документации MyBatis Dynamic SQL .
Если ваш файл сопоставления XML находится в mypackage/MyMapper.xml
, вы можете использовать интерфейс Java MyMapper
в пакете, соответствующем этому каталогу. Там нет ничего конкретного для идентификатора базы данных.
package mypackage;
public interface MyMapper {
void createTables();
void deleteItem(@Param("gid") UUID gid);
Something getLatestSomething();
}
При использовании MyBatis с Spring вы можете установить конфигурацию поставщика следующим образом:
@Bean
public VendorDatabaseIdProvider vendorDatabaseIdProvider() {
Properties vendorProperties = new Properties();
vendorProperties.setProperty("PostgreSQL", "postgresql");
vendorProperties.setProperty("SQL Server", "sqlserver");
// Add others as required, this will look for the substring in the product name coming
// from the database metadata.
// ...
VendorDatabaseIdProvider dbIdProvider = new VendorDatabaseIdProvider();
dbIdProvider.setProperties(vendorProperties);
return dbIdProvider;
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource, ApplicationContext appContext,
VendorDatabaseIdProvider vendorDatabaseIdProvider) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setDatabaseIdProvider(vendorDatabaseIdProvider);
SqlSessionFactory factory = bean.getObject();
return factory;
}
Если вы не используете Spring, вы сможете настроить DatabaseIdProvider
с помощью XML-конфигурации .
Вам строго не нужен поставщик идентификатора базы данных. Все, что он делает, это устанавливает идентификатор базы данных в конфигурации, основываясь на имени продукта, которое он получает из DataSource
. Что-то в этом роде:
String databaseId = databaseIdProvider.getDatabaseId(dataSource);
configuration.setDatabaseId(databaseId);
(Если вы посмотрите на код org.apache.ibatis.mapping.VendorDatabaseIdProvider
, вы увидите, что databaseIdProvider.getDatabaseId(...)
просто ищет подходящую подстроку в том, что возвращается из DatabaseMetaData.getDatabaseProductName()
. Вы также можете сделать это вручную с помощью других настроек, если это необходимо. )
Обратите внимание, что когда databaseId=""
используется непосредственно в качестве атрибута элемента XML, подчеркивание отсутствует, но когда оно используется в качестве условия проверки, оно называется _databaseId
.