8, jOOQ series tutorial - Spring Boot and jOOQ integration

Keywords: Programming Spring JDBC MySQL Maven

Complete tutorial: https://jooq.diamondfsd.com/

In the current situation of the prevalence of micro services, the micro service system based on Spring Boot or Spring Cloud is the mainstream, and it is also the new selection direction in the current business scenario

Compared with using Spring directly, using Spring Boot to integrate jOOQ is relatively simple

Maven dependence

Spring Boot officially supports jOOQ, so you only need to simply reference Spring Boot starter jOOQ and the corresponding jdbc driver

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jooq</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
        <groupId>org.jooq</groupId>
        <artifactId>jooq-codegen</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>

To configure

The biggest feature of Spring Boot is that there are many autoconfigurations. Spring Boot starter jooq relies on Spring Boot starter JDBC, which automatically configures data sources, transaction managers, etc

Spring Boot starter jooq automatically configures org.jooq.Configuration and org.jooq.DSLContext objects. We only need to write the data source related configuration in src/main/resources/application.yml, and all the rest can be handed over to Spring Boot for processing

  • src/main/resources/application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/learn-jooq?serverTimezone=GMT%2B8
    username: root
    password: root

Run / test

Start the Spring Boot service directly through the main method

@SpringBootApplication
public class Section8Main {
    public static void main(String[] args) {
        SpringApplication.run(Section8Main.class);
    }
}

In the test case, use the SpringBootTest annotation

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Section8Main.class)
@Transactional
@Rollback
public class BaseTest {
    @Autowired
    DSLContext dslContext;

    @Autowired
    Configuration configuration;

    @Autowired
    TransactionManager transactionManager;

    @Test
    public void empty() {
        Assertions.assertNotNull(dslContext);
        Assertions.assertNotNull(configuration);
        Assertions.assertNotNull(transactionManager);
    }
}

Source code analysis of JooqAutoConfiguration

The following is the auto configuration source code of jOOQ, copied from spring boot autoconfigure. It can be seen that this configuration will be executed after data source configuration and transaction configuration

We often use Bean dslContext and jooqConfiguration. Most automatically configured beans use @ ConditionalOnMissingBean annotation, which indicates that the configuration marked by the annotation will be executed only when there is no Bean

  • org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration
/**
 * {@link EnableAutoConfiguration Auto-configuration} for JOOQ.
 *
 * @author Andreas Ahlenstorf
 * @author Michael Simons
 * @author Dmytro Nosan
 * @since 1.3.0
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(DSLContext.class)
@ConditionalOnBean(DataSource.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, TransactionAutoConfiguration.class })
public class JooqAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean(ConnectionProvider.class)
	public DataSourceConnectionProvider dataSourceConnectionProvider(DataSource dataSource) {
		return new DataSourceConnectionProvider(new TransactionAwareDataSourceProxy(dataSource));
	}

	@Bean
	@ConditionalOnBean(PlatformTransactionManager.class)
	public SpringTransactionProvider transactionProvider(PlatformTransactionManager txManager) {
		return new SpringTransactionProvider(txManager);
	}

	@Bean
	@Order(0)
	public DefaultExecuteListenerProvider jooqExceptionTranslatorExecuteListenerProvider() {
		return new DefaultExecuteListenerProvider(new JooqExceptionTranslator());
	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingBean(DSLContext.class)
	@EnableConfigurationProperties(JooqProperties.class)
	public static class DslContextConfiguration {

		@Bean
		public DefaultDSLContext dslContext(org.jooq.Configuration configuration) {
			return new DefaultDSLContext(configuration);
		}

		@Bean
		@ConditionalOnMissingBean(org.jooq.Configuration.class)
		public DefaultConfiguration jooqConfiguration(JooqProperties properties, ConnectionProvider connectionProvider,
				DataSource dataSource, ObjectProvider<TransactionProvider> transactionProvider,
				ObjectProvider<RecordMapperProvider> recordMapperProvider,
				ObjectProvider<RecordUnmapperProvider> recordUnmapperProvider, ObjectProvider<Settings> settings,
				ObjectProvider<RecordListenerProvider> recordListenerProviders,
				ObjectProvider<ExecuteListenerProvider> executeListenerProviders,
				ObjectProvider<VisitListenerProvider> visitListenerProviders,
				ObjectProvider<TransactionListenerProvider> transactionListenerProviders,
				ObjectProvider<ExecutorProvider> executorProvider) {
			DefaultConfiguration configuration = new DefaultConfiguration();
			configuration.set(properties.determineSqlDialect(dataSource));
			configuration.set(connectionProvider);
			transactionProvider.ifAvailable(configuration::set);
			recordMapperProvider.ifAvailable(configuration::set);
			recordUnmapperProvider.ifAvailable(configuration::set);
			settings.ifAvailable(configuration::set);
			executorProvider.ifAvailable(configuration::set);
			configuration.set(recordListenerProviders.orderedStream().toArray(RecordListenerProvider[]::new));
			configuration.set(executeListenerProviders.orderedStream().toArray(ExecuteListenerProvider[]::new));
			configuration.set(visitListenerProviders.orderedStream().toArray(VisitListenerProvider[]::new));
			configuration.setTransactionListenerProvider(
					transactionListenerProviders.orderedStream().toArray(TransactionListenerProvider[]::new));
			return configuration;
		}
	}
}

If we need to use multiple data sources, we can use the exclude option in @ SpringBootApplication in the startup portal to prevent Spring Boot from automatically configuring the data sources and the configuration of jOOQ. Finally, refer to the previous article on multiple data sources, and then perform the same configuration. Spring Boot is essentially the integration of spring framework

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, 
                                  JooqAutoConfiguration.class, 
                                  TransactionAutoConfiguration.class})

Content summary

Source code of this chapter: https://github.com/k55k32/learn-jooq/tree/master/section-8

Through this chapter, we can see that the integration of Spring Boot saves a lot of work compared with the direct use of Spring. Many configurations are automatically configured by Spring Boot. Therefore, the following articles will be explained based on this, and the source code demonstration will be expanded based on the source code of this chapter

In addition, this is the end of the integration related chapters. In the following chapters, some problems in the actual business will be solved. For example, the DAO currently generated by jOOQ only contains some basic queries. In business development, multi criteria query, pagination query and association query are not very supported. In the following chapters, we will explain some practical business problems

Posted by Hagaroo on Wed, 26 Feb 2020 02:47:19 -0800