SQLServer数据库返回错误的国际化

  前段时间测试提了一个BUG,我们繁体环境报错的提示是简体的,经查询之后这个错误是SQLServer抛出的,代码只是进行了异常转换,没有把异常信息换掉,在进行异常信息转换后,我又想,会不会有其他地方SQLServer的异常也没有转换,这个我没有办法去进行代码的全部扫描查询(即使进行了,也很难保证后面的同事不会再写),那我退而求其次,信息没转换我最起码能让用户看到的报错提示信息的语种是没有问题的,不能英语环境看到的是中文的报错。这个问题之前没有处理过也没有想过,于是只能自己摸索,经过查阅资料首先知道了这种情况在生产环境中基本不太可能出现,因为SQLServer默认给出的错误提示信息语言是和SQLServer环境有关的,英文生产环境下不太可能连接一个中文环境的数据库吧。

  但是好奇心重的我还是想看一下有没有代码的方式可以解决这个问题,结果还真找到了。首先想到的就是驱动,驱动中有没有这么一个参数可以配置呢?查看Driver类,找到一个类似的

public static final String LANGUAGE      = "prop.language";

只有这个常量看着是和语言有关系的,不能确定,也不知道怎么修改,那么第一步,先看下Driver是如何获取connection的,看Driver的connect方法

public Connection connect(String url, Properties info)
        throws SQLException  {
        if (url == null || !url.toLowerCase().startsWith(driverPrefix)) {
            return null;
        }

        Properties props = setupConnectProperties(url, info);

        if (JDBC3) {
            return new ConnectionJDBC3(url, props);
        }

        return new ConnectionJDBC2(url, props);
    }

而ConnectionJDBC3是继承自ConnectionJDBC2,构造只是调用了ConnectionJDBC2的构造,ConnectionJDBC2的构造代码如下

ConnectionJDBC2(String url, Properties info)
            throws SQLException {
        this.url = url;
        //
        // Extract properties into instance variables
        //
        unpackProperties(info);
        this.messages = new SQLDiagnostic(serverType);
        //
        // Get the instance port, if it is specified.
        // Named pipes use instance names differently.
        //
        if (instanceName.length() > 0 && !namedPipe) {
            final MSSqlServerInfo msInfo = new MSSqlServerInfo(serverName);

            portNumber = msInfo.getPortForInstance(instanceName);

            if (portNumber == -1) {
                throw new SQLException(
                                      Messages.get("error.msinfo.badinst", serverName, instanceName),
                                      "08003");
            }
        }

        SharedSocket.setMemoryBudget(bufferMaxMemory * 1024);
        SharedSocket.setMinMemPkts(bufferMinPackets);
        SQLWarning warn;

        try {
            Object timer = null;
            if (loginTimeout > 0) {
                // Start a login timer
                timer = TimerThread.getInstance().setTimer(loginTimeout * 1000,
                        new TimerThread.TimerListener() {
                            public void timerExpired() {
                                if (socket != null) {
                                    socket.forceClose();
                                }
                            }
                        });
            }

            if (namedPipe) {
                // Use named pipe
                socket = createNamedPipe(this);
            } else {
                // Use plain TCP/IP socket
                socket = new SharedSocket(this);
            }

            if (timer != null && TimerThread.getInstance().hasExpired(timer)) {
                // If the timer has expired during the connection phase, close
                // the socket and throw an exception
                socket.forceClose();
                throw new IOException("Login timed out");
            }

            if ( charsetSpecified ) {
                loadCharset(serverCharset);
            } else {
                // Need a default charset to process login packets for TDS 4.2/5.0
                // Will discover the actual serverCharset later
                loadCharset("iso_1");
                serverCharset = ""; // But don‘t send charset name to server!
            }

            //
            // Create TDS protocol object
            //
            baseTds = new TdsCore(this, messages);

            //
            // Negotiate SSL connection if required
            //
            if (tdsVersion >= Driver.TDS80 && !namedPipe) {
                baseTds.negotiateSSL(instanceName, ssl);
            }

            //
            // Now try to login
            //
            baseTds.login(serverName,
                          databaseName,
                          user,
                          password,
                          domainName,
                          serverCharset,
                          appName,
                          progName,
                          wsid,
                          language,
                          macAddress,
                          packetSize);

            if (timer != null) {
                // Cancel loginTimer
                TimerThread.getInstance().cancelTimer(timer);
            }

            //
            // Save any login warnings so that they will not be overwritten by
            // the internal configuration SQL statements e.g. setCatalog() etc.
            //
            warn = messages.warnings;

            // Update the tdsVersion with the value in baseTds. baseTds sets
            // the TDS version for the socket and there are no other objects
            // with cached TDS versions at this point.
            tdsVersion = baseTds.getTdsVersion();
            if (tdsVersion < Driver.TDS70 && databaseName.length() > 0) {
                // Need to select the default database
                setCatalog(databaseName);
            }
        } catch (UnknownHostException e) {
            throw Support.linkException(
                    new SQLException(Messages.get("error.connection.badhost",
                            e.getMessage()), "08S03"), e);
        } catch (IOException e) {
            if (loginTimeout > 0 && e.getMessage().indexOf("timed out") >= 0) {
                throw Support.linkException(
                        new SQLException(Messages.get("error.connection.timeout"), "HYT01"), e);
            }
            throw Support.linkException(
                    new SQLException(Messages.get("error.connection.ioerror",
                            e.getMessage()), "08S01"), e);
        } catch (SQLException e) {
            if (loginTimeout > 0 && e.getMessage().indexOf("socket closed") >= 0) {
                throw Support.linkException(
                        new SQLException(Messages.get("error.connection.timeout"), "HYT01"), e);
            }

            throw e;
        }

        // If charset is still unknown and the collation is not set either,
        // determine the charset by querying (we‘re using Sybase or SQL Server
        // 6.5)
        if ((serverCharset == null || serverCharset.length() == 0)
                && collation == null) {
            loadCharset(determineServerCharset());
        }

        // Initial database settings.
        // Sets: auto commit mode  = true
        //       transaction isolation = read committed.
        if (serverType == Driver.SYBASE) {
            baseTds.submitSQL(SYBASE_INITIAL_SQL);
        } else {
            // Also discover the maximum decimal precision:  28 (default)
            // or 38 for MS SQL Server 6.5/7, or 38 for 2000 and later.
            Statement stmt = this.createStatement();
            ResultSet rs = stmt.executeQuery(SQL_SERVER_INITIAL_SQL);

            if (rs.next()) {
                maxPrecision = rs.getByte(1);
            }

            rs.close();
            stmt.close();
        }

        //
        // Restore any login warnings so that the user can retrieve them
        // by calling Connection.getWarnings()
        //
        messages.warnings = warn;
    }
protected void unpackProperties(Properties info)        throws SQLException {

    serverName = info.getProperty(Messages.get(Driver.SERVERNAME));    portNumber = parseIntegerProperty(info, Driver.PORTNUMBER);    serverType = parseIntegerProperty(info, Driver.SERVERTYPE);    databaseName = info.getProperty(Messages.get(Driver.DATABASENAME));    instanceName = info.getProperty(Messages.get(Driver.INSTANCE));    domainName = info.getProperty(Messages.get(Driver.DOMAIN));    user = info.getProperty(Messages.get(Driver.USER));    password = info.getProperty(Messages.get(Driver.PASSWORD));    macAddress = info.getProperty(Messages.get(Driver.MACADDRESS));    appName = info.getProperty(Messages.get(Driver.APPNAME));    progName = info.getProperty(Messages.get(Driver.PROGNAME));    wsid = info.getProperty(Messages.get(Driver.WSID));    serverCharset = info.getProperty(Messages.get(Driver.CHARSET));    language = info.getProperty(Messages.get(Driver.LANGUAGE));    lastUpdateCount = "true".equalsIgnoreCase(            info.getProperty(Messages.get(Driver.LASTUPDATECOUNT)));    useUnicode = "true".equalsIgnoreCase(            info.getProperty(Messages.get(Driver.SENDSTRINGPARAMETERSASUNICODE)));    namedPipe = "true".equalsIgnoreCase(            info.getProperty(Messages.get(Driver.NAMEDPIPE)));    tcpNoDelay = "true".equalsIgnoreCase(            info.getProperty(Messages.get(Driver.TCPNODELAY)));    useCursors = (serverType == Driver.SQLSERVER)            && "true".equalsIgnoreCase(                    info.getProperty(Messages.get(Driver.USECURSORS)));    useLOBs = "true".equalsIgnoreCase(            info.getProperty(Messages.get(Driver.USELOBS)));    useMetadataCache = "true".equalsIgnoreCase(            info.getProperty(Messages.get(Driver.CACHEMETA)));    xaEmulation = "true".equalsIgnoreCase(            info.getProperty(Messages.get(Driver.XAEMULATION)));    charsetSpecified = serverCharset.length() > 0;

    Integer parsedTdsVersion =            DefaultProperties.getTdsVersion(info.getProperty(Messages.get(Driver.TDS)));    if (parsedTdsVersion == null) {        throw new SQLException(Messages.get("error.connection.badprop",                Messages.get(Driver.TDS)), "08001");    }    tdsVersion = parsedTdsVersion.intValue();

    packetSize = parseIntegerProperty(info, Driver.PACKETSIZE);    if (packetSize < TdsCore.MIN_PKT_SIZE) {        if (tdsVersion >= Driver.TDS70) {            // Default of 0 means let the server specify packet size            packetSize = (packetSize == 0) ? 0 : TdsCore.DEFAULT_MIN_PKT_SIZE_TDS70;        } else if (tdsVersion == Driver.TDS42) {            // Sensible minimum for older versions of TDS            packetSize = TdsCore.MIN_PKT_SIZE;        } // else for TDS 5 can auto negotiate    }    if (packetSize > TdsCore.MAX_PKT_SIZE) {        packetSize = TdsCore.MAX_PKT_SIZE;    }    packetSize = (packetSize / 512) * 512;

    loginTimeout = parseIntegerProperty(info, Driver.LOGINTIMEOUT);    socketTimeout = parseIntegerProperty(info, Driver.SOTIMEOUT);    lobBuffer = parseLongProperty(info, Driver.LOBBUFFER);

    maxStatements = parseIntegerProperty(info, Driver.MAXSTATEMENTS);

    statementCache = new ProcedureCache(maxStatements);    prepareSql = parseIntegerProperty(info, Driver.PREPARESQL);    if (prepareSql < 0) {        prepareSql = 0;    } else if (prepareSql > 3) {        prepareSql = 3;    }    // For Sybase use equivalent of sp_executesql.    if (tdsVersion < Driver.TDS70 && prepareSql == TdsCore.PREPARE) {        prepareSql = TdsCore.EXECUTE_SQL;    }    // For SQL 6.5 sp_executesql not available so use stored procedures.    if (tdsVersion < Driver.TDS50 && prepareSql == TdsCore.EXECUTE_SQL) {        prepareSql = TdsCore.TEMPORARY_STORED_PROCEDURES;    }

    ssl = info.getProperty(Messages.get(Driver.SSL));

    batchSize = parseIntegerProperty(info, Driver.BATCHSIZE);    if (batchSize < 0) {        throw new SQLException(Messages.get("error.connection.badprop",                Messages.get(Driver.BATCHSIZE)), "08001");    }

    bufferMaxMemory = parseIntegerProperty(info, Driver.BUFFERMAXMEMORY);    if (bufferMaxMemory < 0) {        throw new SQLException(Messages.get("error.connection.badprop",                Messages.get(Driver.BUFFERMAXMEMORY)), "08001");    }

    bufferMinPackets = parseIntegerProperty(info, Driver.BUFFERMINPACKETS);    if (bufferMinPackets < 1) {        throw new SQLException(Messages.get("error.connection.badprop",                Messages.get(Driver.BUFFERMINPACKETS)), "08001");    }}
 

至此,如果所猜测没有错,我们应该给Driver的connetion方法传入Properties,key是Messages.get(Driver.LANGUAGE),value是我们希望SQLServer数据库返回给我们的信息的语种。

但是Driver的方法我们是没有办法直接去调用的,我们能操作的只有数据源。

下一步,查询一下获取连接的代码,我们自定义的dataSource是继承BasicDataSource(org.apache.commons.dbcp)的,查看BasicDataSource的getConnection方法

/**
     * Create (if necessary) and return a connection to the database.
     *
     * @throws SQLException if a database access error occurs
     * @return a database connection
     */
    public Connection getConnection() throws SQLException {
        return createDataSource().getConnection();
    }
protected synchronized DataSource createDataSource()    throws SQLException {    if (closed) {        throw new SQLException("Data source is closed");    }

    // Return the pool if we have already created it    if (dataSource != null) {        return (dataSource);    }

    // create factory which returns raw physical connections    ConnectionFactory driverConnectionFactory = createConnectionFactory();

    // create a pool for our connections    createConnectionPool();

    // Set up statement pool, if desired    GenericKeyedObjectPoolFactory statementPoolFactory = null;    if (isPoolPreparedStatements()) {        statementPoolFactory = new GenericKeyedObjectPoolFactory(null,                    -1, // unlimited maxActive (per key)                    GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,                    0, // maxWait                    1, // maxIdle (per key)                    maxOpenPreparedStatements);    }

    // Set up the poolable connection factory    createPoolableConnectionFactory(driverConnectionFactory, statementPoolFactory, abandonedConfig);

    // Create and return the pooling data source to manage the connections    createDataSourceInstance();

    try {        for (int i = 0 ; i < initialSize ; i++) {            connectionPool.addObject();        }    } catch (Exception e) {        throw new SQLNestedException("Error preloading the connection pool", e);    }

    return dataSource;}
protected ConnectionFactory createConnectionFactory() throws SQLException {    // Load the JDBC driver class    Class driverFromCCL = null;    if (driverClassName != null) {        try {            try {                if (driverClassLoader == null) {                    Class.forName(driverClassName);                } else {                    Class.forName(driverClassName, true, driverClassLoader);                }            } catch (ClassNotFoundException cnfe) {                driverFromCCL = Thread.currentThread(                        ).getContextClassLoader().loadClass(                                driverClassName);            }        } catch (Throwable t) {            String message = "Cannot load JDBC driver class ‘" +                driverClassName + "‘";            logWriter.println(message);            t.printStackTrace(logWriter);            throw new SQLNestedException(message, t);        }    }

    // Create a JDBC driver instance    Driver driver = null;    try {        if (driverFromCCL == null) {            driver = DriverManager.getDriver(url);        } else {            // Usage of DriverManager is not possible, as it does not            // respect the ContextClassLoader            driver = (Driver) driverFromCCL.newInstance();            if (!driver.acceptsURL(url)) {                throw new SQLException("No suitable driver", "08001");             }        }    } catch (Throwable t) {        String message = "Cannot create JDBC driver of class ‘" +            (driverClassName != null ? driverClassName : "") +            "‘ for connect URL ‘" + url + "‘";        logWriter.println(message);        t.printStackTrace(logWriter);        throw new SQLNestedException(message, t);    }

    // Can‘t test without a validationQuery    if (validationQuery == null) {        setTestOnBorrow(false);        setTestOnReturn(false);        setTestWhileIdle(false);    }

    // Set up the driver connection factory we will use    String user = username;    if (user != null) {        connectionProperties.put("user", user);    } else {        log("DBCP DataSource configured without a ‘username‘");    }

    String pwd = password;    if (pwd != null) {        connectionProperties.put("password", pwd);    } else {        log("DBCP DataSource configured without a ‘password‘");    }

    ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driver, url, connectionProperties);    return driverConnectionFactory;}
 

关注红色代码,发现最终会new 一个DriverConnectionFactory

public class DriverConnectionFactory implements ConnectionFactory {
    public DriverConnectionFactory(Driver driver, String connectUri, Properties props) {
        _driver = driver;
        _connectUri = connectUri;
        _props = props;
    }

    public Connection createConnection() throws SQLException {
        return _driver.connect(_connectUri,_props);
    }

    protected Driver _driver = null;
    protected String _connectUri = null;
    protected Properties _props = null;

    public String toString() {
        return this.getClass().getName() + " [" + String.valueOf(_driver) + ";" + String.valueOf(_connectUri) + ";"  + String.valueOf(_props) + "]";
    }
}

我们可以看到,其实最终调用的还是Driver的connection方法来产生连接,而这个方法会把props给传进去,所以我们的目标就变为了给connectionProperties给增加键值对,而BasicDataSource中确实有这么个方法

public void addConnectionProperty(String name, String value) {
        connectionProperties.put(name, value);
        this.restartNeeded = true;
    }

接下来就简单了,只需要在继承类中调用这个方法就可以了,KEY值已确定,VALUE值查询SQLServer相关文档很容易获取到。

PS:如果没有写继承类,也可以使用xml定义,例如:<property name=“connectionProperties” value="LANGUAGE=简体中文"/>,如果存在多个需要配置的属性,使用英文分号隔开即可。我使用继承类来写主要是我只希望是SQLServer环境的时候这个参数才起作用,使用代码实现比较方便,XML怎么实现不是特别清楚。

那么只剩下最后一步了,测试我们的猜测是否正确,幸运的是我们的猜测完全正确((〃‘▽‘〃))。其实不正确也没关系,理论上来说只要驱动提供了这个功能我们应该就是可以这么设置的,只不过KEY可能猜错了,换其他的KEY试一下就好了。

原文地址:https://www.cnblogs.com/fiftyonesteps/p/11417827.html

时间: 2024-11-02 04:43:16

SQLServer数据库返回错误的国际化的相关文章

sqlserver数据库18456错误怎么解决?

1.以windows验证模式进入数据库管理器. 2.右击sa,选择属性: 在常规选项卡中,重新填写密码和确认密码(改成个好记的).把强制实施密码策略去掉. 3.点击状态选项卡:勾选授予和启用.然后确定 4.右击实例名称(就是下图画红线的部分),选择属性. 5.点安全性,确认选择了SQL SERVER 和Windows身份验证模式. 6.重启SQLSERVER服务(重要).

java.sql.SQLException: 无法转换为内部表示 -〉java 查询oracle数据库返回错误信息

java.sql.SQLException: 无法转换为内部表示 Query: SELECT * FROM  nontheasttycoon Parameters: []    at org.apache.commons.dbutils.AbstractQueryRunner.rethrow(AbstractQueryRunner.java:392) ~[commons-dbutils-1.6.jar:1.6]    at org.apache.commons.dbutils.QueryRunn

VB语言使用ADO连接、操作SQLServer数据库教程

VB语言使用ADO连接.操作SQLServer数据库教程 这篇文章主要介绍了VB语言使用ADO连接.操作SQLServer数据库教程,本文讲解详细.代码中有大量注释,是非常好的一篇教程,需要的朋友可以参考下 几年前学过的VB几乎忘光了,这几天复习了下.VB连接ADO数据库并不是非常难. 连接第一步(要仔细看) 对于小白来讲,这里的教程最详细,连接ADO数据库第一步,要添加什么部件呢?全称是Microsoft ADO Data Control 6.0 (SP6) (OLEDB) 部件. 在Micr

SQLServer数据库查询优化建议

虽然查询速度慢的原因很多,但是如果通过一定的优化,也可以使查询问题得到一定程度的解决. 查询速度慢的原因很多,常见如下几种: 1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) 2.I/O吞吐量小,形成了瓶颈效应. 3.没有创建计算列导致查询不优化. 4.内存不足 5.网络速度慢 6.查询出的数据量过大(可以采用多次查询,其他的方法降低数据量) 7.锁或者死锁(这也是查询慢最常见的问题,是程序设计的缺陷) 8.sp_lock,sp_who,活动的用户查看,原因是读写竞争资源

php+sqlserver之如何操作sqlserver数据库

https://blog.csdn.net/xia13100004562/article/details/58598872 2016年12月19日 17:15:39 阅读数:6790 前面已经基本配置了sqlserver的环境,现在就用学习一下如何去操作数据库!!其实方法还是比较简单,可以参考一下mysql,尽量去跟mysql进行比较 1.学习的方法,最好是看手册 在前一篇文章中涉及到了连接数据库sqlsrv_connect();还记得我们mysql连接数据库的时候也是mysql_connect

SQLServer数据库自增长标识列的更新修改操作

SQLServer数据库自增长标识列的更新修改操作方法在日常的sql server开发中,经常会用到Identity类型的标识列作为一个表结构的自增长编号.比如文章编号.记录序号等等.自增长的标识列的引用很大程度上方便了数据库程序的开发,但是有时这个固执的字段类型也会带来一些麻烦. 一.修改标识列字段的值:(在执行insert时,将ID手动的设置成想要的值)有时,为了实现某个功能,需要修改类型为Identity自增长类型的字段的值,但由于标识的类型所限,这种操作默认是不允许的.比如,目前数据库有

JavaWeb程序连接SQLserver数据库

声明:一直以来都以为javaweb程序连接数据库是一个很高大上很难的问题,结果今天学习了一下,不到两个小时就解决了,所以总结一篇博客. JavaWeb程序连接SQLserver数据库分为一下步骤: 1:在http://www.microsoft.com/en-us/download/details.aspx?id=21599下载sqljdbc.jar的压缩包 2:解压之后,将sqljdbc4.jar复制粘贴到你项目的WEB-INF的lib目录下 3:需要知道一些数据库方面的技术知识: 先举个例子

开启SQLSERVER数据库缓存依赖优化网站性能

很多时候,我们服务器的性能瓶颈会是在查询数据库的时候,所以对数据库的缓存非常重要,那么有没有一种方法,可以实现SQL SERVER数据库的缓存,当数据表没有更新时,就从缓存中读取,当有更新的时候,才从数据表中读取呢,答案是肯定的,这样的话我们对一些常用的基础数据表就可以缓存起来,比如做新闻系统的新闻类别等,每次就不需要从数据库中读取了,加快网站的访问速度. 那么如何开启SQLSERVER数据库缓存依赖,方法如下: 第一步:修改Web.Config的<system.web>节的配置,代码如下,让

Win7 sql2005附加数据库失败 错误5120

错误信息如下: 标题: Microsoft SQL Server Management Studio Express------------------------------ 附加数据库 对于 服务器“TITANIC-PC/SQLEXPRESS”失败. (Microsoft.SqlServer.Express.Smo) 有关帮助信息,请单击: http://go.microsoft.com/fwlink?ProdName=Microsoft+SQL+Server&ProdVer=9.00.30