Hibernate获取执行的SQL语句

7 篇文章 1 订阅
2 篇文章 0 订阅

今天无意间刷到有人问Hibernate怎么获取到执行的SQL语句,下面所有人都回复说代码中取不到,只能去日志文件中读取,感觉太误导人了,其实Hibernate完全是可以取到执行的SQL

 

方法一:

可以通过自定义EmptyInterceptor来实现,非常简单

 

public class TestInterceptor extends EmptyInterceptor {
	private static final long serialVersionUID = -460548083498143271L;

	@Override
		public String onPrepareStatement(String sql) {
			System.out.println(sql);
			//TODO 你想要实现的操作
			return super.onPrepareStatement(sql);
		}
}

使用方式,在sessionFactory bean中设置自定义的EmptyInterceptor ,以配置文件的方式为例

    <!--自定义的EmptyInterceptor-->
    <bean id="testInterceptor" class="com.xxx.xxx.xx.interceptor.TestInterceptor"/>

	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate5.LocalSessionFactoryBean" >
		<property name="dataSource" ref="dataSource" />
        <!--自定义的EmptyInterceptor-->
		<property name="entityInterceptor" ref="testInterceptor"/>
		<property name="packagesToScan">
			<list>
				<value>com.xxxx.**.entity.**</value>
			</list>
		</property>

		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">${spring.jpa.database-platform}</prop>
				<prop key="hibernate.dialect.storage_engine">innodb</prop>
				<prop key="hibernate.show_sql">${spring.jpa.show-sql}</prop>
				<!-- 将SQL脚本进行格式化后再输出 -->
				<prop key="hibernate.format_sql">${spring.jpa.properties.hibernate.format_sql}</prop>
				<prop key="hibernate.hbm2ddl.auto">${spring.jpa.hibernate.ddl-auto}</prop>
				<prop key="hibernate.default_batch_fetch_size">${spring.jpa.properties.hibernate.default_batch_fetch_size}</prop>
			</props>
		</property>
		<property name="implicitNamingStrategy" ref="springImplicitNamingStrategy" />
		<property name="physicalNamingStrategy" ref="springPhysicalNamingStrategy" />
	</bean>

如果使用Spring Boot的java形式配置,使用setEntityInterceptor(Interceptor entityInterceptor)方法即可

 

方法二:

实现StatementInspector接口

public class SqlInspector implements StatementInspector {
	private static final long serialVersionUID = 9132883548949230280L;

	@Override
	public String inspect(String sql) {
		System.out.println(sql);
		return sql;
	}

}

配置

<bean id="sessionFactory"
		class="org.springframework.orm.hibernate5.LocalSessionFactoryBean" >
		<property name="dataSource" ref="dataSource" />
		<property name="packagesToScan">
			<list>
				<value>com.xxxx.**.entity.**</value>
			</list>
		</property>

		<property name="hibernateProperties">
			<props>
                <!-- 拦截sql -->
				<prop key="hibernate.session_factory.statement_inspector">com.xxx.xxx.xx.interceptor.SqlInspector</prop>
				<prop key="hibernate.dialect">${spring.jpa.database-platform}</prop>
				<prop key="hibernate.dialect.storage_engine">innodb</prop>
				<prop key="hibernate.show_sql">${spring.jpa.show-sql}</prop>
				<!-- 将SQL脚本进行格式化后再输出 -->
				<prop key="hibernate.format_sql">${spring.jpa.properties.hibernate.format_sql}</prop>
				<prop key="hibernate.hbm2ddl.auto">${spring.jpa.hibernate.ddl-auto}</prop>
				<prop key="hibernate.default_batch_fetch_size">${spring.jpa.properties.hibernate.default_batch_fetch_size}</prop>
			</props>
		</property>
		<property name="implicitNamingStrategy" ref="springImplicitNamingStrategy" />
		<property name="physicalNamingStrategy" ref="springPhysicalNamingStrategy" />
	</bean>

 

补充:有人私信问配置文件的问题,不明白为什么SessionFactory的bean中的class="org.springframework.orm.hibernate5.LocalSessionFactoryBean",为什么LocalSessionFactoryBean会变位SessionFactory?他们之间的关系是怎样的

看LocalSessionFactoryBean源码

public class LocalSessionFactoryBean extends HibernateExceptionTranslator
		implements FactoryBean<SessionFactory>, ResourceLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {

可以看到LocalSessionFactoryBean实现了FactoryBean<T>接口,再看FactoryBean<T>源码

/*
 * Copyright 2002-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory;

import org.springframework.lang.Nullable;

/**
 * Interface to be implemented by objects used within a {@link BeanFactory} which
 * are themselves factories for individual objects. If a bean implements this
 * interface, it is used as a factory for an object to expose, not directly as a
 * bean instance that will be exposed itself.
 *
 * <p><b>NB: A bean that implements this interface cannot be used as a normal bean.</b>
 * A FactoryBean is defined in a bean style, but the object exposed for bean
 * references ({@link #getObject()}) is always the object that it creates.
 *
 * <p>FactoryBeans can support singletons and prototypes, and can either create
 * objects lazily on demand or eagerly on startup. The {@link SmartFactoryBean}
 * interface allows for exposing more fine-grained behavioral metadata.
 *
 * <p>This interface is heavily used within the framework itself, for example for
 * the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the
 * {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for
 * custom components as well; however, this is only common for infrastructure code.
 *
 * <p><b>{@code FactoryBean} is a programmatic contract. Implementations are not
 * supposed to rely on annotation-driven injection or other reflective facilities.</b>
 * {@link #getObjectType()} {@link #getObject()} invocations may arrive early in the
 * bootstrap process, even ahead of any post-processor setup. If you need access to
 * other beans, implement {@link BeanFactoryAware} and obtain them programmatically.
 *
 * <p><b>The container is only responsible for managing the lifecycle of the FactoryBean
 * instance, not the lifecycle of the objects created by the FactoryBean.</b> Therefore,
 * a destroy method on an exposed bean object (such as {@link java.io.Closeable#close()}
 * will <i>not</i> be called automatically. Instead, a FactoryBean should implement
 * {@link DisposableBean} and delegate any such close call to the underlying object.
 *
 * <p>Finally, FactoryBean objects participate in the containing BeanFactory's
 * synchronization of bean creation. There is usually no need for internal
 * synchronization other than for purposes of lazy initialization within the
 * FactoryBean itself (or the like).
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 08.03.2003
 * @param <T> the bean type
 * @see org.springframework.beans.factory.BeanFactory
 * @see org.springframework.aop.framework.ProxyFactoryBean
 * @see org.springframework.jndi.JndiObjectFactoryBean
 */
public interface FactoryBean<T> {

	/**
	 * The name of an attribute that can be
	 * {@link org.springframework.core.AttributeAccessor#setAttribute set} on a
	 * {@link org.springframework.beans.factory.config.BeanDefinition} so that
	 * factory beans can signal their object type when it can't be deduced from
	 * the factory bean class.
	 * @since 5.2
	 */
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";


	/**
	 * Return an instance (possibly shared or independent) of the object
	 * managed by this factory.
	 * <p>As with a {@link BeanFactory}, this allows support for both the
	 * Singleton and Prototype design pattern.
	 * <p>If this FactoryBean is not fully initialized yet at the time of
	 * the call (for example because it is involved in a circular reference),
	 * throw a corresponding {@link FactoryBeanNotInitializedException}.
	 * <p>As of Spring 2.0, FactoryBeans are allowed to return {@code null}
	 * objects. The factory will consider this as normal value to be used; it
	 * will not throw a FactoryBeanNotInitializedException in this case anymore.
	 * FactoryBean implementations are encouraged to throw
	 * FactoryBeanNotInitializedException themselves now, as appropriate.
	 * @return an instance of the bean (can be {@code null})
	 * @throws Exception in case of creation errors
	 * @see FactoryBeanNotInitializedException
	 */
	@Nullable
	T getObject() throws Exception;

	@Nullable
	Class<?> getObjectType();

	default boolean isSingleton() {
		return true;
	}

}

FactoryBean的源码注释大概意思就是实现这个接口的类实际得到的是T getObject()方法返回的对象,也就是SessionFactory对象,而不是LocalSessionFactoryBean

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 SpringBoot 中,可以通过配置日志级别来获取系统执行过的 SQL 语句。具体实现步骤如下: 1. 打开 application.properties 或 application.yml 配置文件,添加以下配置: ``` logging.level.org.hibernate.SQL=debug logging.level.org.hibernate.type.descriptor.sql.BasicBinder=trace ``` 2. 重启项目,执行 SQL 语句。 3. 在控制台或日志文件中查看输出信息,就可以看到系统执行的 SQL 语句了。 注意:以上配置只是一个示例,具体的 SQL 日志输出方式可能会因为使用的数据库框架或日志框架而有所不同。 ### 回答2: 在Spring Boot中可以通过配置来获取系统执行过的SQL语句。具体步骤如下: 1. 首先,在Spring Boot的配置文件(例如application.properties或application.yml)中配置以下属性: ``` spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true ``` 2. 设置spring.jpa.show-sql为true,表示开启显示SQL语句。这样在系统执行JPA操作时,会在控制台输出相应的SQL语句。 3. 设置spring.jpa.properties.hibernate.format_sql为true,表示格式化显示SQL语句。这样输出的SQL语句会更容易阅读和理解。 4. 重新启动应用程序,当应用程序执行JPA操作时,控制台会打印出相应的SQL语句,包括执行的查询语句、插入语句、更新语句等等。 需要注意的是,以上配置只适用于使用JPA作为持久化框架的情况。如果应用程序使用其他持久化框架(例如Hibernate)或者使用原生的JDBC进行数据库操作,需要根据具体框架的配置方式进行相应的调整。 ### 回答3: 在Spring Boot中获取系统执行过的SQL语句,可以通过配置数据库连接池的属性来实现。具体步骤如下: 1. 添加依赖:在pom.xml文件中添加如下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>net.ttddyy</groupId> <artifactId>datasource-proxy</artifactId> <version>1.7</version> </dependency> ``` 这里使用了datasource-proxy库来拦截SQL语句。 2. 配置数据源:在application.properties或application.yml中配置数据源,例如: ```properties spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false spring.datasource.username=root spring.datasource.password=123456 ``` 3. 配置代理数据源:创建一个配置类,例如: ```java @Configuration public class DataSourceConfig { @Bean @Primary public DataSource dataSource() { ProxyDataSource proxyDataSource = new ProxyDataSource(); proxyDataSource.setDataSource(createActualDataSource()); proxyDataSource.setListener(new MyQueryExecutionListener()); return proxyDataSource; } private DataSource createActualDataSource() { // 创建真实的DataSource并返回 // 例如:return new HikariDataSource(); } private class MyQueryExecutionListener extends AbstractQueryExecutionListener { @Override public void beforeQuery(ExecutionInfo execInfo, List<QueryInfo> queryInfoList) { // 在执行SQL语句之前的操作 } @Override public void afterQuery(ExecutionInfo execInfo, List<QueryInfo> queryInfoList) { // 在执行SQL语句之后的操作 for(QueryInfo queryInfo : queryInfoList) { String sql = queryInfo.getQuery(); // 对执行过的SQL语句进行处理 } } } } ``` 通过以上配置,我们创建了一个代理数据源,其中设置了一个自定义的QueryExecutionListener,当程序执行SQL语句时,该监听器会拦截并将执行过的SQL语句传递给afterQuery方法进行处理。 最后,就可以在程序中通过注入DataSource,并在需要的地方使用它来执行SQL语句,同时也能获取到系统执行过的SQL语句
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值