springboot打印sql并用AOP监控sql执行时间

项目打印出每句sql,有利于我们维护项目,出现bug时能够及时的找到原因,因此sql的打印和慢sql的监控相当重要。
springboot默认使用的数据源是HikariCP,它的速度较快,但是并不提供监控。我们使用p6spy来进行sql的打印。为方便演示使用H2内嵌式数据库+Jpa,为了便于开发使用lombok提供快捷的注解。

一、生成项目框架

在https://start.spring.io/上选择自己需要的依赖,便可生成一个zip包。我选择的是maven项目,zip解压之后直接使用idea打开就可以开发了springboot打印sql并用AOP监控sql执行时间_第1张图片

二、配置

pom.xml文件中需要添加p6spy的依赖`


			p6spy
			p6spy
			3.8.1

source文件夹下添加spy.properties配置文件提供p6spy的相关配置

# 单行日志
logMessageFormat=com.p6spy.engine.spy.appender.SingleLineFormat
# 使用Slf4J记录sql
appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准,单位秒
outagedetectioninterval=2

application.properties中配置数据库连接相关属性
由于使用的是p6spy,url和driver-class-name与平常不大一样,driver使用的是p6spy提供的Driver,url里面要添加p6spy。
spring.jpa.hibernate.ddl-auto=none让jpa不进行ddl操作,不创建表
注:spring.jpa.properties.hibernate.show_sql=true,spring.jpa.properties.hibernate.format_sql=true
其实也可以使用jpa自带的sql打印

spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver
spring.datasource.url=jdbc:p6spy:h2:mem:testdb
spring.datasource.username=sa
spring.datasource.password=

spring.jpa.hibernate.ddl-auto=none

在项目运行的时候床架数据表:在resource文件夹下创建schema.sql文件,项目运行时会执行文件夹里的sql语句

drop table coffee if exists ;
create table coffee(
  id bigint auto_increment,
  name varchar(64) not null,
  price bigint not null,
  create_time timestamp ,
  update_time timestamp ,
  primary key(id)
);
insert into coffee(name,price,create_time,update_time) values ('latte',30,now(),now())

代码

实体类BaseEntity

@Data      //自动添加get、set、toString方法
@MappedSuperclass    //定义为父类可以被其它类继承
@NoArgsConstructor     //自动添加无参构造方法
@AllArgsConstructor      //自动添加所有参数的构造方法
public class BaseEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @CreationTimestamp    //创建时间
    @Column(updatable = false)   //不可被修改
    private Date createTime;

    @UpdateTimestamp     //修改时间
    private Date updateTime;
}

实体类Coffee

@Entity      //定义为实体类
@Table(name = "coffee")     //关联数据表
@Data
@ToString(callSuper = true)       //生成toString方法并继承父类的toString
@NoArgsConstructor
@AllArgsConstructor
@Builder     //生成builder
@EqualsAndHashCode(callSuper = true)
public class Coffee extends BaseEntity implements Serializable {
    private String name;
    @Type(type = "org.jadira.usertype.moneyandcurrency.joda.PersistentMoneyMinorAmount",
            parameters = {@org.hibernate.annotations.Parameter(name = "currencyCode", value = "CNY")})
    private Money price;
}

repository

public interface CoffeeRepository extends JpaRepository {
    Coffee findCoffeeByName(String name);
}

切面


@Aspect    //定义为切面
@Component     //加component注解和bean注解才能被容器加载
@Slf4j
public class performanceAspect {
    @Around("crud()")      //在方法执行前后执行,使用crud()定义的切点
    public Object logPerformance(ProceedingJoinPoint pjp) throws Throwable{
        long start = System.currentTimeMillis();
        String name="-";
        String result="Y";
        try{
            name = pjp.getSignature().toShortString();
            return pjp.proceed();
        }catch (Throwable t){
            result = "N";
            throw t;
        }finally {
            long end =System.currentTimeMillis();
            log.info("{};{};{}ms",name,result,end-start);
        }
    }

    @Pointcut("execution(* com.changli.aop.repository..*(..))")   //定义切点
    private void crud(){}
}

主程序

@SpringBootApplication
@Slf4j
@EnableAspectJAutoProxy    //开启aspectJ
@EnableJpaRepositories    //开启jpa
@EnableTransactionManagement   //开启事务
public class AopApplication implements CommandLineRunner {
	@Autowired
	private CoffeeRepository coffeeRepository;

	public static void main(String[] args) {
		SpringApplication.run(AopApplication.class, args);
	}

	@Override
	public void run(String... args) throws Exception {
		log.info("latte {}",coffeeRepository.findCoffeeByName("latte"));
	}
}

运行效果

在这里插入图片描述
demo的git地址:https://github.com/struggle1to1win/aop.git

注:此demo是在学习丁雪丰老师课程时跟着写的练习demo,侵删

你可能感兴趣的:(springboot)