引言
最近在实习中,公司用到了Jooq,针对自己的疑问,特地在网上找资料学习
JOOQ是什么?
JOOQ 是基于Java访问关系型数据库的工具包,轻量,简单,并且足够灵活,可以轻松的使用Java面向对象语法来实现各种复杂的sql。对于写Java的码农来说ORMS再也熟悉不过了,不管是Hibernate或者Mybatis,都能简单的使用实体映射来访问数据库。但有时候这些 ‘智能’的对象关系映射又显得笨拙,没有直接使用原生sql来的灵活和简单,而且对于一些如:joins,union, nested selects等复杂的操作支持的不友好。JOOQ 既吸取了传统ORM操作数据的简单性和安全性,又保留了原生sql的灵活性,它更像是介于 ORMS和JDBC的中间层。对于喜欢写sql的码农来说,JOOQ可以完全满足你控制欲,可以是用Java代码写出sql的感觉来。就像官网说的那样 :
get back in control of your sql
相比于流行的Hibernate/Mybatis来说,这货的文档少的可怜,而且大多是英文,但不管这么多,总要先试试,先尝试一下官网的demo
官网地址
开源版——Open Source Edition
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>3.11.4</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-meta</artifactId>
<version>3.11.4</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen</artifactId>
<version>3.11.4</version>
</dependency>
首先要代码生成
需要使用mysql-connector
<profiles>
<profile>
<id>jooq</id>
<properties />
<activation>
<property>
<name>jooq</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<version>${jooq.version}</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<jdbc>
<driver>com.mysql.jdbc.Driver</driver>
<url>xxxxxxx</url>
<user>root</user>
<password>xxxxxx</password>
</jdbc>
<generator>
<database>
<name>org.jooq.util.mysql.MySQLDatabase</name>
<includes>.*</includes>
<excludes />
<inputSchema>xxxx</inputSchema>
</database>
<generate>
<deprecated>false</deprecated>
</generate>
<target>
<packageName>com.jooq</packageName>
<directory>src/main/java</directory>
</target>
<generate>
<pojos>false</pojos>
<daos>false</daos>
</generate>
</generator>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
配置好相关参数后直接maven安装就好了
安装成功后目录下会显示:
这里生成了相关JAVA Record,有了这个就可以直接使用JAVA代码与数据库产生映射。
构造DSLContext
我们使用的是数据源是阿里云Druid
阿里云Druid是一个用于实时查询和分析的高容错、高性能开源分布式系统,旨在快速处理大规模的数据,并能够实现快速查询和分析。
新建DataSourceConfig用于配置Druid连接池:
@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceConfig {
@Primary
@Bean(name = "localhostDatasource")
public DataSource dataSourceConfig(DataSourceProperties dataSourceProperties){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(dataSourceProperties.getUrl());
druidDataSource.setUsername(dataSourceProperties.getUsername());
druidDataSource.setPassword(dataSourceProperties.getPassword());
druidDataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
return druidDataSource;
}
}
在Service层中的构造函数进行初始化:
public class Demo{
private DSLContext dslContext;
public Demo(@Qualifier("localhostDatasource") DataSource dataSource){
ConnectionProvider connectionProvider = new DataSourceConnectionProvider(dataSource);
org.jooq.Configuration configuration = new DefaultConfiguration()
.set(connectionProvider)
.set(SQLDialect.MYSQL);//这里表明了使用的是MYsql数据库
dslContext = DSL.using(configuration);
}
}
这样我们就得到了DSLContext进行数据库的操作了
实现普通的增删改查
@Test
public void insert() {
MyStore store = new MyStore();
store.setName("foo");
store.setAddress("mars No. 1989");
StoreRecord storeRecord = dslContext.newRecord(Tables.STORE, store);
storeRecord.insert();
dslContext.insertInto(Tables.STORE)
.set(Store.STORE.NAME, "bar")
.set(Store.STORE.ADDRESS, "eclipse No.1891")
.execute();
}
@Test
public void find() {
dslContext.selectFrom(Tables.STORE)
.where(Store.STORE.NAME.eq("foo"))
.fetchInto(MyStore.class)
.stream()
.forEach(myStore -> System.out.println(myStore.getName()));
}
@Test
public void update() {
dslContext.update(Tables.STORE)
.set(Store.STORE.ADDRESS, "sun No.1988")
.where(Store.STORE.ID.eq(UInteger.valueOf(1)))
.execute();
}
进阶用法
- 事务
JOOQ 官方提供了 TransactionProvider 对事务的支持,只需要在创建DSLContext的时候设置一下。代码如下:
ConnectionProvider connectionProvider = new DataSourceConnectionProvider(dataSource)
TransactionProvider transactionProvider = new DefaultTransactionProvider(connectionProvider, false);
Configuration configuration = new DefaultConfiguration()
.set(connectionProvider)
.set(transactionProvider)
.set(SQLDialect.MYSQL);
return DSL.using(configuration);
具体例子
@Test
public void transaction() {
dslContext.transaction(configuration -> {
DSL.using(configuration).update(Tables.STORE)
.set(Store.STORE.ADDRESS, "transaction test1")
.where(Store.STORE.ID.eq(UInteger.valueOf(1)))
.execute();
DSL.using(configuration).update(Tables.STORE)
.set(Store.STORE.ADDRESS, "transaction test1")
.where(Store.STORE.ID.eq(UInteger.valueOf(2)))
.execute();
int i = 1/0;
});
}
没错就这么简单,只需要把需要用事务的代码包在transaction里面,假如有异常发生,业务会自动回滚。需要注意一点的是必须使用configuration 重新构建context,要不然不会生效,这也是我为什么没有使用官方提供的事务管理器。正常的项目中一个业务需要组合若干个service 方法来完成,而官方提供的默认事务管理器就需要把所有业务写在一个方法中,这在实际应用中显然是不合理的。幸好JOOQ抽象了事务管理,这样我们就可以集成第三方的事务管理器。
-
其他特性
JOOQ还有很多其他有意思的特性 如对其他语言的支持,数据导出,存储过程,JPA支持等等,感兴趣的可以参阅一下文档。说到文档,不得不说开发者对JOOQ的用心,简单、详细、美观是最直接的感受,并且还有丰富的demo示例,对于编程新手来说上手使用也是手到擒来。 -
SelectJoinStep
public Collection<BalanceModel> getTopBalance(boolean user, boolean bank, int fromRank, int toRank, boolean showHidden)
{
SelectJoinStep<Record4<String, String, String, Long>> from = db.getDSL()
.select(TABLE_BALANCE.ACCOUNT_ID, TABLE_BALANCE.CURRENCY, TABLE_BALANCE.CONTEXT, TABLE_BALANCE.BALANCE)
.from(TABLE_BALANCE.join(TABLE_ACCOUNT).on(TABLE_BALANCE.ACCOUNT_ID.eq(TABLE_ACCOUNT.ID)));
Condition userCond = TABLE_ACCOUNT.IS_UUID.eq(true);
Condition bankCond = TABLE_ACCOUNT.IS_UUID.eq(false);
SelectConditionStep<Record4<String, String, String, Long>> where;
if (!user && !bank)
{
throw new IllegalArgumentException();
}
if (user)
{
where = from.where(userCond);
}
else if (bank)
{
where = from.where(bankCond);
}
else
{
where = from.where(DSL.condition(true));
}
if (!showHidden)
{
where = where.and(TABLE_ACCOUNT.HIDDEN.eq(false));
}
return where.orderBy(TABLE_BALANCE.BALANCE.desc()).limit(fromRank - 1, toRank - fromRank + 1).fetchInto(BalanceModel.class);
}
写在最后
对于在国内占了大半边天的Hibernate/Mybatis,JOOQ还是一个小清新,很多人对它都还陌生。通过上面的简单介绍,也许对你有一点帮助。无论是强大的数据转换能力还是处理业务的灵活性,简洁性,都会带来一些不一样的体验。如果你已经厌倦了ORMS的开发模式,正好又接手一个新的项目,JOOQ也许是一个不错的选择。