iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >详解Spring不同数据库异常如何抽象的
  • 341
分享到

详解Spring不同数据库异常如何抽象的

2024-04-02 19:04:59 341人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录前言代码实现处理流程图用到了哪些设计模式?组合模式单例模式策略模式总结:前言 使用spring-Jdbc的情况下,在有些场景中,我们需要根据数据库报的异常类型的不同,来编写我们

前言

使用spring-Jdbc的情况下,在有些场景中,我们需要根据数据库报的异常类型的不同,来编写我们的业务代码。比如说,我们有这样一段逻辑,如果我们新插入的记录,存在唯一约束冲突,就会返回给客户端描述:记录已存在,请勿重复操作

代码一般是这么写的:


@Resource
private JdbcTemplate jdbcTemplate;
public String testAdd(){
    try {
        jdbcTemplate.execute("INSERT INTO user_info (user_id, user_name, email, nick_name, status, address) VALUES (80002, '张三丰', 'xxx@126.com', '张真人', 1, '武当山');");
        return "OK";
    }catch (DuplicateKeyException e){
        return "记录已存在,请勿重复操作";
    }
}

测试一下:

如上图提示,并且无论什么更换什么数据库(Spring-Jdbc支持的),代码都不用改动

那么Spring-Jdbc是在使用不同数据库时,Spring如何帮我们实现对异常的抽象的呢?

代码实现

我们来正向看下代码:

首先入口JdbcTemplate.execute方法:


public void execute(final String sql) throws DataAccessException {
    if (this.logger.isDebugEnabled()) {
        this.logger.debug("Executing SQL statement [" + sql + "]");
    }
    ...
    //实际执行入口,调用内部方法
    this.execute(new ExecuteStatementCallback(), true);
}

内部方法execute


@Nullable
private <T> T execute(StatementCallback<T> action, boolean closeResources) throws DataAccessException {
    Assert.notNull(action, "Callback object must not be null");
    Connection con = DataSourceUtils.getConnection(this.obtainDataSource());
    Statement stmt = null;

    Object var12;
    try {
	...
    } catch (SQLException var10) {
        ....
	//SQL出现异常后,所有的异常在这里进行异常转换
        throw this.translateException("StatementCallback", sql, var10);
    } finally {
        if (closeResources) {
            JdbcUtils.closeStatement(stmt);
            DataSourceUtils.releaseConnection(con, this.getDataSource());
        }

    }

    return var12;
}

异常转换方法translateException


protected DataAccessException translateException(String task, @Nullable String sql, SQLException ex) {
	//获取异常转换器,然后根据数据库返回码相关信息执行转换操作
	//转换不成功,也有兜底异常UncateGorizedSQLException
    DataAccessException dae = this.getExceptionTranslator().translate(task, sql, ex);
    return (DataAccessException)(dae != null ? dae : new UncategorizedSQLException(task, sql, ex));
}

获取转换器方法getExceptionTranslator


public SQLExceptionTranslator getExceptionTranslator() {
    //获取转换器属性,如果为空,则生成一个
    SQLExceptionTranslator exceptionTranslator = this.exceptionTranslator;
    if (exceptionTranslator != null) {
        return exceptionTranslator;
    } else {
        synchronized(this) {
            SQLExceptionTranslator exceptionTranslator = this.exceptionTranslator;
		if (exceptionTranslator == null) {
                DataSource dataSource = this.getDataSource();
                //shouldIgnoreXml是一个标记,就是不通过xml加载bean,默认false
		if (shouldIgnoreXml) {
                    exceptionTranslator = new SQLExceptionSubclassTranslator();
                } else if (dataSource != null) {
		//如果DataSource不为空,则生成转换器SQLErrorCodeSQLExceptionTranslator,一般情况下首先获取到该转换器
                    exceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(dataSource);
                } else {
		// 其他情况,生成SQLStateSQLExceptionTranslator转换器
                    exceptionTranslator = new SQLStateSQLExceptionTranslator();
                }

                this.exceptionTranslator = (SQLExceptionTranslator)exceptionTranslator;
            }
            return (SQLExceptionTranslator)exceptionTranslator;
        }
    }
}

转换方法:

因为默认的转换器是SQLErrorCodeSQLExceptionTranslator,所以这里调用SQLErrorCodeSQLExceptionTranslator的doTranslate方法

类图调用关系如上,实际先调用的是AbstractFallbackSQLExceptionTranslator.translate的方法


@Nullable
public DataAccessException translate(String task, @Nullable String sql, SQLException ex) {
    Assert.notNull(ex, "Cannot translate a null SQLException");
		//这里才真正调用SQLErrorCodeSQLExceptionTranslator.doTranslate方法
    DataAccessException dae = this.doTranslate(task, sql, ex);
    if (dae != null) {
        return dae;
    } else {
		    //如果没有找到响应的异常,则调用其他转换器,输入递归调用,这里后面说
        SQLExceptionTranslator fallback = this.getFallbackTranslator();
        return fallback != null ? fallback.translate(task, sql, ex) : null;
    }
}

实际转换类SQLErrorCodeSQLExceptionTranslator的方法:


//这里省略了一些无关代码,只保留了核心代码
//先获取SQLErrorCodes集合,在根据返回的SQLException中获取的ErrorCode进行匹配,根据匹配结果进行返回响应的异常
protected DataAccessException doTranslate(String task, @Nullable String sql, SQLException ex) {
	....
	SQLErrorCodes sqlErrorCodes = this.getSqlErrorCodes();
    
	String errorCode = Integer.toString(ex.getErrorCode());
	...
	//这里用1062唯一性约束冲突,所以走到这里的逻辑,从而返回DuplicateKeyException
	if (Arrays.binarySearch(sqlErrorCodes.getDuplicateKeyCodes(), errorCode) >= 0) {
		this.logTranslation(task, sql, sqlEx, false);
		return new DuplicateKeyException(this.buildMessage(task, sql, sqlEx), sqlEx);
	}
    ...
    return null;
}

上面的SQLErrorCodes是一个错误码集合,但是不是全部数据库的所有错误码集合,而是只取了相应数据库的错误码集合,怎么保证获取的是当前使用的数据库的错误码,而不是其他数据库的错误码呢?当然Spring为我们实现了,在SQLErrorCodeSQLExceptionTranslator中:


public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExceptionTranslator {

private SingletonSupplier<SQLErrorCodes> sqlErrorCodes;
//默认构造方法,设置了如果转换失败,下一个转换器是SQLExceptionSubclassTranslator
    public SQLErrorCodeSQLExceptionTranslator() {
        this.setFallbackTranslator(new SQLExceptionSubclassTranslator());
}
//前面生成转换器的时候,exceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(dataSource);
//使用的是本构造方法,传入了DataSource,其中有数据库厂商信息,本文中是Mysql
public SQLErrorCodeSQLExceptionTranslator(DataSource dataSource) {
	this();
	this.setDataSource(dataSource);
}

//从错误码工厂SQLErrorCodesFactory里,获取和数据源对应的厂商的所有错误码
public void setDataSource(DataSource dataSource) {
	this.sqlErrorCodes = SingletonSupplier.of(() -> {
		return SQLErrorCodesFactory.getInstance().resolveErrorCodes(dataSource);
	});
	this.sqlErrorCodes.get();
}
}

错误码工厂SQLErrorCodesFactory的resolveErrorCodes方法:


//既然是工厂,里面肯定有各种数据库的错误码,本文中使用的是mysql,我们看一下实现逻辑
@Nullable
public SQLErrorCodes resolveErrorCodes(DataSource dataSource) {
    Assert.notNull(dataSource, "DataSource must not be null");
    if (logger.isDebugEnabled()) {
        logger.debug("Looking up default SQLErrorCodes for DataSource [" + this.identify(dataSource) + "]");
    }
    //从缓存中拿MYSQL对应的SQLErrorCodes
    SQLErrorCodes sec = (SQLErrorCodes)this.dataSourceCache.get(dataSource);
    if (sec == null) {
        synchronized(this.dataSourceCache) {
            sec = (SQLErrorCodes)this.dataSourceCache.get(dataSource);
            if (sec == null) {
                try {
                    String name = (String)JdbcUtils.extractDatabaseMetaData(dataSource, DatabaseMetaData::getDatabaseProductName);
                    if (StringUtils.hasLength(name)) {
                        SQLErrorCodes var10000 = this.reGISterDatabase(dataSource, name);
                        return var10000;
                    }
                } catch (MetaDataAccessException var6) {
                    logger.warn("Error while extracting database name", var6);
                }

                return null;
            }
        }
    }

    if (logger.isDebugEnabled()) {
        logger.debug("SQLErrorCodes found in cache for DataSource [" + this.identify(dataSource) + "]");
    }

    return sec;
}

缓存dataSourceCache如何生成的?


public SQLErrorCodes registerDatabase(DataSource dataSource, String databaseName) {
   //根据数据库类型名称(这里是MySQL),获取错误码列表
    SQLErrorCodes sec = this.getErrorCodes(databaseName);
    if (logger.isDebugEnabled()) {
        logger.debug("Caching SQL error codes for DataSource [" + this.identify(dataSource) + "]: database product name is '" + databaseName + "'");
    }

    this.dataSourceCache.put(dataSource, sec);
    return sec;
}

public SQLErrorCodes getErrorCodes(String databaseName) {
        Assert.notNull(databaseName, "Database product name must not be null");
	//从errorCodesMap根据key=MYSQL获取SQLErrorCodes
        SQLErrorCodes sec = (SQLErrorCodes)this.errorCodesMap.get(databaseName);
        if (sec == null) {
            Iterator var3 = this.errorCodesMap.values().iterator();

            while(var3.hasNext()) {
                SQLErrorCodes candidate = (SQLErrorCodes)var3.next();
                if (PatternMatchUtils.simpleMatch(candidate.getDatabaseProductNames(), databaseName)) {
                    sec = candidate;
                    break;
                }
            }
        }

        if (sec != null) {
            this.checkCustomTranslatorRegistry(databaseName, sec);
            if (logger.isDebugEnabled()) {
                logger.debug("SQL error codes for '" + databaseName + "' found");
            }

            return sec;
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("SQL error codes for '" + databaseName + "' not found");
            }

            return new SQLErrorCodes();
        }
    }
		
		
//SQLErrorCodesFactory构造方法中,生成的errorCodesMap,map的内容来自org/springframework/jdbc/support/sql-error-codes.xml文件		
protected SQLErrorCodesFactory() {
        Map errorCodes;
        try {
            DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
            lbf.setBeanClassLoader(this.getClass().getClassLoader());
            XmlBeanDefinitionReader bdr = new XmlBeanDefinitionReader(lbf);
            Resource resource = this.loadResource("org/springframework/jdbc/support/sql-error-codes.xml");
            if (resource != null && resource.exists()) {
                bdr.loadBeanDefinitions(resource);
            } else {
                logger.info("Default sql-error-codes.xml not found (should be included in spring-jdbc jar)");
            }

            resource = this.loadResource("sql-error-codes.xml");
            if (resource != null && resource.exists()) {
                bdr.loadBeanDefinitions(resource);
                logger.debug("Found custom sql-error-codes.xml file at the root of the classpath");
            }

            errorCodes = lbf.getBeansOfType(SQLErrorCodes.class, true, false);
            if (logger.isTraceEnabled()) {
                logger.trace("SQLErrorCodes loaded: " + errorCodes.keySet());
            }
        } catch (BeansException var5) {
            logger.warn("Error loading SQL error codes from config file", var5);
            errorCodes = Collections.emptyMap();
        }

        this.errorCodesMap = errorCodes;
}

sql-error-codes.xml文件中配置了各个数据库的主要的错误码

这里列举了MYSQL部分,当然还有其他部分,我们可以看到唯一性约束错误码是1062,就可以翻译成DuplicateKeyException异常了


<bean id="MySQL" class="org.springframework.jdbc.support.SQLErrorCodes">
		<property name="databaseProductNames">
			<list>
				<value>MySQL</value>
				<value>MariaDB</value>
			</list>
		</property>
		<property name="badSqlGrammarCodes">
			<value>1054,1064,1146</value>
		</property>
		<property name="duplicateKeyCodes">
			<value>1062</value>
		</property>
		<property name="dataIntegrityViolationCodes">
			<value>630,839,840,893,1169,1215,1216,1217,1364,1451,1452,1557</value>
		</property>
		<property name="dataAccessResourceFailureCodes">
			<value>1</value>
		</property>
		<property name="cannotAcquireLockCodes">
			<value>1205,3572</value>
		</property>
		<property name="deadlockLoserCodes">
			<value>1213</value>
		</property>
	</bean>

你已经看到,比如上面的错误码值列举了一部分,如果出现了一个不在其中的错误码肯定是匹配不到,Spring当然能想到这种情况了


   
    @Nullable
    public DataAccessException translate(String task, @Nullable String sql, SQLException ex) {
        Assert.notNull(ex, "Cannot translate a null SQLException");
        DataAccessException dae = this.doTranslate(task, sql, ex);
        if (dae != null) {
            return dae;
        } else {
            SQLExceptionTranslator fallback = this.getFallbackTranslator();
            return fallback != null ? fallback.translate(task, sql, ex) : null;
        }
    }

SQLErrorCodeSQLExceptionTranslator的后置转换器是什么?


//构造方法中已经指定,SQLExceptionSubclassTranslator
public SQLErrorCodeSQLExceptionTranslator() {
   this.setFallbackTranslator(new SQLExceptionSubclassTranslator());
}

SQLExceptionSubclassTranslator的转换方法逻辑如下:



@Nullable
protected DataAccessException doTranslate(String task, @Nullable String sql, SQLException ex) {
    if (ex instanceof SQLTransientException) {
        if (ex instanceof SQLTransientConnectionException) {
            return new TransientDataAccessResourceException(this.buildMessage(task, sql, ex), ex);
        }

        if (ex instanceof SQLTransactionRollbackException) {
            return new ConcurrencyFailureException(this.buildMessage(task, sql, ex), ex);
        }

        if (ex instanceof SQLTimeoutException) {
            return new QueryTimeoutException(this.buildMessage(task, sql, ex), ex);
        }
    } else if (ex instanceof SQLNonTransientException) {
        if (ex instanceof SQLNonTransientConnectionException) {
            return new DataAccessResourceFailureException(this.buildMessage(task, sql, ex), ex);
        }

        if (ex instanceof SQLDataException) {
            return new DataIntegrityViolationException(this.buildMessage(task, sql, ex), ex);
        }

        if (ex instanceof SQLIntegrityConstraintViolationException) {
            return new DataIntegrityViolationException(this.buildMessage(task, sql, ex), ex);
        }

        if (ex instanceof SQLInvalidAuthorizationSpecException) {
            return new PermissionDeniedDataAccessException(this.buildMessage(task, sql, ex), ex);
        }

        if (ex instanceof SQLSyntaxErrorException) {
            return new BadSqlGrammarException(task, sql != null ? sql : "", ex);
        }

        if (ex instanceof SQLFeatureNotSupportedException) {
            return new InvalidDataAccessapiUsageException(this.buildMessage(task, sql, ex), ex);
        }
    } else if (ex instanceof SQLRecoverableException) {
        return new RecoverableDataAccessException(this.buildMessage(task, sql, ex), ex);
    }

    return null;
}

SQLStateSQLExceptionTranslator的转换方法:



@Nullable
protected DataAccessException doTranslate(String task, @Nullable String sql, SQLException ex) {
    String sqlState = this.getSqlState(ex);
    if (sqlState != null && sqlState.length() >= 2) {
        String classCode = sqlState.substring(0, 2);
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Extracted SQL state class '" + classCode + "' from value '" + sqlState + "'");
        }

        if (BAD_SQL_GRAMMAR_CODES.contains(classCode)) {
            return new BadSqlGrammarException(task, sql != null ? sql : "", ex);
        }

        if (DATA_INTEGRITY_VIOLATION_CODES.contains(classCode)) {
            return new DataIntegrityViolationException(this.buildMessage(task, sql, ex), ex);
        }

        if (DATA_ACCESS_RESOURCE_FAILURE_CODES.contains(classCode)) {
            return new DataAccessResourceFailureException(this.buildMessage(task, sql, ex), ex);
        }

        if (TRANSIENT_DATA_ACCESS_RESOURCE_CODES.contains(classCode)) {
            return new TransientDataAccessResourceException(this.buildMessage(task, sql, ex), ex);
        }

        if (CONCURRENCY_FAILURE_CODES.contains(classCode)) {
            return new ConcurrencyFailureException(this.buildMessage(task, sql, ex), ex);
        }
    }

    return ex.getClass().getName().contains("Timeout") ? new QueryTimeoutException(this.buildMessage(task, sql, ex), ex) : null;
}

为什么SQLState可以得出错误类型?

因为数据库是根据 X/Open 和 SQL Access Group SQL CAE 规范 (1992) 所进行的定义,SQLERROR 返回 SQLSTATE 值。SQLSTATE 值是包含五个字符的字符串 。五个字符包含数值或者大写字母, 代表各种错误或者警告条件的代码。SQLSTATE 有个层次化的模式:头两个字符标识条件的通常表示错误条件的类别, 后三个字符表示在该通用类中的子类。成功的状态是由 00000 标识的。SQLSTATE 代码在大多数地方都是定义在 SQL 标准里

处理流程图

用到了哪些设计模式?

组合模式

通过上图大家有没有发现三个实现类之间的关系—组合关系,组合关系在父类AbstractFallbackSQLExceptionTranslator中变成了递归调用,这里充满了智慧(Composite设计模式)。

单例模式

在SQLErrorCodesFactory(单例模式)

策略模式

根据数据库的不同,获取不同的errorcodes集合

总结:

学习的过程中,我们不但要关注其实现的方式,还要关注我们能从里面学到什么?比如说从这个异常抽象中,能学到几种设计模式,以及使用的场景,这些都是可以运用到以后的工作中。

到此这篇关于详解Spring不同数据库异常如何抽象的文章就介绍到这了,更多相关Spring数据库异常抽象内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 详解Spring不同数据库异常如何抽象的

本文链接: https://www.lsjlt.com/news/134860.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 详解Spring不同数据库异常如何抽象的
    目录前言代码实现处理流程图用到了哪些设计模式?组合模式单例模式策略模式总结:前言 使用Spring-Jdbc的情况下,在有些场景中,我们需要根据数据库报的异常类型的不同,来编写我们...
    99+
    2024-04-02
  • 详解C++中的数据抽象
    目录C++ 数据抽象访问标签强制抽象数据抽象的好处数据抽象的实例设计策略C++ 数据抽象 数据抽象是指,只向外界提供关键信息,并隐藏其后台的实现细节,即只表现必要...
    99+
    2023-05-19
    C++抽象 C++数据抽象
  • java如何抛出适合抽象的异常
    这篇文章主要介绍java如何抛出适合抽象的异常,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!抛出适合抽象的异常抛出的异常应该与调用者执行的任务有联系。此项介绍异常转换(捕获异常并抛出另一个)和异常链(将异常包装在新的...
    99+
    2023-06-27
  • Aurora Serverless数据库与常规Aurora数据库有何不同
    Aurora Serverless数据库与常规Aurora数据库有几个重要的不同之处: 自动伸缩:Aurora Serverle...
    99+
    2024-04-02
  • Spring myBatis数据库连接异常问题及解决
    目录spring myBatis数据库连接异常报错如下myBatis连接数据库时报错原因归纳报错信息spring myBatis数据库连接异常 报错如下 org.mybatis.sp...
    99+
    2024-04-02
  • 如何解决Spring boot数据源未配置异常
    本篇内容主要讲解“如何解决Spring boot数据源未配置异常”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何解决Spring boot数据源未配置异常”吧!Spring boot 数据源未...
    99+
    2023-06-20
  • springboot连接不同数据库的写法详解
    目录MySQL达梦MySQL 当url连接不指定/数据库名可以访问到mysql服务器上有权限的任何库,但是所有sql需要加上库名前缀. pom <dependency> ...
    99+
    2023-05-16
    springboot连接数据库 springboot连接不同数据库
  • 从不同角度看Sybase和Oracle数据库的异同
    Sybase和Oracle都是在企业级数据库领域备受青睐的两大数据库管理系统。它们在功能、性能、可靠性等方面都有各自的优势,并且在实际应用中常常被广泛使用。本文将从不同角度来探讨Syb...
    99+
    2024-03-09
    数据库 oracle sybase
  • 如何使用$.get()根据选项的不同从数据库异步请求数据
    这篇文章给大家介绍如何使用$.get()根据选项的不同从数据库异步请求数据,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。 Ajax极大地改善了用户体验,对...
    99+
    2024-04-02
  • Spring boot 数据源未配置异常的解决
    Spring boot 数据源未配置异常 问题 在使Springboot自动生成的项目框架时如果选择了数据源,比如选择了mysql,生成项目之后,启动会报一下异常: Descrip...
    99+
    2024-04-02
  • PHP 对象关系映射与数据库抽象层中的常见陷阱和解决方案
    PHP 对象关系映射与数据库抽象层中的常见陷阱和解决方案 陷阱 1:延迟加载的问题 当使用延迟加载策略时,在访问实体的属性或方法之前,需要先加载整个实体。这可能会导致意想不到的性能问题...
    99+
    2024-05-06
    php orm 延迟加载 数据丢失
  • python如何实现不同数据库间数据同步功能
    这篇文章主要为大家展示了python如何实现不同数据库间数据同步功能,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带大家一起来研究并学习一下“python如何实现不同数据库间数据同步功能”这篇文章吧。python是什么意思P...
    99+
    2023-06-06
  • Spring访问数据库异常的处理方法是什么
    Spring访问数据库异常的处理方法是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。使用JDBC API时,很多操作都要声明抛出java.sql.SQLExceptio...
    99+
    2023-06-17
  • Java大数据异步编程:如何处理不同类型的数据?
    在现代数据处理领域,大数据已经成为了一种必不可少的资源。然而,处理大量数据时,我们面临着一个很大的问题:处理速度。传统的同步处理方式往往会导致程序运行变慢,甚至可能导致系统崩溃。因此,异步编程已经成为了一种解决方案。在本文中,我们将探讨J...
    99+
    2023-07-06
    大数据 异步编程 数据类型
  • 如何使用Jdbc连接不同数据库
    今天就跟大家聊聊有关如何使用Jdbc连接不同数据库,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1.Jdbc连接Access数据库①通过控制面板&g...
    99+
    2024-04-02
  • mysql数据不同步如何解决
    mysql数据不同步的解决方法首先,对数据进行锁表,防止数据写入;flush tables with read lock; 对数据进行备份;mysqldump -uroot -p123456 --all-databases > /tmp/m...
    99+
    2024-04-02
  • 如何在 ASP 对象中使用不同的数据类型?
    ASP(Active Server Pages)是一种服务端脚本语言,常用于创建动态的网页。在ASP中,我们经常需要使用不同的数据类型来进行数据的存储和处理。本文将介绍如何在ASP对象中使用不同的数据类型。 一、字符串类型 字符串类型是AS...
    99+
    2023-07-29
    对象 数据类型 leetcode
  • STL 中的函数对象如何处理异常?
    stl的函数对象可处理异常。stl算法通过catch语句自动捕获函数对象抛出的异常并转发给调用算法的函数,从而确保异常的正确处理。 STL 中的函数对象如何处理异常 函数对象是 STL...
    99+
    2024-04-26
    异常处理 stl
  • 解决安卓访问阿里云数据库异常的详细步骤
    安卓设备在访问阿里云数据库时可能会遇到各种异常情况,如连接失败、数据读取错误等。本文将详细介绍如何解决这些问题。 一、连接失败异常检查数据库配置:首先,你需要检查数据库的配置是否正确。确保数据库的URL、用户名、密码和数据库名称等信息都是正...
    99+
    2023-10-31
    阿里 步骤 异常
  • C++ 技术中的异常处理:如何使用异常对象来获取异常详细信息?
    c++++ 异常处理获取异常详细信息的方法:使用异常对象 e.name() 获取异常类型。使用 e.what() 获取描述异常原因的文本消息。 C++ 中的异常处理:揭秘获取异常详细信...
    99+
    2024-05-10
    c++ 异常处理
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作