# ErrorContext 错误日志
mybatis在读取mapper文件的时候,会存在下面这行代码,那么它用到了ErrorContext 类,那么该类的作用是啥?
ErrorContext.instance().resource(resource);
MyBatis 还有一个很有意思的点在于异常日志的输出。不知道大家有没有发现,使用 MyBatis 时定位问题非常容易,我们只需要查看一下控制台的异常日志就能一目了然地知道问题出现在了哪里。就像这样:
1.存储异常信息的字段
MyBatis 异常涵盖的信息总结为一点就是:异常是由谁在做什么的时候在哪个资源文件中发生的,执行的 SQL 是哪个,以及 java 详细的异常信息。这六个私有变量分别存储这些信息:
public class ErrorContext {
private static final String LINE_SEPARATOR = System.getProperty("line.separator","\n");
private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<ErrorContext>();
private ErrorContext stored;
private String resource;
private String activity;
private String object;
private String message;
private String sql;
private Throwable cause;
- resource:存储异常存在于哪个资源文件中。
如:### The error may exist in mapper/AuthorMapper.xml - activity:存储异常是做什么操作时发生的。
如:### The error occurred while setting parameters - object:存储哪个对象操作时发生异常。
如:### The error may involve defaultParameterMap - message:存储异常的概览信息。
如:### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Unknown column ‘id2’ in ‘field list’ - sql:存储发生日常的 SQL 语句。
如:### SQL: select id2, name, sex, phone from author where name = ? - cause:存储详细的 Java 异常日志。
如:### Cause: java.sql.SQLSyntaxErrorException: Unknown column ‘id2’ in ‘field list’ at
对于这六个成员变量的 “set” 方法,命名同相应成员变量,均是对成员变量做赋值操作并返回存储完相应信息后当前 ErrorContext 的实例。例如:
public ErrorContext resource(String resource) {
this.resource = resource;
return this;
}
public ErrorContext activity(String activity) {
this.activity = activity;
return this;
}
2.使用 ThreadLocal 管理 ErrorContext
private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<ErrorContext>();
ThreadLocal 是本地线程存储,它的作用是为变量在每个线程中创建一个副本,每个线程内部都可以使用该副本,线程之间互不影响。使用 ThreadLocal 来管理 ErrorContext,保证了在多线程环境中,每个线程内部可以共用一份 ErrorContext,但多个线程持有的 ErrorContext 互不影响,保证了异常日志的正确输出。
ErrorContext采用了单例模式,保证了每个线程共用一份实例
private ErrorContext() {
}
public static ErrorContext instance() {
ErrorContext context = LOCAL.get();
if (context == null) {
context = new ErrorContext();
LOCAL.set(context);
}
return context;
}
3.其它方法
stored 变量充当一个中介,在调用store() 方法时将当前 ErrorContext 保存下来,在调用 recall() 方法时将该 ErrorContext 实例传递给 LOCAL。
public ErrorContext store() {
stored = this;
LOCAL.set(new ErrorContext());
return LOCAL.get();
}
public ErrorContext recall() {
if (stored != null) {
LOCAL.set(stored);
stored = null;
}
return LOCAL.get();
}
reset() 顾名思义就是重置方法
public ErrorContext reset() {
resource = null;
activity = null;
object = null;
message = null;
sql = null;
cause = null;
LOCAL.remove();
return this;
}
toString() 方法就是显示我们的错误信息
@Override
public String toString() {
StringBuilder description = new StringBuilder();
if (this.message != null) {
description.append(LINE_SEPARATOR);
description.append("### ");
description.append(this.message);
}
if (resource != null) {
description.append(LINE_SEPARATOR);
description.append("### The error may exist in ");
description.append(resource);
}
if (object != null) {
description.append(LINE_SEPARATOR);
description.append("### The error may involve ");
description.append(object);
}
if (activity != null) {
description.append(LINE_SEPARATOR);
description.append("### The error occurred while ");
description.append(activity);
}
if (sql != null) {
description.append(LINE_SEPARATOR);
description.append("### SQL: ");
description.append(sql.replace('\n', ' ').replace('\r', ' ').replace('\t', ' ').trim());
}
if (cause != null) {
description.append(LINE_SEPARATOR);
description.append("### Cause: ");
description.append(cause.toString());
}
return description.toString();
}
4.Mybatis使用
mybatis是如何使用的,其实这个就相当于是一个进度,例如上面的那行代码,就是把资源路径存入,然后在后面执行SQL的时候,会继续存入其它的信息
ErrorContext.instance().resource(resource);
这里还有一个小细节,为啥这些赋值方法,要返回this 当前这个对象,因为这样就更方便多个赋值,例如ErrorContext.instance().message(message).cause(e).toString() ,这样赋值操作1行就可以搞定
5.ErrorContext
text.instance().resource(resource);
这里还有一个小细节,为啥这些赋值方法,要返回`this`当前这个对象,因为这样就更方便多个赋值,例如`ErrorContext.instance().message(message).cause(e).toString()`,这样赋值操作1行就可以搞定
## 5.ErrorContext
|