一、任务需求
在java代码内和mapper.xml内获取当前数据库的连接类型,使得代码和sql语句可以同时兼容mysql和oracle数据库
二、实施
@Configuration
public class MyDatabaseIdProvider implements DatabaseIdProvider{
/**
* 参考mp的官方设置,sql的xml内使用_databaseId==oracle 来判断当前连接是什么类型的数据库
* @param p
*/
@Override
public void setProperties(Properties p) {
p.setProperty("Oracle", "oracle");
p.setProperty("MySQL", "mysql");
}
/**
* 根据mybatis最原始的配置方式,使用xml的那种,会有一个配置数据库圆的过程
* 而所有的数据都在dataSource内,所以通过Connection获取getMetaData元数据库
* 再获取name,也可以参照DatabaseIdProvider接口的默认实现方式
* @param dataSource
* @return
* @throws SQLException
*/
@Override
public String getDatabaseId(DataSource dataSource) throws SQLException {
Connection conn = null;
String dbName = null;
String dbAlias = "";
try {
conn = dataSource.getConnection();
dbName = conn.getMetaData().getDatabaseProductName();
switch (dbName) {
case "MySQL":
dbAlias = "mysql";
break;
case "Oracle":
dbAlias = "oracle";
break;
default:
break;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 2024/5/17修改,线上发现占用数据库连接问题,
//导致其他sql在使用时造成数据库连接超时,这里需要释放Connection 连接
if (conn != null) {
conn.close();
}
}
return dbAlias;
}
public String getDataBaseName(){
DataSource dataSource = SpringUtil.getBean(DataSource.class);
try {
return this.getDatabaseId(dataSource);
} catch (SQLException e) {
e.printStackTrace();
}
return "";
}
}
三、使用
- 第一个重写的方法是用来判断当前数据库的类型,以便于在写SQL时,对于不同的数据库使用不同的语法。例如:
<select id="containsChild" resultType="com.xxx.entiry.user">
<if test="_databaseId == 'oracle'">
select *
from A
WHERE PERM_ID in
(SELECT perm_id FROM A START
WITH perm_id = #{permId}
CONNECT BY perm_parent = PRIOR perm_id)
</if>
<if test="_databaseId == 'mysql'">
WITH RECURSIVE Aa (
SELECT * FROM
A
WHERE
perm_id = #{permId}
UNION ALL
SELECT p.*
FROM
A p
INNER JOIN
Aa ON p.perm_parent = cte.perm_id
)
SELECT *
FROM A;
</if>
</select>
- 第二个方法是在代码层面判断当前连接的是什么数据库例如:
String name = myDatabaseIdProvider.getDataBaseName()
System.out.println(name); //mysql或者oracle