精华内容
下载资源
问答
  • mybatis拦截器记录sql日志

    千次阅读 2019-07-05 14:35:47
    1.最近公司一个需求让我把每次执行的sql都保存到数据库,然而我看了一些网上的资料没有适合我的例子,下面是我自己用mybatis拦截器写的一套管理sql日志的代码; 其中保存的sql 使用Druid数据库连接池配置的打印SQL的...

    1.最近公司一个需求让我把每次执行的sql都保存到数据库,然而我看了一些网上的资料没有适合我的例子,下面是我自己用mybatis拦截器写的一套管理sql日志的代码;
    其中保存的sql 使用Druid数据库连接池配置的打印SQL的方式,其他方式我也不太了解感兴趣的可以自己了解一下;

    1.Druid的包和json的包

     		<dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.10</version>
            </dependency>
     	<dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.47</version>
            </dependency>
    

    2.数据库sql

    CREATE TABLE `sp_audit_db_log` (
      `ID` varchar(48) NOT NULL,
      `SQL_CONTENT` text COMMENT 'SQL内容',
      `IN_PARAM` varchar(256) DEFAULT NULL COMMENT 'sql入参',
      `START_TIME` datetime DEFAULT NULL COMMENT 'sql开始执行时间',
      `END_TIME` datetime DEFAULT NULL COMMENT 'sql执行结束时间',
      `COST_TIME` bigint(20) DEFAULT NULL COMMENT '执行sql耗时',
      `RESUTL_TYPE` varchar(4) DEFAULT NULL COMMENT '执行结果,01:成功;02:失败',
      `ERROR_CONTENT` varchar(512) DEFAULT NULL COMMENT '错误内容',
      `REMARK` varchar(256) DEFAULT NULL COMMENT '备注',
      PRIMARY KEY (`ID`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    

    3.实体

    额,这个自己看着数据库写把;
    

    4.拦截器代码
    所用工具地址:
    日期工具类:https://blog.csdn.net/qq_41988504/article/details/94734733
    stringutil工具类:https://blog.csdn.net/qq_41988504/article/details/94735032

    package com.xiaolc.intercept;
    
    
    import com.alibaba.druid.pool.DruidDataSource;
    import com.alibaba.druid.sql.SQLUtils;
    import com.alibaba.fastjson.JSON;
    import com.xiaolc.mapper.SpAuditDbLogMapper;
    import com.xiaolc.model.SpAuditDbLog;
    import com.xiaolc.util.DateUtils;
    import com.xiaolc.util.StringUtil;
    import org.apache.ibatis.cache.CacheKey;
    import org.apache.ibatis.executor.Executor;
    import org.apache.ibatis.executor.statement.StatementHandler;
    import org.apache.ibatis.mapping.BoundSql;
    import org.apache.ibatis.mapping.MappedStatement;
    import org.apache.ibatis.mapping.ParameterMapping;
    import org.apache.ibatis.plugin.*;
    import org.apache.ibatis.session.Configuration;
    import org.apache.ibatis.session.ResultHandler;
    import org.apache.ibatis.session.RowBounds;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Method;
    import java.util.*;
    
    
    /**
     * @Author: LiCheng
     * @Date: 2019/7/4 16:04
     */
    @Intercepts({@org.apache.ibatis.plugin.Signature(
            type = Executor.class,
            method = "update",
            args = {MappedStatement.class, Object.class}),
            @Signature(type = Executor.class,
                    method = "query",
                    args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class,
                            CacheKey.class, BoundSql.class})})
    @Component
    public class ExecutorInterceptor implements Interceptor {
    
        @Autowired
        private SpAuditDbLogMapper spAuditDbLogMapper;
    
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            Object[] args = invocation.getArgs();
    
            MappedStatement ms = (MappedStatement) args[0];
            ms.getStatementType();
            //当前SQL使用的是哪个Mapper,即哪个Mapper类
            String mapper = ms.getResource();
            Configuration configuration = ms.getConfiguration();
            //执行当前SQL的Mapper id,其组成 [ 类型.方法 ]
            String mapperID = ms.getId();
    
            //获取当前执行的SQL使用哪个数据源,我这里的数据源组件使用的是Druid,如果使用c3p0或者其他,则需要查看相关API,一般来降一个项目可能会配多个数据源,但是数据源组件都会使用一个
            DruidDataSource dataSource = (DruidDataSource) configuration.getEnvironment().getDataSource();
            //获取数据库的类型[即mysql,或者oracle等等]
            Date createdTime = dataSource.getCreatedTime();
            String dbType = dataSource.getDataSourceStat().getDbType();
    
            //存放的是SQL的参数[它是一个实例对象]
            Object parameterObject = args[1];
            Object target = invocation.getTarget();
            StatementHandler handler = configuration.newStatementHandler((Executor) target, ms, parameterObject, RowBounds.DEFAULT, null, null);
    
            /**
             * commandName.startsWith(增/删/改/查),可以得到crud的具体类型[得到的是大写的INSERT UPDATE]
             * method.getName()得到的name可能为update, query, flushStatements, commit, rollback, getTransaction, close, isClosed
             */
            String commandName = ms.getSqlCommandType().name();
            Method method = invocation.getMethod();
            String methodName = method.getName();
    
            BoundSql boundSql = ms.getBoundSql(parameterObject);
            //这个ParameterMapping表示当前SQL绑定的是哪些参数,及参数类型,但并不是参数本身
            List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
            //将参数值转成json字符串
            String parameterObjects = JSON.toJSONString(boundSql.getParameterObject());
    
    
            //要拦截的SQL,通过拦截器的SQL 其不带参数
            String srcSQL = boundSql.getSql();
            //返回拼装好参数的SQL
            String retSQL = formatSQL(srcSQL, dbType, parameterObjects);
            //先执行当前的SQL方法,即通过当前拦截器的CRUD操作,因为我们要返回这个结果
            long start = System.currentTimeMillis();
            Object result = invocation.proceed();
            long end = System.currentTimeMillis();
            long time = end - start;
    
            //记录影响行数
            // Integer integer = Integer.valueOf(Integer.parseInt(result.toString()));
            //TODO 还可以记录参数,或者单表id操作时,记录数据操作前的状态
            //获取insertSqlLog方法
            //ms = ms.getConfiguration().getMappedStatement("insertSqlLog");
            //替换当前的参数为新的ms
            //args[0] = ms;
            //insertSqlLog 方法的参数为 log
            //args[1]=log;
    
            //组装自己的SQL记录类
            SpAuditDbLog spAuditDbLog = new SpAuditDbLog();
            spAuditDbLog.setId(UUID.randomUUID().toString());
            //记录SQL
            spAuditDbLog.setSqlContent(retSQL);
            //入参
            spAuditDbLog.setInParam(parameterObjects);
            //sql开始执行时间
            spAuditDbLog.setStartTime(DateUtils.dateParse(start, "yyyy-MM-dd HH:mm:ss"));
            //sql执行结束时间
            spAuditDbLog.setEndTime(DateUtils.dateParse(end, "yyyy-MM-dd HH:mm:ss"));
            //耗时
            spAuditDbLog.setCostTime(time);
            //执行结果
            spAuditDbLog.setResutlTupe(StringUtil.isNotEmpty(result) ? "01" : "02");
            SpAuditDbLog save = spAuditDbLogMapper.save(spAuditDbLog);
            //返回拦截器拦截的执行结果
            return result;
        }
    
        /**
         * plugin方法是拦截器用于封装目标对象的,通过该方法我们可以返回目标对象本身,也可以返回一个它的代理。
         * 当返回的是代理的时候我们可以对其中的方法进行拦截来调用intercept方法,当然也可以调用其他方法
         * 对于plugin方法而言,其实Mybatis已经为我们提供了一个实现。Mybatis中有一个叫做Plugin的类,
         * 里面有一个静态方法wrap(Object target,Interceptor interceptor),通过该方法可以决定要返回的对象是目标对象还是对应的代理。
         */
        @Override
        public Object plugin(Object o) {
    //        只拦截Executor对象,减少目标被代理的次数
            if (o instanceof Executor) {
                return Plugin.wrap(o, this);
            }
            return o;
        }
    
        /**
         * setProperties方法是用于在Mybatis配置文件中指定一些属性的
         * 这个方法在Configuration初始化当前的Interceptor时就会执行
         */
        @Override
        public void setProperties(Properties properties) {
    
        }
    
        /**
         * @describe: 组装SQL
         * @params:
         * @Author: LiCheng
         * @Date: 2019/7/4 15:10
         */
        public String formatSQL(String src, String dbType, String params) {
            //要传入的SQLUtils的参数集合,实际上虽然泛型是Object,但其实都是基本数据类型
            List<Object> paramList = new ArrayList();
            //有了JSON字符串我们就可以通过正则表达式得到参数了
            System.out.println(params);
            //需要注意的是这个SQLUtils是Druid数据源中的一个工具类,因为有现成的拼sql的工具,所以我就不再重复造轮子了,如果你的项目并没有使用Druid,
            //则需要将这个工具类加入到你的项目中
            String retSQL = SQLUtils.format(src, dbType, paramList);
            return retSQL;
        }
    }
    
    

    5.测试结果
    在这里插入图片描述
    6.不懂的或者有问题的加我qq:1269958153 欢迎一起交流

    展开全文
  • 项目运行报错时,查看sql日志是非常好的排查手段,以前在spring框架下往往都是通过修改日志级别为DEBUG然后重启再次运行才生效,那么SpringBoot如何修改呢? SpringBoot的spring-boot-starter依赖默认已经包含日志...

    项目运行报错时,查看sql日志是非常好的排查手段,以前在spring框架下往往都是通过修改日志级别为DEBUG然后重启再次运行才生效,那么SpringBoot如何修改呢?

    SpringBoot的spring-boot-starter依赖默认已经包含日志依赖,其默认使用的日志框架为logback,且默认的日志级别均为INFO,若不配置日志输出路径,默认日志信息打印在控制台。为了打印sql日志信息,我们只需把对应dao包下的日志级别改为DEBUG即可,在yaml配置文件中配置如下:

    logging:
      level:
        # Map<String, String>格式,前者为对应的路径或是进程 后者为日志级别
        activitiTest.activitiTest.dao: debug
    

    上图这种是针对本地测试或是临时修改,毕竟DEBUG级别下打印的日志会非常多,倘若生产环境下使用该级别会造成大量的垃圾日志信息,因此项目运行时一般不会这么干,所以需要在项目运行时动态修改其日志级别(无需重启),使之输出sql日志

     

    SpringBoot动态修改日志级别

    1、首先引入对应的监控工具依赖,其中包含有日志端点监控:

    <!-- springBoot监控工具 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    2、在yaml中配置如下:

    # 配置端点信息
    management:
      endpoints:
        # 关闭所有默认为true的端点
        enabled-by-default: false
        web:
          exposure:
            # 由于health端点在启动时无法扫描MongoConfig类中的mongoTemplate实例,因此此处去掉该端点 这里只留日志端点 使用post请求访问/actuator/loggers/端点名(先通过get请求访问/actuator/loggers获取所有端点名)
            # 请求体为{"configuredLevel": "DEBUG"},即可打印sql日志
            include:
            - loggers
    # 端点访问路径 默认即为/actuator
    #      base-path: /actuator
      endpoint:
        loggers:
          enabled: true
    
    # 端点端口配置,默认与服务端一样
    #  server:
    #    port:

    3、由于本文只是为了修改日志级别,因此只配了loggers端点,一般项目中往往还需要info和health端点用以监控,下面启动项目,然后使用get请求访问/actuator/loggers,会看到以下输出信息:

    {
        "levels":[
            "OFF",
            "ERROR",
            "WARN",
            "INFO",
            "DEBUG",
            "TRACE"
        ],
        "loggers":{
            "ROOT":{
                "configuredLevel":"INFO",
                "effectiveLevel":"INFO"
            },
            "com":{
                "configuredLevel":null,
                "effectiveLevel":"INFO"
            },
            "com.caiyi":{
                "configuredLevel":null,
                "effectiveLevel":"INFO"
            }
            ...
        }
    }

    4、开始修改日志级别,使用post请求访问,例如:/actuator/loggers/com.caiyi,请求体如下:

    {
      "configuredLevel": "DEBUG"
    }

    此时已经修改完毕,可直接访问controller层,查看日志信息,此时已有sql日志打印出:

    展开全文
  • 这个时候就需要开启SQL日志,将数据库执行过的SQL都记录下来,以方便进行跟踪分析 DM数据库控制SQL日志是通过一个系统参数,以及一个ini文件动态控制的 DM数据库开启SQL日志的方法: SP_SET_PARA_VALUE(1,‘SVR_LOG...

    在项目当中遇到性能问题时,有个很重要的优化手段是去检查SQL的执行效率。但是有些项目情况比较复杂的情况,难以准确抓取到性能有问题的SQL。这个时候就需要开启SQL日志,将数据库执行过的SQL都记录下来,以方便进行跟踪分析
    DM数据库控制SQL日志是通过一个系统参数,以及一个ini文件动态控制的
    DM数据库开启SQL日志的方法:
    SP_SET_PARA_VALUE(1,‘SVR_LOG’,1);
    关闭SQL日志的方法:
    SP_SET_PARA_VALUE(1,‘SVR_LOG’,0);
    另外,SVR_LOG只是SQL日志的开关,SQL日志的具体内容,需要通过sqllog.ini来进行控制
    具体的SQLLOG.INI的配置请参考手册

    下面是一个参考手册里提供的,SVR_LOG_NAME为SLOG_ALL 的sqllog.ini的例子:
    BUF_TOTAL_SIZE = 10240 #SQLs Log Buffer Total Size(K)(1024~1024000)
    BUF_SIZE = 1024 #SQLs Log Buffer Size(K)(50~409600)
    BUF_KEEP_CNT = 6 #SQLs Log buffer keeped count(1~100)
    [SLOG_ALL]
    FILE_PATH = …\log
    PART_STOR = 0
    SWITCH_MODE = 0
    SWITCH_LIMIT = 0
    ASYNC_FLUSH = 0
    FILE_NUM = 0
    ITEMS = 0
    SQL_TRACE_MASK = 0
    MIN_EXEC_TIME = 0
    USER_MODE = 0
    USERS =

    参考手册里的这个例子全都是0也是很任性。。。配成这样就算开了SVR_LOG也不会记录SQL日志。后面我自己配一个再发吧

    展开全文
  • application.properties: logging.level.com.alibaba.grow.repository.mapper=debug 在yml文件中: logging: level: com: looedu: mapper: debug
    application.properties:
    
    logging.level.com.alibaba.grow.repository.mapper=debug
    
    在yml文件中:
    logging:
      level:
        com:
          looedu:
            mapper: debug

     

    展开全文
  • 其后,捐献了Apache基金会,成立了iBatis 项目。2010 年5 月,将代码库迁致Google Code,并更名为MyBatis。(导包名:ibatis) MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除 了...
  • 之前做项目,一般会有一张,用户操作记录的数据表,里面主要包括一些,用户请求的URL和请求参数,用以记录用户做过哪些事情。并没有以文件的形式来做记录,当然只适合于一些用户量特别少的系统。 而Mybatis打印SQL...
  • 原文地址: ... 作者:永远的70KG logback中文网: ...-- 日志级别从低到高分为TRACE ,如果设置为WARN,则低于WARN的信息都不会输出 --> ...-- scan:当此属性设置为... 使用mybatis的时候,sql语句是debug下才会打印,而...
  • 项目依赖太多导致sql不打印,下面介绍下处理过程 首先排除包 一定要排除干净,不然会报这个,虽然不报错(有得冲突直接报错了)但是已经冲突了 SLF4J: Class path contains multiple SLF4J bindings. SLF4J:...
  • 准备开一大项目的话,日志系统必不可少。Apache为了让众多的日志工具有一个相同操作方式,实现了一个通用日志工具包:commons-logging。而Log4j基本上是Java平台上最好的日志组件了。使用ommons-logging的Log接口,...
  • 1、maven 项目的 pom.xml,引入依赖p6spy3.0 &lt;!-- https://mvnrepository.com/artifact/p6spy/p6spy --&gt; &lt;dependency&gt; &lt;groupId&gt;p6spy&lt;/groupId&gt; &...
  • SQL 实验项目8_事务控制

    千次阅读 2019-12-25 01:34:57
    笔记本:Intel® Core™ i7-7700HQ CPU @ 2.80GHz 、16G内存、48TB分布式硬盘、Windows 10 1909政府版、SQL Server Management Studio 18.4 实验室电脑:英特尔 酷睿2 双核 T7700 @ 2.40GHz、3G内存、128 G...
  • Golang XORM搭配OpenTracing+Jaeger链路监控让SQL执行一览无遗
  • 本次项目是基于企业大数据经典案例项目(大数据日志分析),全方位、全流程讲解 大数据项目的业务分析、技术选型、架构设计、集群规划、安装部署、整合继承与开发和web可视化交互设计。 项目代码托管于github,大家...
  • 目录 第一步:首先处理pom.xml中的依赖关系,...springboot+mybatis日志转换——log4j转logback配置文件怎么 公司的项目一直都是运行起来会打印所有执行的语句: 好处是:一旦出现问题方便排查,可以清晰的知道...
  • sql server

    千次阅读 2012-03-23 01:14:56
    sql server 作者:Sanle 来源:博客园 发布时间:2006-04-27 13:06 阅读:3402 次 原文链接 [收藏]  1.清空日志:DUMP TRANSACTION 库名 WITH NO_LOG  2.截断事务日志:BACKUP LOG 数据库名 WITH NO...
  • SQL SERVER

    千次阅读 2006-01-17 15:56:00
    SQL Server数据库文件恢复技术SQL Server数据库备份有两种方式,一种是使用BACKUP DATABASE将数据库文件备份出去,另外一种就是直接拷贝数据库文件mdf和日志文件ldf的方式。下面将主要讨论一下后者的备份与恢复。...
  • SQLServer 扫盲

    千次阅读 热门讨论 2014-02-12 14:31:38
    谨以本文记录本人成长历程,并分享各位SQL Server数据库管理系统使用者。本系列包含个人认为一个DBA应该具有的各项素质,系列文章将以下面列表展示,将持续更新,敬请留意及指导,谢谢。下列文章具有一定的优先级...
  • 1.项目A中有一个log4j.properties(配置为把日志输出到以项目名称命名的文件夹中)  2.为了减轻tomcat负担,把项目A的WEB-INF/lib下的所有jar文件拷贝到tomcat下的lib中并修改catalina.properties对其加载  3.把...
  • 什么是 SQL 注入速查表?SQL注入速查表是可以为你提供关于不同种类 SQL注入漏洞 的详细信息的一个资源。这份速查表对于经验丰富的渗透测试人员,或者刚开始接触 Web应用安全 的初学者,都是一份很好的参考资料。...
  • 精通SQL

    千次阅读 2009-10-13 15:32:00
    精通SQL查询语句(精华篇)2009-02-26 15:19一、 简单查询 简单的Transact-SQL查询只包括选择列表、FROM子句和WHERE子句。它们分别说明所查询列、查询的表或视图、以及搜索条件等。例如,下面的语句查询testtable表中...
  • SQL语句

    千次阅读 2008-01-19 20:28:00
    SQL语言由命令、子句、运算和集合函数等构成。在SQL中,数据定义语言DDL(用来建立及定义数据表、字段以及索引等数据库结构)包含的命令有CREATE、DROP、ALTER;数据操纵语言DML(用来提供数据的查询、排序以及筛选...
  • Flink SQL CDC

    千次阅读 2020-09-11 16:09:01
    CDC 被广泛使用在复制数据、更新缓存、微服务间同步数据、审计日志等场景,本文由社区由曾庆东同学分享,主要介绍 Flink SQL CDC 在生产环境的落地实践以及总结的实战经验,文章分为以下几部分:项目背景 ...
  • 快来学习 SQL !!!

    千次阅读 多人点赞 2020-10-15 16:16:47
    SQL 相关学习总结sql sever 2008 建库相关操作SQL 语句相关操作新建数据库建表插入数据查询语句 sql sever 2008 建库相关操作 连接到服务器 新建数据库 输入数据库相关参数 右键数据库名称,新建表 输入列名,...
  • 多数据源前一切正常,配置多数据源后,长时间不操作,第二天重新请求报错,求各位大佬帮忙看一下什么原因,怎么解决~ 报错日志: ger for transaction; nested exception is javax.persistence....
  • sql总结

    万次阅读 2007-04-06 10:54:00
    用循环法Locate赋值,找到就退出. 如:A:Array[1..3] of string=('字段1','字段2','字段3'); for i:=1 to 3 do ADOTable1.Locate(''+A[1]+'','参数',[]);// 如果找到就break ==================================...
  • C# LINQ TO SQL

    千次阅读 2017-11-25 09:21:10
    LINQ to SQL语句(1)之Where   Where操作   适用场景:实现过滤,查询等功能。   说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子句。   Where操作包括3种...
  • SQL总结

    千次阅读 2016-12-01 15:18:11
    用循环法Locate赋值,找到就退出.  如:A:Array[1..3] of string=('字段1','字段2','字段3');  for i:=1 to 3 do  ADOTable1.Locate(''+A[1]+'','参数',[]);//  如果找到就break ====================...
  • 注: 本教程实践基于 Ververica 开源的 sql-training 项目。基于 Flink 1.7.2 。 通过本课你能学到什么? 本文将通过五个实例来贯穿 Flink SQL 的编程实践,主要会涵盖以下几个方面的内容。 如何使用 SQL CLI...
  • 错误信息汇总-SQL CODE和SQL State相关

    千次阅读 2011-09-28 11:38:11
    操作数据库过程中,遇到许多问题,很多都与SQL CODE和SQL State相关,现在把一个完整的SQLCODE和SQLState错误信息和相关解释作以下说明,一来可以自己参考,对DB2错误自行找出原因  (声明:这是搜集网上的资料得...
  • 就是如何让输出sql方便查看,因为出了问题时,要去查错时sql日志我们很大帮助,但hibernate通过p6spy输出很乱,且只能输了到spy.log中,很不好查看,这里是我在项目中的一个解决过程,和大家分享一下,按照...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 17,512
精华内容 7,004
关键字:

给项目配sql日志