Hibernate/JPA如何保证不生成多余的SQL语句?

栏目: Hibernate · 发布时间: 4年前

内容简介:对SQL语句如果没有计数和断言的情况下,很容易失去对当前场景背后执行的SQL的控制,从而导致性能损失。本应用是计数和断言“幕后”触发的SQL语句的示例。计数SQL语句非常有用,以确保您的代码不会生成比你预计的更多的SQL(例如,通过声明预期语句的数量可以轻松检测到N + 1)。第一步:在Maven的pom.xml中添加依赖datasource-proxy和Vlad Mihalcea的db-util:

SQL 语句如果没有计数和断言的情况下,很容易失去对当前场景背后执行的SQL的控制,从而导致性能损失。

本应用是计数和断言“幕后”触发的SQL语句的示例。计数SQL语句非常有用,以确保您的代码不会生成比你预计的更多的SQL(例如,通过声明预期语句的数量可以轻松检测到N + 1)。

第一步:在Maven的pom.xml中添加依赖datasource-proxy和Vlad Mihalcea的db-util:

 <dependency>
            <groupId>net.ttddyy</groupId>
            <artifactId>datasource-proxy</artifactId>
            <version>${datasource-proxy.version}</version>
        </dependency>
        <dependency>
            <groupId>com.vladmihalcea</groupId>
            <artifactId>db-util</artifactId>
            <version>${db-util.version}</version>
        </dependency>

第二步:使用countQuery()创建ProxyDataSourceBuilder:

@Component
<b>public</b> <b>class</b> DatasourceProxyBeanPostProcessor implements BeanPostProcessor {

    <b>private</b> <b>static</b> <b>final</b> Logger logger
            = Logger.getLogger(DatasourceProxyBeanPostProcessor.<b>class</b>.getName());

    @Override
    <b>public</b> Object postProcessAfterInitialization(Object bean, String beanName) {

        <b>if</b> (bean instanceof DataSource) {

            logger.info(() -> <font>"DataSource bean has been found: "</font><font> + bean);

            <b>final</b> ProxyFactory proxyFactory = <b>new</b> ProxyFactory(bean);

            proxyFactory.setProxyTargetClass(<b>true</b>);
            proxyFactory.addAdvice(<b>new</b> ProxyDataSourceInterceptor((DataSource) bean));

            <b>return</b> proxyFactory.getProxy();
        }
        <b>return</b> bean;
    }

    @Override
    <b>public</b> Object postProcessBeforeInitialization(Object bean, String beanName) {
        <b>return</b> bean;
    }

    <b>private</b> <b>static</b> <b>class</b> ProxyDataSourceInterceptor implements MethodInterceptor {

        <b>private</b> <b>final</b> DataSource dataSource;

        <b>public</b> ProxyDataSourceInterceptor(<b>final</b> DataSource dataSource) {
            <b>super</b>();
            <b>this</b>.dataSource = ProxyDataSourceBuilder.create(dataSource)
                    .name(</font><font>"DATA_SOURCE_PROXY"</font><font>)
                    .logQueryBySlf4j(SLF4JLogLevel.INFO)
                    .multiline()
                    .countQuery()
                    .build();
        }

        @Override
        <b>public</b> Object invoke(<b>final</b> MethodInvocation invocation) throws Throwable {

            <b>final</b> Method proxyMethod = ReflectionUtils.
                    findMethod(<b>this</b>.dataSource.getClass(),
                            invocation.getMethod().getName());

            <b>if</b> (proxyMethod != <b>null</b>) {
                <b>return</b> proxyMethod.invoke(<b>this</b>.dataSource, invocation.getArguments());
            }

            <b>return</b> invocation.proceed();
        }
    }
}
</font>

第三步:通过SQLStatementCountValidator.reset()重置计数器:

@SpringBootApplication
<b>public</b> <b>class</b> CountSQLStatementsApplication {

    @Autowired
    <b>private</b> UserService userService;

    <b>public</b> <b>static</b> <b>void</b> main(String args) {
        SpringApplication.run(CountSQLStatementsApplication.<b>class</b>, args);
    }

    @Bean
    <b>public</b> ApplicationRunner init() {
        <b>return</b> args -> {

            userService.userOperationsWithoutTransactional();
            
            SQLStatementCountValidator.reset();      
            userService.userOperationsWithTransactional();

            <font><i>// allow the transaction to commit</i></font><font>
            </font><font><i>// a total of 2 statements instead of 5 as in the case of no explicit transaction</i></font><font>
            assertInsertCount(1);
            assertUpdateCount(0);
            assertDeleteCount(1);
            assertSelectCount(0);
        };
    }
}
</font>

第四步:通过assertInsert{Update/ Delete/Select}Count(long expectedNumberOfSql断言INSERT,UPDATE,DELETE,和SELECT:

@Service
<b>public</b> <b>class</b> UserService {

    @Autowired
    <b>private</b> UserRepository userRepository;

    <b>public</b> <b>void</b> userOperationsWithoutTransactional() {
        User user = <b>new</b> User();

        user.setName(<font>"Jacky Francisco"</font><font>);
        user.setCity(</font><font>"Banesti"</font><font>);
        user.setAge(24);

        SQLStatementCountValidator.reset();

        userRepository.save(user);   </font><font><i>// 1 insert</i></font><font>
        user.setCity(</font><font>"Craiova"</font><font>);
        userRepository.save(user);   </font><font><i>// 1 update</i></font><font>
        userRepository.delete(user); </font><font><i>// 1 delete</i></font><font>

        </font><font><i>// at this point there is no transaction running</i></font><font>
        </font><font><i>// a total of 5 statements, not very good</i></font><font>
        assertInsertCount(1);
        assertUpdateCount(1);
        assertDeleteCount(1);
        assertSelectCount(2);
    }

    @Transactional
    <b>public</b> <b>void</b> userOperationsWithTransactional() {
        User user = <b>new</b> User();

        user.setName(</font><font>"Jacky Francisco"</font><font>);
        user.setCity(</font><font>"Banesti"</font><font>);
        user.setAge(24);
              
        userRepository.save(user);   </font><font><i>// 1 insert</i></font><font>
        user.setCity(</font><font>"Craiova"</font><font>);
        userRepository.save(user);   </font><font><i>// update not triggered since a delete follows</i></font><font>
        userRepository.delete(user); </font><font><i>// 1 delete        </i></font><font>
    }
}
</font>

源代码可以在 这里 找到


以上所述就是小编给大家介绍的《Hibernate/JPA如何保证不生成多余的SQL语句?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

不是为了快乐

不是为了快乐

宗萨蒋扬钦哲仁波切 / 姚仁喜 / 深圳报业集团出版社 / 2013-1 / 38.00元

前行修持是一套完整的实修系统,它既是一切佛法修持的根基,又囊括了所有修持的精华,以及心灵之道上所需的一切;既适合入门者打造学佛基本功,也是修行人需要终生修持的心法。书中除了实际的方法指导之外,还不断启发佛法的珍贵与修持的必要,并处处可见对学佛者的鼓舞和纠正,其最终的用心,是让我们踏上不间断的修持之路,真正转化我们僵硬、散乱和困惑的心。 在现代人看来,快乐,理应是最值得追求的目标。我们希望生活......一起来看看 《不是为了快乐》 这本书的介绍吧!

html转js在线工具
html转js在线工具

html转js在线工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具