我有一个 spring boot 应用程序,其中 spring data-jpa (v3.2.2) 在 java 17 上运行。
我已激活
generate_statistics
并配置了自定义 stats.factory
和自定义 session_factory.statement_inspector
来拦截正在调用的“任何”SQL 方法。
我试图获取有关应用程序及其运行时的所有 SQL 调用的一些额外信息,但统计 API 似乎不涵盖由 spring 预定义触发的插入/删除方法
.save()
,.findById()
来自
.deleteAll()
的和
CrudRepository
方法。请你解释一下为什么?
更具体地说:
我有 1 个实体:
@Entity
@NamedQueries(
@NamedQuery(name="MyEntity.findByField2", query = "select e from MyEntity e where e.field2 = :someValue")
)
@Data
@ToString
@Table(name = "ent")
public class MyEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", updatable = false, nullable = false)
private Long id;
@Version
@Column(name = "version")
private int version = 0;
private String field1;
private Integer field2;
}
1 个存储库:
@Repository
public interface MyEntityRepository extends CrudRepository<MyEntity, Long> {
@Query("select e.id from MyEntity e where e.field1 = :someValue")
public abstract List<Long> getIdsByField1(@Param("someValue") String someValue);
@Query(value = "select field1 from ent where field2 = :someValue", nativeQuery = true)
public abstract List<String> getField1ByField2(@Param("someValue") Integer someValue);
public List<MyEntity> findByField2(@Param("someValue") Integer field2);
}
自定义报表检查器:
@Slf4j
public class SqlQueryInspector implements StatementInspector {
@Override
public String inspect(String s) {
log.error("QUERY: {}", s);
return s;
}
}
以及
application.yaml
集中相应的设置:
spring.jpa.properties.hibernate.session_factory.statement_inspector=org.example.hibernate.SqlQueryInspector
自定义
StatisticsFactory
,创建自定义 StatisticsImpl
:
@Slf4j
public class CustomStatisticsFactory implements StatisticsFactory {
@Override
public StatisticsImplementor buildStatistics(SessionFactoryImplementor sessionFactory) {
return new CustomStatisticsInitiator(sessionFactory);
}
}
@Slf4j
public class CustomStatisticsInitiator extends StatisticsImpl {
public CustomStatisticsInitiator(SessionFactoryImplementor sessionFactory) {
super(sessionFactory);
}
@Override
public void queryExecuted(String hql, int rows, long time) {
log.info("########## [{}], [{}], [{}]", hql, rows, time);
super.queryExecuted(hql, rows, time);
}
}
与
application.yaml
中相应的属性:
spring.jpa.properties.hibernate.stats.factory=org.example.hibernate.CustomStatisticsFactory
我从存储库中调用以下方法:
repo.save(myEntity);
repo.getIdsByField1("someString");
repo.getField1ByField2(1);
repo.findByField2(2);
repo.findAll();
repo.findById(1L);
repo.deleteAll();
在运行时,当通过统计 API 请求统计数据时(请参阅下面使用的代码片段),我发现我只有 4 个
QueryStatistics
,相当于 findAll()
、findByField2(int)
、getIdsByField1(String)
和 getField1ByField2(int)
。但不适用于 save()
、deleteAll()
或 findById
。但是 StatementInspector
会被所有查询调用(但它只包含 sql,而不包含时间)。为什么不是所有查询都通过统计 API 呈现?我如何也可以获得有关其他方法的信息?
获取统计数据代码:
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
Statistics stats = sessionFactory.getStatistics();
String[] queries = stats.getQueries();
for (String query : queries) {
QueryStatistics queryStats = stats.getQueryStatistics(query);
// do something
}
应用程序.属性
spring.jpa.show-sql=true
spring.jpa.hibernate.format_sql=true
spring.jpa.properties.hibernate.generate_statistics=true
logging.level.org.hibernate.stat=DEBUG
您的SpringBoot应用程序
import org.hibernate.SessionFactory;
import org.hibernate.stat.Statistics;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class YourApplication {
public static void main(String[] args) {
SpringApplication.run(YourApplication.class, args);
}
@Bean
public String showHibernateStatistics(SessionFactory sessionFactory) {
Statistics statistics = sessionFactory.getStatistics();
statistics.setStatisticsEnabled(true);
new Thread(() -> {
while (true) {
try {
Thread.sleep(5000); // 5秒更新一次统计信息
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Create (save) count: " + statistics.getEntityInsertCount());
}
}).start();
return "Hibernate statistics are now being displayed on console.";
}
}
运行你的 Spring Boot,然后调用一些东西让你的应用程序保存一些实体。
您可以找到 Spring Boot 应用程序控制台输出:
Hibernate: insert into person (age,name,id) values (?,?,default)
和 Create (save) count: 1
Statistics statistics = sessionFactory.getStatistics();
statistics.setStatisticsEnabled(true);
statistics.getEntityInsertCount());
<-- get Entity Insert count.