[#1836] Document using jOOQ with Spring for transaction support

This commit is contained in:
Lukas Eder 2013-06-14 16:16:47 +02:00
parent e11f5ecb94
commit cf27f62991
4 changed files with 399 additions and 6 deletions

View File

@ -13,6 +13,11 @@
<artifactId>jooq-codegen-maven-example</artifactId>
<name>jOOQ Codegen Maven (Example)</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<org.springframework.version>3.2.3.RELEASE</org.springframework.version>
</properties>
<dependencies>
<dependency>
<groupId>log4j</groupId>
@ -50,11 +55,97 @@
<type>jar</type>
<optional>true</optional>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<!-- Core utilities used by other modules. Define this if you use
Spring Utility APIs (org.springframework.core.*/org.springframework.util.*) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!-- Bean Factory and JavaBeans utilities (depends on spring-core)
Define this if you use Spring Bean APIs (org.springframework.beans.*) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!-- Application Context (depends on spring-core, spring-expression,
spring-aop, spring-beans) This is the central artifact for Spring's Dependency
Injection Container and is generally always defined -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!-- Aspect Oriented Programming (AOP) Framework (depends on spring-core,
spring-beans) Define this if you use Spring AOP APIs (org.springframework.aop.*) -->
<!--
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${org.springframework.version}</version>
</dependency> -->
<!-- Various Application Context utilities, including EhCache, JavaMail,
Quartz, and Freemarker integration Define this if you need any of these integrations -->
<!--
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${org.springframework.version}</version>
</dependency> -->
<!-- Transaction Management Abstraction (depends on spring-core,
spring-beans, spring-aop, spring-context) Define this if you use Spring Transactions
or DAO Exception Hierarchy (org.springframework.transaction.*/org.springframework.dao.*) -->
<!--
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework.version}</version>
</dependency> -->
<!-- JDBC Data Access Library (depends on spring-core, spring-beans,
spring-context, spring-tx) Define this if you use Spring's JdbcTemplate API
(org.springframework.jdbc.*) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!-- Object-to-Relation-Mapping (ORM) integration with Hibernate,
JPA, and iBatis. (depends on spring-core, spring-beans, spring-context, spring-tx)
Define this if you need ORM (org.springframework.orm.*) -->
<!--
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${org.springframework.version}</version>
</dependency> -->
<!-- Support for testing Spring applications with tools such as JUnit
and TestNG This artifact is generally always defined with a 'test' scope
for the integration testing framework and unit testing stubs -->
<!--
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
<scope>test</scope>
</dependency> -->
</dependencies>
<build>
<plugins>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- Using Apache DBCP as a connection pooling library.
Replace this with your preferred DataSource implementation -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
init-method="createDataSource" destroy-method="close">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:~/maven-test" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<!-- Using Spring JDBC for transaction management -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="transactionAwareDataSource"
class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<constructor-arg ref="dataSource" />
</bean>
<!-- Bridging Spring JDBC data sources to jOOQ's ConnectionProvider -->
<bean class="org.jooq.impl.DataSourceConnectionProvider" name="connectionProvider">
<constructor-arg ref="transactionAwareDataSource" />
</bean>
<bean id="dsl" class="org.jooq.impl.DefaultDSLContext">
<constructor-arg ref="config" />
</bean>
<!-- Invoking an internal, package-private constructor for the example
Implement your own Configuration for more reliable behaviour -->
<bean class="org.jooq.impl.DefaultConfiguration" name="config">
<constructor-arg index="0" ref="connectionProvider" />
<constructor-arg index="1"><null /></constructor-arg>
<constructor-arg index="2"><value type="org.jooq.SQLDialect">H2</value></constructor-arg>
<constructor-arg index="3"><null /></constructor-arg>
<constructor-arg index="4"><null /></constructor-arg>
</bean>
</beans>

View File

@ -0,0 +1,73 @@
/**
* Copyright (c) 2009-2013, Lukas Eder, lukas.eder@gmail.com
* All rights reserved.
*
* This software is licensed to you under the Apache License, Version 2.0
* (the "License"); You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name "jOOQ" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.jooq.test.spring;
import org.jooq.DSLContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
public class Test {
public static void main(String[] args) {
// Configure the Spring application context, loading the bean configuration
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {
"jooq-spring-config-minimal.xml"
});
// Fetch a DSLContext reference
DSLContext dsl = context.getBean("dsl", DSLContext.class);
// Execute a jOOQ query in its isolated "ad-hoc" transaction
// ---------------------------------------------------------
System.out.println(dsl.selectOne().fetch());
// Execute some jOOQ queries in an explicit transaction
// ----------------------------------------------------
PlatformTransactionManager transactionManager =
context.getBean("transactionManager", PlatformTransactionManager.class);
TransactionStatus tx = transactionManager.getTransaction(new DefaultTransactionDefinition());
dsl.selectOne().fetch();
dsl.selectOne().fetch();
dsl.selectOne().fetch();
transactionManager.commit(tx);
}
}

View File

@ -906,9 +906,194 @@ public class Main {
</section>
<section id="jooq-with-spring">
<title>Using jOOQ with Spring</title>
<title>Using jOOQ with Spring and DBCP</title>
<content>
<p>Feel free to contribute a tutorial!</p>
<p>
jOOQ and Spring are easy to integrate. In this example, we shall integrate:
</p>
<ul>
<li><a href="http://commons.apache.org/proper/commons-dbcp">Apache Commons DBCP</a> as the connection pooling library.</li>
<li><a href="http://www.springsource.org/spring-data">Spring JDBC</a> as the transaction management library.</li>
<li><a href="http://www.jooq.org">jOOQ</a> as the <reference id="sql-building" title="SQL building"/> and <reference id="sql-execution" title="execution"/> library.</li>
</ul>
<p>
The following steps show how to integrate the libraries.
</p>
<h3>Add the required Maven dependencies</h3>
<p>
For this example, we'll create the following Maven dependencies
</p>
<xml><![CDATA[<!-- Use this or the latest Spring RELEASE version -->
<properties>
<org.springframework.version>3.2.3.RELEASE</org.springframework.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>{jooq-version}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.168</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
</dependencies>
]]></xml>
<h3>Create a minimal Spring configuration file</h3>
<p>
The above dependencies are configured together using a Spring Beans configuration:
</p>
<xml><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- Using Apache DBCP as a connection pooling library.
Replace this with your preferred DataSource implementation -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
init-method="createDataSource" destroy-method="close">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:~/maven-test" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<!-- Using Spring JDBC for transaction management -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="transactionAwareDataSource"
class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<constructor-arg ref="dataSource" />
</bean>
<!-- Bridging Spring JDBC data sources to jOOQ's ConnectionProvider -->
<bean class="org.jooq.impl.DataSourceConnectionProvider" name="connectionProvider">
<constructor-arg ref="transactionAwareDataSource" />
</bean>
<bean id="dsl" class="org.jooq.impl.DefaultDSLContext">
<constructor-arg ref="config" />
</bean>
<!-- Invoking an internal, package-private constructor for the example
Implement your own Configuration for more reliable behaviour -->
<bean class="org.jooq.impl.DefaultConfiguration" name="config">
<constructor-arg index="0" ref="connectionProvider" />
<constructor-arg index="1"><null /></constructor-arg>
<constructor-arg index="2"><value type="org.jooq.SQLDialect">H2</value></constructor-arg>
<constructor-arg index="3"><null /></constructor-arg>
<constructor-arg index="4"><null /></constructor-arg>
</bean>
</beans>]]></xml>
<h3>Run a query in the JDBC Connection's transaction:</h3>
<p>
The following simple program shows how you can now easily obtain a <reference id="dsl-context" title="DSLContext" /> instance, from which queries can be executed:
</p>
<java><![CDATA[package org.jooq.test.spring;
import org.jooq.DSLContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
// Configure the Spring application context, loading the bean configuration
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {
"jooq-spring-config-minimal.xml"
});
// Fetch a DSLContext reference
DSLContext dsl = context.getBean("dsl", DSLContext.class);
// Execute a jOOQ query in its JDBC Connection's transaction
// ---------------------------------------------------------
System.out.println(dsl.selectOne().fetch());
}
}]]></java>
<p>
The above example shows how Spring's TransactionAwareDataSourceProxy discovers that a jOOQ query is not executed in a transactional context.
</p>
<h3>Run a query in an "explicit transaction":</h3>
<p>
The following simple program shows how Spring's TransactionAwareDataSourceProxy will discover that several jOOQ queries are executed in the context of an explicitly created transaction
</p>
<java><![CDATA[package org.jooq.test.spring;
import org.jooq.DSLContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
// Configure the Spring application context, loading the bean configuration
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {
"jooq-spring-config-minimal.xml"
});
// Fetch a DSLContext reference
DSLContext dsl = context.getBean("dsl", DSLContext.class);
// Execute some jOOQ queries in an explicit transaction
// ----------------------------------------------------
PlatformTransactionManager transactionManager =
context.getBean("transactionManager", PlatformTransactionManager.class);
TransactionStatus tx = transactionManager.getTransaction(new DefaultTransactionDefinition());
dsl.selectOne().fetch();
dsl.selectOne().fetch();
dsl.selectOne().fetch();
transactionManager.commit(tx);
}
}]]></java>
<p>
Of course, in an actual productive setup, you are more likely to use Spring's AOP features to declare transactions and transactional behaviour on service methods, instead of explicitly starting and committing / rollbacking transactions. There are many other transaction models that you can choose to use with jOOQ.
</p>
</content>
</section>