JOOQ и весна
Кто-нибудь пробовал использовать JOOQ со средой Spring или я открываю новые возможности?
8 ответов
Я хотел использовать 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 работал с пружиной:
- Получить
java.sql.Connection
связан с потоком менеджером транзакций. - Правильно обрабатывать транзакции посредством преобразования исключений
- Поймите, что объекты фабрики 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