MyBatis框架定义了许多的异常类,之所以定义这么多的异常类,应该是将每一种异常情况都独立出来,这样在出现异常时,定位就很明确了。而我们平时写代码时,都是瞎搞一通,异常类大多也是随便定义,或者是使用JDK自带异常类,有时候甚至是直接弄Exception。缺点显而易见了。今后写代码,也应该是学着MyBatis,将每种业务(或场景)可能出现的异常进行单独封装,这样,当项目报错,出现异常时,定位起来也就简单很多。

  MyBatis的异常爹是IbatisException.class ,而它又是RuntimeException的儿子。这是为什么呢?

  1. Exception异常,要么抛,要么处理。。。强制性要求。。。

  2. RuntimeException异常,编译时我也不知道会不会出错,运行时才知道结果咋样,,,, 可以不处理,但是出错了,程序就停摆。

  具体啥原因,我也不知道,但是人家MyBatis都是这样搞,那我们以后写代码也跟着这样弄吧!!!

  

public class IbatisException extends RuntimeException {

  private static final long serialVersionUID = 3880206998166270511L;

  public IbatisException() {
super();
} public IbatisException(String message) {
super(message);
} public IbatisException(String message, Throwable cause) {
super(message, cause);
} public IbatisException(Throwable cause) {
super(cause);
} }

  MyBatis异常爹就是这样定义的,提供了4个结构函数,构造函数全是super, 而且它所有的异常子类,似乎也都是这种款式。 以后工作中也跟着用呗!

  工作中,我们也应该学习MyBatis的这种套路,但是这些并非MyBatis异常模块的核心。在MyBatis中,它提供了两个核心类,ExceptionFactory.class 和 ErrorContext.class。

其作用也是顾名思义。接着我们来看看它的具体实现,还是比较有意思的,以后工作中也应该尝试这种套路。

1. ExceptionFactory.class

 

public class ExceptionFactory {

  private ExceptionFactory() {
// Prevent Instantiation
} public static RuntimeException wrapException(String message, Exception e) {
return new PersistenceException(ErrorContext.instance().message(message).cause(e).toString(), e);
} }

     私有化构造器,但然后通过静态方法,将异常信息和异常真实对象创建出来。

  注意: 返回的异常类型是RuntimeException.class, 而 new 的是PersistenceException.class。 在高版本的MyBatis中将IbatisException.class标注为过时类,而 PersistenceException.class却又是IbatisException.class的子类。。。。。 这似乎是一种代码扩展/升级/兼容老版本的方式呢!!!!

不过,我觉得ExceptionFactory.class中,最关键是应该是ErrorContext.instance().message(message).cause(e).toString()这句代码了。 下面我们来看看ErrorContext.class

2. ErrorContext.class

public class ErrorContext {

  private static final String LINE_SEPARATOR = System.getProperty("line.separator","\n");
private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<>(); private ErrorContext stored;
private String resource;
private String activity;
private String object;
private String message;
private String sql;
private Throwable cause; private ErrorContext() {
} public static ErrorContext instance() {
ErrorContext context = LOCAL.get();
if (context == null) {
context = new ErrorContext();
LOCAL.set(context);
}
return context;
} public ErrorContext store() {
ErrorContext newContext = new ErrorContext();
newContext.stored = this;
LOCAL.set(newContext);
return LOCAL.get();
} public ErrorContext recall() {
if (stored != null) {
LOCAL.set(stored);
stored = null;
}
return LOCAL.get();
} public ErrorContext resource(String resource) {
this.resource = resource;
return this;
} public ErrorContext activity(String activity) {
this.activity = activity;
return this;
} public ErrorContext object(String object) {
this.object = object;
return this;
} public ErrorContext message(String message) {
this.message = message;
return this;
} public ErrorContext sql(String sql) {
this.sql = sql;
return this;
} public ErrorContext cause(Throwable cause) {
this.cause = cause;
return this;
} public ErrorContext reset() {
resource = null;
activity = null;
object = null;
message = null;
sql = null;
cause = null;
LOCAL.remove();
return this;
} @Override
public String toString() {
StringBuilder description = new StringBuilder(); // message
if (this.message != null) {
description.append(LINE_SEPARATOR);
description.append("### ");
description.append(this.message);
} // resource
if (resource != null) {
description.append(LINE_SEPARATOR);
description.append("### The error may exist in ");
description.append(resource);
} // object
if (object != null) {
description.append(LINE_SEPARATOR);
description.append("### The error may involve ");
description.append(object);
} // activity
if (activity != null) {
description.append(LINE_SEPARATOR);
description.append("### The error occurred while ");
description.append(activity);
} // activity
if (sql != null) {
description.append(LINE_SEPARATOR);
description.append("### SQL: ");
description.append(sql.replace('\n', ' ').replace('\r', ' ').replace('\t', ' ').trim());
} // cause
if (cause != null) {
description.append(LINE_SEPARATOR);
description.append("### Cause: ");
description.append(cause.toString());
} return description.toString();
} }

  

  private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<>(); 因为少见多怪,所以看到这行代码 ,瞬间就觉得有点逼 格了,ThreadLocal这个类的使用,一般都是为了解决线程安全的问题。MyBatis有必要考虑这个问题吗?或许真的有必要吧,谁让它有那么多成员变量呢!

  不求甚解,但套路必须要学!!!

  想想自己项目中的异常体系,简直不堪入目!!!

MyBatis框架之异常处理的更多相关文章

  1. 使用intellij idea搭建MAVEN+springmvc+mybatis框架

    原文:使用intellij idea搭建MAVEN+springmvc+mybatis框架 1.首先使用idea创建一个maven项目 2.接着配置pom.xml,以下为我的配置 <projec ...

  2. Mybatis框架的多对一关联关系(六)

    一.一对多的关联映射 一对多关联查询多表数据 1接口 public interface IDeptDAO { //根据部门编号查询该部门单个查询 public Emp getEmpById(Integ ...

  3. Spring+SpringMvc+Mybatis框架集成搭建教程

    一.背景 最近有很多同学由于没有过SSM(Spring+SpringMvc+Mybatis , 以下简称SSM)框架的搭建的经历,所以在自己搭建SSM框架集成的时候,出现了这样或者那样的问题,很是苦恼 ...

  4. Mybatis框架中实现双向一对多关系映射

    学习过Hibernate框架的伙伴们很容易就能简单的配置各种映射关系(Hibernate框架的映射关系在我的blogs中也有详细的讲解),但是在Mybatis框架中我们又如何去实现 一对多的关系映射呢 ...

  5. Hibernate框架与Mybatis框架的对比

    学习了Hibernate和Mybatis,但是一直不太清楚他们两者的区别的联系,今天在网上翻了翻,就做了一下总结,希望对大家有帮助! 原文:http://blog.csdn.net/firejuly/ ...

  6. 初识Mybatis框架,实现增删改查等操作(动态拼接和动态修改)

    此第一次接触Mybatis框架确实是有点不适应,特别是刚从Hibernate框架转转型过来,那么为什么要使用Mybatis框架,Mybatis框架和Hibernate框架又有什么异同呢? 这个问题在我 ...

  7. Spring+MyBatis框架中sql语句的书写,数据集的传递以及多表关联查询

    在很多Java EE项目中,Spring+MyBatis框架经常被用到,项目搭建在这里不再赘述,现在要将的是如何在项目中书写,增删改查的语句,如何操作数据库,以及后台如何获取数据,如何进行关联查询,以 ...

  8. SSM框架-----------SpringMVC+Spring+Mybatis框架整合详细教程

    1.基本概念 1.1.Spring Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One  ...

  9. Spring3.0 与 MyBatis框架 整合小实例

    本文将在Eclipse开发环境下,采用Spring MVC + Spring + MyBatis + Maven + Log4J 框架搭建一个Java web 项目. 1. 环境准备: 1.1 创建数 ...

随机推荐

  1. 不间断电源(UPS)

    UPS电源一般指不间断电源 UPS(Uninterruptible Power System/Uninterruptible Power Supply),即不间断电源,是将蓄电池(多为铅酸免维护蓄电池 ...

  2. 将原生JS和jquery里面的DOM操作进行了一下整理

    创建元素节点 1.原生: document.createElement("div") 2.jquery: $("<div></div>" ...

  3. Oracle-数据表对象

    表一般指的是一个关系表,也可以生成对象表以及临时表.齐总,对象表是通过用户定义的数据类型生成的,临时表用于存储专用于某个事务或会话的临时数据 字符类型: 定长:char (1-2000字节) 变长:v ...

  4. 用Delphi从内存流中判断图片格式[转]

    http://blog.163.com/tfn2008%40yeah/blog/static/110321319201222243214337/ 用Delphi从内存流中判断图片格式[转] 2012- ...

  5. c#Cache的用法

    public class Cache { /// <summary> /// 获取数据缓存 /// </summary> /// <param name="ca ...

  6. 爬虫(六)——存储库(一)MongoDB存储库

    目录 存储库--MongoDB 一.安装MongoDB 4.0 1.安装 2.修改数据库文件和日志保存位置设置(可不改) 3.账户管理.远程服务 三.MongoDB数据库操作 1.对库操作 2.对集合 ...

  7. C++学习笔记(一)--基础

    1.遵循标准C++,主函数类型为int,成功返回值为0,异常返回默认为-1. 2.使用系统函数库,必须加上 using namespace std,因为C++的标准库函数是在命名空间std中: 3.输 ...

  8. SpringBoot 接口并行高效聚合

    转自:juejin.im/post/5d064b90e51d45777540fda7 背景 接口开发是后端开发中最常见的场景, 可能是RESTFul接口, 也可能是RPC接口. 接口开发往往是从各处捞 ...

  9. Python入门习题1.温度转换

    这一节的课堂例题为: 例1.编写一个Python程序,完成摄氏度到华氏度,华氏度到摄氏度的温度转换. 解: (1)分析问题:利用程序实现温度转换,由用户输入温度值,程序给出输出结果. (2)划分边界: ...

  10. [Bzoj3223][Tyvj1729] 文艺平衡树(splay/无旋Treap)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3223 平衡树处理区间问题的入门题目,普通平衡树那道题在维护平衡树上是以每个数的值作为维护 ...