文章目录
- [WITH (NOLOCK) 是什么?](#WITH (NOLOCK) 是什么?)
- 代码示例
WITH (NOLOCK) 是什么?
WITH (NOLOCK) 也叫 未提交读(READ UNCOMMITTED),是 SQL Server 中的一种表提示(Table Hint),本质是让查询语句忽略目标表上的共享锁和排他锁,直接读取数据,核心目的是提升查询性能、避免查询被阻塞。
SQL Server 默认的隔离级别是 READ COMMITTED(已提交读),即查询会等待目标数据上的锁释放后再读取,且只能读取已提交的数据;而 NOLOCK 会强制查询使用 READ UNCOMMITTED 隔离级别,打破这个规则。
代码示例
java
package com.qf.config;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;
import java.sql.Connection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
@Component
public class MybatisPlusSqlInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
// 先判断是不是SELECT操作 不是直接跳过
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
return invocation.proceed();
}
String id = mappedStatement.getId();
String methodName = id.substring(id.lastIndexOf(".") + 1, id.length());
//只有Mybatis plus的selectOne和selectList做特殊处理
if (!methodName.equals("selectOne") && !methodName.equals("selectList") && !methodName.equals("selectMaps")) {
return invocation.proceed();
}
BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
// 执行的SQL语句
String originalSql = boundSql.getSql().replace("\n", "");
String tableName = extractFromClause(originalSql);
log.info("要执行的sql:{}", originalSql);
log.info("正则表达式获取要执行的sql的表名:{}", tableName);
if (StringUtils.isNotEmpty(tableName)) {
String finalSql = originalSql.replace(tableName, tableName + " WITH(NOLOCK)");
log.info("处理后的sql:{}", finalSql);
metaObject.setValue("delegate.boundSql.sql", finalSql);
}
return invocation.proceed();
}
public static String extractFromClause(String query) {
String table = "";
Pattern p = Pattern.compile("FROM \\[(.*?)\\]");
Matcher m = p.matcher(query);
if (m.find()) {
table = m.group();
}
return table.trim();
}
}