JOOQ и весна

Кто-нибудь пробовал использовать JOOQ со средой Spring или я открываю новые возможности?

http://www.jooq.org/

8 ответов

Решение

Да, многие люди (сейчас). И руководство jOOQ включает в себя учебное пособие о том, как начать использовать jOOQ, Spring, Spring-TX и BoneCP:

Есть также очень хорошее руководство от Петри Кайнулайнена, объясняющее каждый шаг по созданию проекта, здесь:

Я хотел использовать jOOQ в качестве библиотеки для построения запросов к Spring JdbcTemplate и связанным классам. К сожалению, jOOQ объединяет две концепции в один и тот же набор классов: генерация SQL и выполнение запросов. В моем случае я хочу первое, но хочу, чтобы Spring справился со вторым. Это работает, хотя. Например, вы можете сделать что-то вроде этого (используя jOOQ 2.x API):

Factory create = new Factory(null, SQLDialect.ORACLE);
getJdbcTemplate().query(
    create.select(create.field(ID_COL),
                  create.field(VALUE_COL))
        .from(FOO_TABLE)
        .where(create.field(ID_COL).equals("ignored"))
        .getSQL(),
    myRowMapper,
    id);

Запускать весенние транзакции с помощью jOOQ намного проще (если я что-то не забыл):

просто оберните ваш источник данных в

org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy

необязательно: отложить открытие соединения JDBC до тех пор, пока не произойдет первый фактический оператор SQL.

org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy

в качестве примера сделайте это для создания фабрики jOOQ с применением "транзакций" и "ленивости"

DataSource rawDS = /* your actual data source */
// (optional) make access lazy
final DataSource lazyDS = new LazyConnectionDataSourceProxy(rawDataSource);
// make spring transactions available in plain jdbc context
final DataSource txDS = new TransactionAwareDataSourceProxy(lazyDS);
// create jOOQ factory
Factory jooq = new Factory(txDS, /* dialect */, /* settings */)
// voila!

Все, что вам нужно сделать / знать, чтобы jOOQ работал с пружиной:

  1. Получить java.sql.Connection связан с потоком менеджером транзакций.
  2. Правильно обрабатывать транзакции посредством преобразования исключений
  3. Поймите, что объекты фабрики jOOQ (несмотря на имя) не являются потокобезопасными. и, следовательно, потребует создания нового объекта для каждого использования (не делайте этот другой ответ).

Поэтому для первого и второго случая я предлагаю следующую суть: https://gist.github.com/3669307 которая делает то, что рекомендует Лукас.

В третьем случае вы можете создать фабрику фабрики (которая содержит DataSource) или просто создать новую Factory объект в каждом методе с использованием проводного DataSource в вашей весенней составляющей.

@Service
public class MyDaoOrService {
    @Autowired
    private void DataSource dataSource;

    @Transactional
    public void doSomeJooq(){
        Settings s = new Settings();
        //You could instead put this jooq configuration xml
         s.getExecuteListeners().add("com.snaphop.jooq.SpringExceptionTranslationExecuteListener");
        MyGeneratedFactory f = new MyGeneratedFactory(dataSource, s);
        f.select(); //etc
    }
}

Что касается слушателя настроек, вы можете использовать поддержку конфигурации JOOQ, чтобы избежать программного создания.

Я не буду рассказывать, как вы настроили DataSource весной, поскольку это покрыто множеством других / лучших мест.

Надеюсь, это будет полезно для кого-то....

Настройка контекста приложения Spring.

 <bean id="propertyConfigurer" 
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="systemPropertiesModeName">
            <value>SYSTEM_PROPERTIES_MODE_OVERRIDE</value>
        </property>
        <property name="searchSystemEnvironment">
            <value type="boolean">true</value>
        </property>
    </bean>



    <bean id="dataSource" 
        class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
        <property name="driverClassName" value="org.h2.Driver"/>
        <property name="url" 
        value="jdbc:h2://${user.home}
        ${file.separator}tracciabilitaCanarini${file.separator}db${file.separator}basedb"/>
        <property name="username" value="sa"/>
        <property name="password" value="sa"/>
    </bean>

    <bean id="datasourceConnection" 
     class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" 
      lazy-init="true" depends-on="dataSource">
        <property name="targetObject">
            <ref bean="dataSource"/>
        </property>
        <property name="targetMethod">
            <value>getConnection</value>
        </property>
    </bean>

    <bean id="publicFactory" class="dbLayer.db.PublicFactory" lazy-init="true"
      depends-on="datasourceConnection" >
        <constructor-arg index="0" ref="datasourceConnection"  />
    </bean>

Он автоматически заполняет общедоступную фабрику данным соединением (и да, это может быть соединение в пуле, с автоматическим закрытием и т. Д., См. Класс DriverManagerDataSource для более подробной конфигурации). А теперь публичный завод. Примечание: нет необходимости изменять исходную общедоступную фабрику, созданную jOOQ.

/**
 * This class is generated by jOOQ
 */
package dbLayer.db;

/**
 * This class is generated by jOOQ.
 */
@javax.annotation.Generated(value    = {"http://www.jooq.org", "2.0.5"},
                            comments = "This class is generated by jOOQ")
public class PublicFactory extends org.jooq.util.h2.H2Factory {

    private static final long serialVersionUID = -1930298411;

    /**
     * Create a factory with a connection
     *
     * @param connection The connection to use with objects created from this factory
     */
    public PublicFactory(java.sql.Connection connection) {
        super(connection);
    }

    /**
     * Create a factory with a connection and some settings
     *
     * @param connection The connection to use with objects created from this factory
     * @param settings The settings to apply to objects created from this factory
     */
    public PublicFactory(java.sql.Connection connection, org.jooq.conf.Settings settings) {
        super(connection, settings);
    }
}

В конце просто позвоните на завод.

 PublicFactory vs = (PublicFactory) SpringLoader.getBean("publicFactory");
    SimpleSelectQuery<VersionRecord> sq = vs.selectQuery(dbLayer.db.tables.Version.VERSION);
    VersionRecord v = null;
                try {
                    v = sq.fetchAny();
                } catch (Exception e) {
                    log.warn("Seems that version table does not exists!", e);
                }

Готово!

Предполагая, что вы используете Spring для создания веб-приложения, вы, вероятно, хотите сделать что-то вроде этого:

try {
  Connection conn = dataSource.getConnection();
  try {
    // Do something with JOOQ
    // No need to use a JdbcTemplate!
  }
  finally {
    if (conn != null) {
      conn.close();
    }
  }
} catch (SQLException e) {
  // your error handling
}

Возможно, вы хотите получить DataSource через внедрение зависимостей Spring, потому что ваш веб-контейнер, Tomcat или whathaveyou, предоставляет DataSource и выполняет пул соединений. В одном из ваших весенних конфигурационных файлов у вас будет что-то вроде

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>

Объект, в котором находится приведенный выше код (или некоторый объект, который предоставляет этот код с источником данных), может иметь конфигурацию в весеннем файле для создания экземпляра его с источником данных, например

<bean id="fooService" class="com.fubar.FooServiceImpl">
  <constructor-arg ref="dataSource" type="javax.sql.DataSource" />
</bean>

Часть строки "jdbc/datasource" будет соответствовать имени ресурса, настроенному в веб-контейнере. Это варьируется, но для Tomcat это может быть файл контекста в conf/Catalina/localhost, например, в домашней папке Tomcat,

<?xml version="1.0" encoding="UTF-8"?>
<Context debug="10" reloadable="true" useNaming="true" antiJARLocking="true">
    <Resource name="jdbc/datasource" auth="Container" type="javax.sql.DataSource"
        maxActive="100" maxIdle="30" maxWait="10000" validationQuery="SELECT 1"
        username="foo" password="fubar" driverClassName="org.postgresql.Driver" 
        url="jdbc:postgresql://localhost/foobase"/>         
</Context>

Для конфигурации Java (которая по умолчанию для Spring Boot) вы можете использовать следующий код:

/* JOOQ Configuration */
@Bean
public DataSourceConnectionProvider dataSourceConnectionProvider() {
    return new DataSourceConnectionProvider(dataSource());
}

@Bean
public DefaultConfiguration defaultConfiguration() {
    DefaultConfiguration defaultConfiguration = new DefaultConfiguration();
    defaultConfiguration.setConnectionProvider(dataSourceConnectionProvider());
    defaultConfiguration.setSQLDialect(SQLDialect.POSTGRES);
    return defaultConfiguration;
}

@Bean
public DSLContext dslContext() {
    return new DefaultDSLContext(defaultConfiguration());
}

Самый простой способ (я нашел) использовать Spring Транзакции с jOOQ приведен здесь: http://blog.liftoffllc.in/2014/06/jooq-and-transactions.html

Посмотрите на этот ответ для лучшего объяснения: /questions/20696536/jooq-i-tranzaktsii/20696560#20696560

Другие вопросы по тегам