暂无图片
暂无图片
3
暂无图片
暂无图片
暂无图片

【与达梦同行】记一次国产化数据库从安装到生产环境适配分析思考全过程

原创 每天译点晓知识 2023-01-07
3465

image.png
开篇:本文主要分为达梦数据库安装指南篇、达梦数据库生产环境适配篇。

达梦数据库安装指南篇

一、系统环境
数据库版本:dm8_setup_arm64_ent_8.1.1.48_20191203.iso

特别说明:这个服务器 cpu 是 arm 架构的,需要到达梦官网下载 arm 版本的安装包,否则其他 linux 版本的安装时会无法执行二进制文件。

二、安装前准备
1、下载达梦数据库
达梦官网:

http://www.dameng.com/

下载地址:

http://www.dameng.com/down.aspx?TypeId=11&FId=t14:11:14

这里根据服务器硬件和操作系统版本选择下载,本台服务器选择 DM8开发版(飞腾版本64位),它的镜像可以适用于 arm 架构 CPU。
image.png

2、内存检查
为了保证正确安装和运行,要尽量保证操作系统至少 1GB 的可用内存(RAM)。 如果可用内存过少,可能导致 DM 数据库安装或启动失败。
image.png

3、硬盘空间检查
达梦数据库完全安装需要 1GB 左右,需要保证其至少有 1GB 存储空间。

image.png

同时在安装过程中将产生临时文件,临时文件需要 1GB 的存储空间,目录默认为 /tmp,需要保证其至少有 1GB。

image.png

4、创建用户dmdba
为了减少对操作系统的影响,不建议以 root 系统用户来安装和运行达梦数据库。创建一个专用的系统用户 dmdba,如下

创建用户组 dinstall
groupadd dinstall

创建用户 dmdba
useradd -g dinstall -m -d /home/dmdba -s /bin/bash dmdba

初始化密码
passwd dmdba
使用id dmdba命令查看新建的 dmdba 用户

image.png

5、创建数据库安装目录
创建数据库安装目录并赋予权限,如下

#创建安装目录
mkdir /data/opt/dm
#更改目录权限
chown dmdba.dinstall -R /data/opt/dm

image.png
6、配置用户环境变量
切换到 dmdba 用户,修改 .bash_profile

su - dmdba
vi .bash_profile
添加如下内容(路径自行修改)

export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/data/opt/dm/bin"
export DM_HOME="/data/opt/dm"
export PATH=$DM_HOME/bin:$PATH:$HOME/bin

image.png
执行如下命令,使环境变量生效

source .bash_profile
三、安装
1、加载(mount)iso文件
将达梦数据库 iso 安装文件 mount 到 /mnt/dm/ 目录下,步骤如下

su - root
mkdir /mnt/dm/
mount dm8_setup_arm64_ent_8.1.1.48_20191203.iso -o loop /mnt/dm/

image.png
-o loop 表示使用回环设备(/dev/loop0,/dev/loop1,…)。 加载(mount)光驱后,在 /mnt/dm/ 目录下有个 DMInstall.bin 文件,这个文件就是 DM 的安装程序。在运行安装程序前,需要赋予 DMInstall.bin 文件执行权限

chmod 755 ./DMInstall.bin
2、安装数据库
切换至 dmdba 用户

su - dmdba
执行 DMInstall.bin 文件,安装数据库

cd /mnt/dm/
./DMInstall.bin -i
image.png

安装过程中需要选择语言、时区、安装类型等,如下
image.png

image.png
静默安装完成后,提示“请以 root 系统用户执行命令”,接着往下。

3、执行脚本
首先切换到root用户

su root
/data/opt/dm/script/root/root_installer.sh
image.png

至此,数据库已经安装成功

四、创建数据库实例
切换到 dmdba 用户,进入安装目录的 bin 目录,我们需要用到里面的 dminit 文件来进行实例创建,如下

su - dmdba
cd /data/opt/dm/bin
image.png

执行 dminit 文件初始化实例参数来创建实例

./dminit PATH=/data/opt/dm/data EXTENT_SIZE=16 PAGE_SIZE=8 LOG_SIZE=500 CASE_SENSITIVE=Y DB_NAME=DAMENG INSTANCE_NAME=DMSERVER PORT_NUM=5236 SYSDBA_PWD=123456
image.png

可以看到已经成功创建,使用./dminit help命令可以查看各参数具体说明,如下

image.png

五、注册数据库服务
进入安装目录的 script/root 目录,需要用到里面的 dm_service_installer.sh 文件进行服务注册。

su root
cd /data/opt/dm/script/root
./dm_service_installer.sh -t dmserver -dm_ini /data/opt/dm/data/DAMENG/dm.ini -p DMSERVER

image.png
可以看到创建服务(DMServiceDMSERVER)完成。

其中 -dm_ini 指定 dm.ini 的路径,使用命令./dm_service_installer.sh -h可查看相关参数解释,如下

image.png

六、服务开启和停止
数据库服务启动、停止和重启的命令如下

#启动数据库服务
systemctl start DmServiceDMSERVER
#停止数据库服务
systemctl stop DmServiceDMSERVER
#重启数据库服务
systemctl restart DmServiceDMSERVER
查看数据库服务的状态

ps aux|grep dmserver
image.png
七、防火墙配置
如果防火墙未打开则开启防火墙,启动 firewall 服务,如下

systemctl start firewalld
永久开放达梦数据库默认端口 5236,如下

#永久开放5236端口
firewall-cmd --add-port=5236/tcp --permanent --zone=public
#重启防火墙
firewall-cmd --reload

八、相关使用
1、disql 连接数据库
Disql 是 DM 数据库自带的数据库命令行客户端工具。切换到 dmdba 用户,进入安装目录的 bin 目录,通过 ./disql 命令即可连接达梦数据库。

su - dmdba
cd /data/opt/dm/bin
./disql
image.png

2、表空间和用户创建
创建表空间

//创建表空间
CREATE TABLESPACE BIGDATA DATAFILE '/data/opt/dm/datafile/db01.dbf' SIZE 2048;
//向表空间添加数据文件
ALTER TABLESPACE BIGDATA ADD DATAFILE '/data/opt/dm/datafile/db02.dbf' SIZE 2048;

创建用户

//创建用户
CREATE USER chao IDENTIFIED BY "123456" DEFAULT TABLESPACE BIGDATA;
//给用户授予PUBLIC和RESOURCE权限
grant public,resource to chao;

3、使用客户端连接
下载一个 windows 版本在本地进行安装,使用里面的客户端功能。如下,打开 DM 管理工具。

image.png

输入刚才安装的数据库相关信息,使用新建的用户进行连接验证

image.png

可以看到成功连接了达梦数据库,至此,达梦数据库相关安装及配置已经完成。

image.png

九、问题及解决方法
1、加载(mount)iso 文件时,提示写保护,将以只读方式挂载
image.png

经验证,不影响后期安装,解决方法可为文件赋予权限。

2、安装时提示“无法执行二进制文件

image.png
原因是此服务器 cpu 为 arm 架构,安装包不兼容,找到 arm 版本安装包进行安装即可。

十、接入+适配
达梦驱动引入:
在项目工程中引入达梦数据库驱动:DmJdbcDriver18(任选一种即可),详细参考如下展开。

达梦数据库生产环境适配篇

image.png
简介:
达梦数据库适配SpringBoot+HiKari+MyBatis+tk.MyBatis+PageHelper
达梦数据库管理系统是由达梦公司推出的具有完全自主知识产权的高性能数据库管理系统,简称DM。达梦为中国电子信息产业集团(CEC)旗下基础软件企业,其可靠性、高性能、海量数据处理和安全性做了大量的研发和改进工作,极大提升了达梦数据库产品的性能、可靠性、可扩展性,能同时兼顾OLTP和OLAP请求。

思考:
1、当使用K8、Docker容器化编排技术受到限制,当Oracle、MySql数据存储等数据库软件不再向我们提供正常的服务?
2、在我们的项目工程中,若是没有了这些核心技术提供正常的服务,如何能够去及时地采取补救的措施,使得业务能够平滑过渡,做到让用户无感知体验?
3、是否能够拥有自己的数据存储解决方案,技术框架是否能够适配,能否做到更好地兼容?
场景:
推进国产数据库在现有项目产品上的适配,推进达梦数据库适配工程落地。
接下来,本文主要以达梦8-DM8适配案例->常见问答Q-A的方式阐述:
image.png

一、下载&安装
首先,需要说明的是达梦的安装包放一起的,没有像Oracle那样把客户端独立出来,跟windows的安装包是一样大的,大约1.1GB的样子,好在的一点就是,直接解压就可以使用,在云盘中附详细操作指南。
image.png
解压以后,进入\source\tool\目录,里面有一个manager.exe的应用程序,可直接打开,登录就行。
其中,达梦8-JDBC驱动版本说明:

  1. DmJdbcDriver16 对应 Jdk1.6 及以上环境
  2. DmJdbcDriver17 对应 Jdk1.7 及以上环境
  3. DmJdbcDriver18 对应 Jdk1.8 及以上环境
    达梦8-hibernate方言包对应版本说明:
  4. DmDialect-for-hibernate2.0.jar 对应 Jdk1.4及以上, hibernate2.0 环境。
  5. DmDialect-for-hibernate2.1.jar 对应 Jdk1.4及以上, hibernate2.1 2.X 环境。
  6. DmDialect-for-hibernate3.0.jar 对应 Jdk1.4及以上, hibernate3.0 环境。
  7. DmDialect-for-hibernate3.1.jar 对应 Jdk1.4及以上, hibernate3.1 3.5 环境。
  8. DmDialect-for-hibernate3.6.jar 对应 Jdk1.5及以上, hibernate3.6 3.X 环境。
  9. DmDialect-for-hibernate4.0.jar 对应 Jdk1.6及以上, hibernate4.0 4.X 环境。
  10. DmDialect-for-hibernate5.0.jar 对应 Jdk1.7及以上, hibernate5.0 5.2 环境。
  11. DmDialect-for-hibernate5.3.jar 对应 Jdk1.7及以上, hibernate5.3 5.4 环境。
    说明:以上的hibernate版本指的是Hibernate ORM版本,注意区分hibernate search版本。

二、DM8&Client
接下来,打开DM8客户端,可通过dm sql脚本方式去创建表,这里只是简单创建了一张crm_version表。这里尤其需要注意的是创建表名不需要带双引号,达梦默认是大写,sql方言中也不需要额外处理,若是通过DM8工具去建表建字段或者带小写加双引号创建脚本,出现双引号则在实际的sql方言中也需要加上双引号,否则执行sql会抛出视图或表不存在,字段列名不存在的异常。
image.png
若是通过Mysql或Oracle或其他数据库,文件等方式迁移导入。这里记录一下迁移过程中遇到的问题,在迁移的时候,报某些字段超长。于是,查看了MySql中那些字段的类型及长度,都是varchar(50) 。这里应该是迁移有些字段,须在DM数据库中增加位宽,在MySql中varchar是表示字符,varchar(50)表示可以存放50个字符,但是DM的默认跟Oracle是一样的,varchar(50)表示50个字节。这就意味着,50个字节,如果存中文,在utf-8的字符集下,只能存最多16个。所以,如果MySql库到DM,varchar类型,需特别留意一下。
image.png
image.png

三、DM8&DmJdbcDriver
然后,在项目工程中引入达梦数据库驱动,SpringBoot对MySql做了集成,没有get到对达梦数据库做集成,小编这里采用的jdk1.8,安装的达梦数据库也是DM8,所以这里引入:
DmJdbcDriver18,其相对于DmJdbcDriver17作出了很大的改进。
i、本地引入的方式
在pom.xml文件中,引入jar版本依赖

<dependency>    
  <groupId>com.dm</groupId>    
   <artifactId>DmJdbcDriver18</artifactId>    
    <version>1.8</version>    
     <scope>system</scope>    
      <systemPath>${project.basedir}/src/main/resources/lib/DmJdbcDriver18.jar</systemPath>
</dependency>

image.png
ii、nexus私服引入的方式
在pom.xml文件中,引入jar版本依赖

<dependency>    
  <groupId>com.dm</groupId>    
   <artifactId>DmJdbcDriver18</artifactId>    
    <version>1.8</version>
</dependency>

image.png

说明:这里的groupId坐标参数,可由使用者自行在nexus中upload创建声明,然后在pom.xml中引入相关坐标即可。
扩展:若是需要从本地deploy到nexus或是先获取本地仓库.m2的包->nexus仓库的包->aliyun maven仓库的包,为了解决开发过程中jar包拉取异常等问题,则在maven中settings.xml中可这样去配置:

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"    
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
   xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">    
   <!-- 本地仓库 -->    
   <localRepository>D:/.m2</localRepository>    
   <mirrors>    
       <mirror>    
           <id>nexus</id>    
           <mirrorOf>*</mirrorOf>    
           <name>yd nexus</name>    
           <url>http://ip:port/repository/maven-public/</url>    
       </mirror>    
   </mirrors>
   <mirror>
    <id>alimaven</id>
    <mirrorOf>central</mirrorOf>
    <name>aliyun maven</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
   </mirror>   
   <profiles>    
       <profile>    
           <id>nexus</id>    
           <repositories>    
               <repository>    
                   <id>maven-snapshots</id>    
                   <url>http://ip:port/repository/maven-snapshots/</url>    
                   <releases><enabled>false</enabled></releases>    
                           <snapshots><enabled>true</enabled></snapshots>    
               </repository>    
               <repository>    
                   <id>maven-releases</id>    
                   <url>http://ip:port/repository/maven-releases/</url>    
                   <releases><enabled>true</enabled></releases>    
                           <snapshots><enabled>false</enabled></snapshots>    
               </repository>    
           </repositories>    
       </profile>    
   </profiles>    
   <servers>   
   <server>    
     <id>nexus</id>    
     <username>yxd179</username>    
     <password>yxd179</password>    
   </server>    
   <server>    
     <id>maven-releases</id>    
     <username>yxd179</username>    
     <password>yxd179</password>    
   </server>    
   <server>    
     <id>maven-snapshots</id>    
     <username>yxd179</username>    
     <password>yxd179</password>    
   </server>    
 </servers>    
 <activeProfiles>    
   <activeProfile>nexus</activeProfile>    
 </activeProfiles>    
</settings>

四、配置达梦数据库的信息
image.png

至此,达梦数据库环境安装,相关版本及其依赖的选取跟引入,配置信息完毕。

image.png

// 驱动-连接地址-账号-密码等信息
String driverClassName = "dm.jdbc.driver.DmDriver";
String url = "jdbc:dm://localhost:5236/";
String username = "yxd179";
String password = "yxd179";
// 加载驱动
Class.forName(driverClassName);
// 获取数据库连接对象
Connection con = (Connection) DriverManager.getConnection(url,username,password);
// 获取数据库操作对象
PreparesStatement ps = con.preparesStatement("SELECT COUNT(*) FROM TEST;");
// 执行sql
ResultSet rs= ps.executeQuery();
// 这里还可以获取到数据库产品名称
DatabaseMetaData metaData = (DatabaseMetaData) con.getMetaData();
// 这里为后续提到的在xml指定达梦的databaseId奠定基础
System.out.println("数据库产品名称:" + metaData.getDatabaseProductName());
最后需关闭连接close,释放资源->rs-ps-con. 

tk.mybatis:mybatis定制的第一大业务增强库。
pagehelper:分页控件,mybatis定制的第二大业务增强库。
image.png
其实,这都是需要我们care到的。当mybatis装配时,若是同一个方法被找到多条sql时,首先,会优先使用 databaseId 相同的 sql。若是没有 databaseId 相同的sql,其次,再使用未配置 databaseId 的 sql,而databaseId 未对应的 sql 不会使用。

(1)、当获取到的数据源信息为mysql,则执行图一中批量插入insertBatch方法;
image.png
(2)、当获取到的数据源信息为db2,则会去执行图二中批量插入insertBatch方法;
image.png
(3)、当获取到的数据源信息为oracle,则会去执行图三批量插入insertBatch方法。
image.png

这样我们就能极其简易的指定 databaseId,很多小伙伴肯定会说为什么需要这样去指定?其背后的原理又是怎样的,我们是否能够扩展并自定义 databaseId?框架这层的应用真能够提供的这么perfect吗?
在上一个Q-A中,我们已经get到了数据库产品的名称,可以从数据源连接对象中去获取,不妨从这里出发。这里先提出一点a little猜想,mybatis既然能够支持mysql,oracle,db2等等数据库,那么其他关系型数据库?肯定是提供一些这样的入口可以去扩展的,只是各种框架的适配程度不一样,都在不断兼容。
网上关于这块的资料并不全面,基于数据库产品名称这条线索,于是,小编封装了独立的适配器sdk,可作达梦等国产数据库适配。当然不同类型的数据库,后续在sdk中去扩展兼容都是可以做到的。
i、通过配置文件属性方式指定databaseId:

mybatis:
  mapper-locations: classpath*:mapper/**.xml
  configuration:
    database-id: dm8

ii、 通过configuration配置类,往容器注入Bean方式指定databaseId:

/**
 * @Auther: X.D.Yang
 * @Date: 2022/12/20 11:11
 * @Description:
 */
@Configuration
public class DatabasesConfig {
 
    private static final Logger logger = LoggerFactory.getLogger(DatabasesConfig.class);
 
    @Bean
    public DatabaseIdProvider getDatabaseIdProvider() {
        DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
        Properties p = new Properties();
        logger.info("Join DM8 databaseId Starting...");
        p.setProperty("DM DBMS", "dm8");
        //p.setProperty("MySQL", "mysql");
        databaseIdProvider.setProperties(p);
        logger.info("Join DM8 databaseId Start completed.");
        return databaseIdProvider;
    }
}

iii、mybatis-config.xml配置方式指定databaseId:

<databaseIdProvider type="DB_VENDOR">
   <property name="SQL Server" value="sqlserver"/>
   <property name="DB2" value="db2"/>
   <property name="Oracle" value="oracle" />
   <property name="DM DBMS" value="dm8" />
</databaseIdProvider>

至于小编封装的独立sdk,其主要思想结合SpringBoot-自动装配-条件配置:
@SpringBootApplication->@SpringBootConfiguration(@Configuration注解,声明为spring的配置类)、@EnableAutoConfigurationspringboot(启动最关键的注解)、@ComponentScan(对包进行扫描)

i、其中@EnableAutoConfiguration注解会读取所有classpath:META-INF/Spring.factories,取key为org.springframework.boot.autoconfigure.EnableAutoConfiguration下的所有value,注册到核心容器,完成自动配置类的加载。

读取:spring提供的工具类-SpringFactoriesLoader>>>第一个参数是个Class对象,决定读取的key,为class对象的全类名。第二个参数是ClassLoader对象,决定从哪里开始找这个文件,然后读取classpath:META-INF/spring.factories文件。
image.png
ii、自动配置类上有大量自动配置生效的条件,比如依赖是否被引入。springboot采用了默认代替配置的策略,当然也可更改默认配置,比如修改application.yml>yamlproperties配置文件,手动往容器中注册特定bean,注册一些实现特殊接口的类,比如实现WebMvcConfigurer接口的类。自动配置即向容器注册组件,实现了特殊接口的组件,影响spring的生命周期。

/**
 * @Auther: X.D.Yang
 * @Date: 2022/12/20 11:16
 * @Description:
 */
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getLoggedInterceptor()).addPathPatterns("/**");
        super.addInterceptors(registry);
    }
 
    @Bean
    public LoggedInterceptor getLoggedInterceptor() {
        return new LoggedInterceptor();
    }
}
@Configuration
public class YdWebMvcConfigurer implements WebMvcConfigurer {

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        RequestJsonHandlerMethodArgumentResolver resolver = new RequestJsonHandlerMethodArgumentResolver();
        //利用工厂给容器外的对象注入所需组件
        applicationContext.getAutowireCapableBeanFactory().autowireBean(resolver);
        argumentResolvers.add(resolver);
    }
}

其中,

@ConditionalOnClass:一些类是否存在当前类路径下。

@ConditionalOnProperty:相应的配置字段满足。

@ConditionalOnMissingBean:容器中没有某个bean。

这里我们着重看一下mybatis提供的自动配置包-MybatisAutoConfiguration,生效条件:需引入mybatis相关的依赖,核心容器中只有一个DataSource,在DataSource自动配置完成后才生效等等条件,并且还开启了配置类@EnableConfigurationProperties(MybatisProperties.class)

image.png
上述构造方法:当前对象被实例化时,会被注入一系列的bean-MybatisProperties对象…

iii、mybatis为我们注册了SqlSessionFactory,SqlSessionTemplate,以及为每个@Mapper注册了一个Mapper实现类-MyBatis->@Autowired注入一个Mapper。

当我们自己为容器中注入SqlSessionFactory对象,从容器中取dataSource(当引入spring-boot-starter-jdbc时会自动配置)作为参数,创建一个SqlSessionFactoryBean对象,该对象是个工厂-生产SqlSessionFactory,这里通过SqlSessionFactoryBean对象的一系列set方法,最后调用getObject方法来获取到SqlSessionFactory对象。其中生成SqlSessionFactory需要的Configuration对象,这里也可以取代mybatis的主配置文件-sqlSessionFactoryBean.setConfiguration方法。

image.png
image.png
而SqlSessionTemplate的创建,则取上述注入的SqlSessionFactory,new SqlSessionTemplate对象即可。至于对MyBatis源码Debug有兴趣的可以参考小编之前的文章>对Mybatis源码的认识_yxd179的博客。

记录:在适配的过程中还试出了达梦的幻读,达梦和Oracle一样默认的隔离级别都是读提交;还有特别需要注意的就是,在数据库中varchar类型的字段,比如在mysql中定义varchar(50),在写满的情况下为50个字符,到了达梦这边最多也就是varchar(150),当然可自行指定位宽,小编用的字符集是UTF-8,每个字符占三个字节,乘以三倍,就肯定是装得下的,详情请参考小编之前撰写的CSDN博文+公众号文章,目前达梦适配现有的框架为:SpringBoot+HiKari+MyBatis3.4.6+tk.MyBatis+PageHelper

https://blog.csdn.net/yxd179/article/details/115665824

Ok,Now,接入sdk适配后,启动的效果,大致如下:
image.png
这里,主要对sql分页查询作下阐述:简单的分页可通过手写sql limit…,首先统计count总数,然后计算分页等相关信息,这里不着重说明,当然sql分页控件也是可以去扩展的。PageHelper分页,其主要原理:首先将传递的参数设置到page这个对象中去,然后会接着将page的副本存放入ThreadLoacl中,保证分页时参数互不影响,通过mybatis提供的拦截器,获取ThreadLocal中的值,重新拼装分页sql语句。

接入之后,我们在控制台输出dm sql日志,看一下打印的sql-伪列分页:
image.png
在DM8中正常执行sql,获取结果集:
image.png
而在MySql中,简单limit分页输出是这样的:
image.png
<附注>Debug分页控件源码,其实也很容易理解,分页最终是这样去拼装的:

protected BoundSql getPageBoundSql(Object parameterObject) {
    String tempSql = sql;
    String orderBy = PageHelper.getOrderBy();
    if (orderBy != null) {
        tempSql = OrderByParser.converToOrderBySql(sql, orderBy);
    }
    tempSql = localParser.get().getPageSql(tempSql);
    return new BoundSql(configuration, tempSql, localParser.get().getPageParameterMapping(configuration, original.getBoundSql(parameterObject)), parameterObject);
}

image.png

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
2人已赞赏
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论