注册
达梦Loginmode模式解析
专栏/技术分享/ 文章详情 /

达梦Loginmode模式解析

DM_738629 2026/09/30 222 1 0
摘要

LoginMode优先级规则

概念

LoginMode:作用于 JDBC、dm_svc.conf 等客户端配置,指定优先登录的服务器模式。定义客户端节点筛选、连接优先级规则,

规则区别

LoginMode取值范围 0~4,缺省为 4。

LoginMode = 0:优先连接 PRIMARY 模式的库,NORMAL 模式次之,最后选择 STANDBY 模式;

LoginMode = 1:只连接主库;

LoginMode = 2:只连接备库;

LoginMode = 3:优先连接 STANDBY 模式的库,PRIMARY 模式次之,最后选择 NORMAL 模式;

LoginMode = 4:优先连接 NORMAL 模式的库,PRIMARY 模式次之,最后选择 STANDBY 模式;

单库模式下连接逻辑

LoginMode 连接匹配逻辑 连接结果
0 PRIMARY>NORMAL>STANDBY 连接成功
1 仅允许 PRIMARY,单机无主库角色 连接失败
2 仅允许 STANDBY,单机无备库角色 连接失败
3 STANDBY>PRIMARY>NORMAL 连接成功
4 优先级最高匹配 NORMAL 单机 连接成功

jdbc测试代码

package java_jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class jdbc_login {
    static String jdbcString = "dm.jdbc.driver.DmDriver";
    static String urlString = "jdbc:dm://DM_SVC?logLevel=all&logDir=D:\\资料\\达梦\\jdbclog";
    static String userName = "SYSDBA";
    static String password = "DMdata456";

    static Connection conn = null;

    public static void main(String[] args) {
        try {
            System.out.println("Loading JDBC Driver...");
            Class.forName(jdbcString);

            System.out.println("Connect via dm_svc.conf service name [DM_SVC] ...");
            conn = DriverManager.getConnection(urlString, userName, password);
            System.out.println("=== 连接建立成功 ===");

            printConnectionInfo(conn);
            keepAliveLoop(conn);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            System.err.println("数据库连接异常:");
            e.printStackTrace();
        } finally {
            closeResource();
        }
    }

    /**
     * 查询实例、会话信息
     */
    public static void printConnectionInfo(Connection conn) throws SQLException {
        if(conn == null || conn.isClosed()){
            System.out.println("当前连接已关闭");
            return;
        }
        Statement stmt = conn.createStatement();
        // SESSID() 获取当前会话ID
        String sql = "SELECT i.NAME, i.MODE$, s.SESS_ID " +
                "FROM V$INSTANCE i, V$SESSIONS s " +
                "WHERE s.SESS_ID = SESSID()";
        ResultSet rs = stmt.executeQuery(sql);
        while (rs.next()){
            String instName = rs.getString("NAME");
            String modeStr = rs.getString("MODE$");
            long sessionId = rs.getLong("SESS_ID");

            System.out.println("实例名称      : " + instName);
            System.out.println("实例MODE$角色: " + modeStr);
            System.out.println("当前会话SESS_ID : " + sessionId);
        }
        rs.close();
        stmt.close();
    }

    public static void keepAliveLoop(Connection conn){
        System.out.println("\n进入保活等待循环,每隔5s执行探测SQL;手动终止程序结束。");
        System.out.println("提示:空闲sleep不会自动切换;只有执行SQL才触发故障切换逻辑。\n");
        Connection localConn = conn;
        while(true){
            try {
                if(localConn.isClosed()){
                    System.out.println("连接已经关闭,尝试重新获取连接...");
                    localConn = DriverManager.getConnection(urlString, userName, password);
                    System.out.println("重连成功!");
                    printConnectionInfo(localConn);
                }
                Statement st = localConn.createStatement();
                st.execute("select 1");
                st.close();
                System.out.printf("[%tT] 链路探测正常,当前角色:%s%n",System.currentTimeMillis(), getCurrentMode(localConn));
                Thread.sleep(5000);
            } catch (SQLException e) {
                System.err.printf("[%tT] 链路出现SQLException: %s%n",System.currentTimeMillis(),e.getMessage());
            } catch (InterruptedException e) {
                System.out.println("线程被中断,退出等待循环");
                break;
            }
        }
    }

    private static String getCurrentMode(Connection conn) {
        String mode = "unknown";
        try(Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("SELECT MODE$ FROM V$INSTANCE")){
            if(rs.next()){
                mode = rs.getString(1);
            }
        } catch (SQLException ignored) {}
        return mode;
    }

    public static void closeResource(){
        try {
            if(conn != null && !conn.isClosed()){
                conn.close();
            }
            System.out.println("\n资源已关闭");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

dm_svc.conf配置如下:

TIME_ZONE=(480)
LANGUAGE=(cn)
DM_SVC=(192.168.43.3:5234)

[DM_SVC]
LOGIN_MODE=(4)
SWITCH_TIMES=(5)
SWITCH_INTERVAL=(300)

修改LOGIN_MODE参数测试

login_mode=1 or 2时,不能连接单库

image20260827124856491.png

login_mode=0,3,4时可以正常连接

image20260827125006506.png

主备模式下连接逻辑

dm_svc.conf配置如下:

TIME_ZONE=(480)
LANGUAGE=(cn)
# 填入你的集群/单机节点IP端口,这里示例服务名叫 DM_SVC
DM_SVC=(192.168.43.4:5236,192.168.43.5:5236)

[DM_SVC]
LOGIN_MODE=(0)     ## primary>normal>standby
SWITCH_TIMES=(5)
SWITCH_INTERVAL=(300)

修改LOGIN_MODE参数测试

login_mode=0 时

优先连接主库

image20260827145546891.png

若主库异常关闭,则进行重连,连接备库

image20260827145706986.png

login_mode=1 时,只连接主库

image20260827150627935.png

此时,重连并不会连接到备库中

image20260827150751484.png

login_mode=2 时,只连接备库

image20260827150944836.png

同理,此时,重连并不会连接到主库中

login_mode=3 时,standby>primary>normal
image20260827151149086.png

若备库异常关闭,则进行重连,连接主库

image20260827151331902.png

中途若备库恢复,则连接指向备库

image20260827151649554.png

login_mode=4 时,normal>primary>standby,验证逻辑同上。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服