在项目中遇到需要切换成国产化达梦数据库(DM8),在切换过程中遇到较多的问题,记录一下。
1、首先在在pom文件中引入DM8依赖:
com.dameng Dm8JdbcDriver188.1.1.49
2、在application.yml文件中引入DM8驱动:
spring:
datasource:
driver-class-name: dm.jdbc.driver.DmDriver
3、数据库连接配置(自动加载配置文件中数据库的连接信息,数据库连接信息随着环境的不同,可灵活加载):
@Configuration
@Slf4j
public class MybatisConfig {
@Autowired
private DataSourceProperties dataSourceProperties;
private ComponentConfig componentConfig = ApplicationContextExt.getComponentConfig();
@Bean(name = "dataSource")
public DruidDataSource DMDataSource() {
//配置数据源
DruidDataSource dataSource = new DruidDataSource();
String driverClassName = dataSourceProperties.getDriverClassName();
dataSource.setDriverClassName(driverClassName);
// 获取数据库配置
SegmentConfig dbConfig = componentConfig.getSegmentSelf(componentConfig.getDbId());
String dbIP = dbConfig.getProperty("db.ip");
String dbPort = dbConfig.getProperty("db.port");
String dbName = dbConfig.getProperty("db.name");
String dbUserName = dbConfig.getProperty("db.username");
String dbPassword = dbConfig.getProperty("db.password");
String url = "jdbc:dm://" + dbIP + ":" + dbPort + "/" + dbName + "?useUnicode=true&characterEncoding=utf-8";
dataSource.setUrl(url);
dataSource.setUsername(dbUserName);
dataSource.setPassword(dbPassword);
return dataSource;
}
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(DMDataSource());
return sqlSessionFactoryBean.getObject();
}
}
之后的mapper以及数据库语句这里不再描述。
【问题1】:Caused by: dm.jdbc.driver.DMException: 第1行附件出现错误:系统处于MOUNT状态
该问题可能有两种原因,一种是网上经常写的,DM数据库有三种形态(MOUNT、OPEN、SUSPEND),当其处于MOUNT状态时,不允许访问数据库对象,只能进行控制文件维护、归档配置、数据库模式修改等操作。需要将其转为OPEN状态,命令行方式执行如下语句:
alter database open;
请参考:达梦数据库:系统处于MOUNT状态_祢真伟大的博客-CSDN博客_系统处于mount状态
还有一种原因是因为数据库连接上去了,但是没有连接上正确的数据库名称,比如,我之前按照网上配置数据库连接信息,如下:
spring:
datasource:
driver-class-name: dm.jdbc.driver.DmDriver
url: jdbc:dm://localhost:12345/TEST?useUnicode=true&characterEncoding=utf-8
username: SYSDBA
password: SYSDBA
并未自动加载正确的数据库名称。导致在环境中运行时报错。如果大家使用的不是自动加载数据库连接信息的方式,而是直接在yml文件中写死的,那么可以参考如下:
spring:
datasource:
driver-class-name: dm.jdbc.driver.DmDriver
url: jdbc:dm://#{数据库ip地址}:#{数据库端口}/#{数据库名称}?useUnicode=true&characterEncoding=utf-8
username: #{数据库用户名}
password: #{数据库连接密码}
#{} 为替换符,大家可以根据实际的数值替换。
【问题2】:testWhileIdle is true, validationQuery not set
这个是因为没有对数据源进行初始化参数配置,如果大家的数据库连接信息是直接在yml文件中写死的,那可以直接在yml中配置数据库的初始化参数。由于我采用的是自动从配置文件中加载的,则写法如下:
private DruidDataSource halfInitDataSource() {
try {
DruidDataSource dataSource = new DruidDataSource();
// 可选配置---------------------------------------------------------------------------------------
// 配置初始化大小、最小、最大
String initSizeStr = componentConfig.getProperty("datasource.initial-size");
int initSize = 5;
if (StringUtils.isNotBlank(initSizeStr) && NumberUtils.isDigits(initSizeStr.trim())) {
initSize = NumberUtils.toInt(initSizeStr.trim());
}
dataSource.setInitialSize(initSize);
// 配置最小闲置时间
String miniIdleStr = componentConfig.getProperty("datasource.min-idle");
int minIdle = 5;
if (StringUtils.isNotBlank(miniIdleStr) && NumberUtils.isDigits(miniIdleStr.trim())) {
minIdle = NumberUtils.toInt(miniIdleStr.trim());
}
dataSource.setMinIdle(minIdle);
// 最大连接数
String maxConnStr = componentConfig.getProperty("datasource.max-active");
int maxConn = 20;
if (StringUtils.isNotBlank(maxConnStr) && NumberUtils.isDigits(maxConnStr.trim())) {
maxConn = NumberUtils.toInt(maxConnStr.trim());
}
dataSource.setMaxActive(maxConn);
// 配置获取连接等待超时的时间
String maxWaitStr = componentConfig.getProperty("datasource.max-wait");
int maxWait = 10 * 1000;
if (StringUtils.isNotBlank(maxWaitStr) && NumberUtils.isDigits(maxWaitStr.trim())) {
maxWait = NumberUtils.toInt(maxWaitStr.trim());
}
dataSource.setMaxWait(maxWait);
// 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
String evictionRunMillsStr = componentConfig.getProperty("datasource.time-between-eviction-runs-millis");
int evictionRunMills = 60 * 1000;
if (StringUtils.isNotBlank(evictionRunMillsStr) && NumberUtils.isDigits(evictionRunMillsStr.trim())) {
evictionRunMills = NumberUtils.toInt(evictionRunMillsStr.trim());
}
dataSource.setTimeBetweenEvictionRunsMillis(evictionRunMills);
// 配置一个连接在池中最小生存的时间,单位是毫秒
String evictionIdleMillsStr = componentConfig.getProperty("datasource.min-evictable-idle-time-millis");
int evictionIdleMills = 5 * 60 * 1000;
if (StringUtils.isNotBlank(evictionIdleMillsStr) && NumberUtils.isDigits(evictionIdleMillsStr.trim())) {
evictionIdleMills = NumberUtils.toInt(evictionIdleMillsStr.trim());
}
dataSource.setMinEvictableIdleTimeMillis(evictionIdleMills);
// 这里配置提交方式,默认就是TRUE,可以不用配置
String autoCommitStr = componentConfig.getProperty("datasource.default-auto-commit");
Boolean autoCommit = true;
if (StringUtils.isNotBlank(autoCommitStr)) {
autoCommit = BooleanUtils.toBoolean(autoCommitStr.trim());
}
dataSource.setDefaultAutoCommit(autoCommit);
// 指定获取连接时连接校验的sql查询语句
String validateQueryStr = componentConfig.getProperty("datasource.validation-query");
String validateQuery = "Select 1";
if (StringUtils.isNotBlank(validateQueryStr)) {
validateQuery = validateQueryStr.trim();
}
dataSource.setValidationQuery(validateQuery);
// 当连接空闲时,是否执行连接测试
String testWhileIdleStr = componentConfig.getProperty("datasource.test.while-idle");
Boolean testWhileIdle = true;
if (StringUtils.isNotBlank(testWhileIdleStr)) {
testWhileIdle = BooleanUtils.toBoolean(testWhileIdleStr.trim());
}
dataSource.setTestWhileIdle(testWhileIdle);
// 当从连接池借用连接时,是否测试该连接
String testonBorrowStr = componentConfig.getProperty("datasource.test.on-borrow");
Boolean testonBorrow = true;
if (StringUtils.isNotBlank(testOnBorrowStr)) {
testonBorrow = BooleanUtils.toBoolean(testOnBorrowStr.trim());
}
dataSource.setTestonBorrow(testOnBorrow);
// 在连接归还到连接池时是否测试该连接
String testonReturnStr = componentConfig.getProperty("datasource.test.on-return");
Boolean testonReturn = false;
if (StringUtils.isNotBlank(testOnReturnStr)) {
testonReturn = BooleanUtils.toBoolean(testOnReturnStr.trim());
}
dataSource.setTestonReturn(testOnReturn);
// 指定是否池化statements
String prepStatmentStr = componentConfig.getProperty("datasource.pool-prepared-statements");
Boolean prepStament = false;
if (StringUtils.isNotBlank(prepStatmentStr)) {
prepStament = BooleanUtils.toBoolean(prepStatmentStr.trim());
}
dataSource.setPoolPreparedStatements(prepStament);
// 指定最大的打开的prepared statements数量
String maxPrepStatmentStr = componentConfig.getProperty("datasource.max-open-prepared-statements");
int maxPrepStament = 10;
if (StringUtils.isNotBlank(maxPrepStatmentStr) && NumberUtils.isDigits(maxPrepStatmentStr.trim())) {
maxPrepStament = NumberUtils.toInt(maxPrepStatmentStr.trim());
}
dataSource.setMaxOpenPreparedStatements(maxPrepStament);
//
String maxPrepStatmentPerConnStr = componentConfig.getProperty("datasource.max-pool-prepared-statement-per-connection-size");
int maxPrepStamentPerConn = 20;
if (StringUtils.isNotBlank(maxPrepStatmentPerConnStr) && NumberUtils.isDigits(maxPrepStatmentPerConnStr.trim())) {
maxPrepStamentPerConn = NumberUtils.toInt(maxPrepStatmentPerConnStr.trim());
}
dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPrepStamentPerConn);
return dataSource;
} catch (Throwable e) {
String msg = "create 'dataSource' bean error.";
log.error(HikLog.toLog(ExceptionUtil.formatErrorCode(UisErrorCode.ERR_FAILED.errorCode()), msg), e);
throw new RuntimeException(msg, e);
}
}
DruidDataSource参数详解见:SpringBoot配置属性之DataSource_stupider0623的博客-CSDN博客



