JOOQ(Java Object Oriented Querying),Java面向对象查询,是一个类型安全的ORM框架
JOOQ使用APT技术,通过分析数据库,对每个数据表和试图生成对应的Bean和查询对象,实现类型安全的ORM操作
SpringBootStarterParent管理了JOOQ依赖,可以不用设置版本号
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jooq</artifactId>
</dependency>
JOOQ需要通过APT动态生成需要的Java类,所以需要配置Maven插件
重要的配置项:
executions.execution.goals.goal
如果需要在 mvn compile
的时候执行apt,需要此设置 dependencies.dependency
数据库驱动所在包 configuration.jdbc
数据库连接配置 configuration.generator.database.inputSchema
指定数据库名称 configuration.generator.target.packageName
指定输出包名 configuration.generator.target.packageName
指定输出位置 <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>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
<configuration>
<jdbc>
<url>jdbc:mysql://localhost:3306/foo</url>
<user>root</user>
<password>root</password>
</jdbc>
<generator>
<database>
<includes>.*</includes>
<inputSchema>foo</inputSchema>
</database>
<target>
<packageName>jooq</packageName>
<directory>${basedir}/target/generated-sources/java</directory>
</target>
</generator>
</configuration>
</plugin>
</plugins>
</build>
执行成功后,会在 /target/generated-sources
目录下生成所需的Class
package bj.mybatis;
import com.zaxxer.hikari.HikariDataSource;
import jooq.tables.records.UserRecord;
import org.jooq.*;
import org.jooq.conf.ParamType;
import org.jooq.impl.DSL;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.annotation.Resource;
import javax.sql.DataSource;
import javax.validation.constraints.NotNull;
import static jooq.tables.User.USER;
/**
* Created by BaiJiFeiLong@gmail.com at 2018/12/11 上午9:57
*/
@SpringBootApplication(exclude = QuartzAutoConfiguration.class)
public class App implements ApplicationListener<ApplicationReadyEvent> {
public static void main(String[] args) {
new SpringApplication(App.class) {{
setWebApplicationType(WebApplicationType.NONE);
}}.run(args);
}
@Resource
private JdbcTemplate jdbcTemplate;
@Override
public void onApplicationEvent(@NotNull ApplicationReadyEvent event) {
initDatabase();
DSLContext dslContext = DSL.using(dataSource, SQLDialect.MYSQL_8_0);
// 插入方式1: 插入对象
UserRecord userRecord = dslContext.newRecord(USER);
userRecord.setUsername("sky");
userRecord.setRealName("九天");
userRecord.insert();
System.out.println("Inserted user: ");
System.out.println(userRecord);
// 插入方式2: 动态插入
dslContext.insertInto(USER).set(USER.USERNAME, "rain").set(USER.REAL_NAME, "暴雨").execute();
// 查询方式1: 查询完整对象
Result<UserRecord> userRecords = dslContext.selectFrom(USER).fetch();
System.out.println("All records: ");
System.out.println(userRecords);
// SEEK分页查询
System.out.println("SEEK:");
dslContext.selectFrom(USER).orderBy(USER.USERNAME.asc(), USER.REAL_NAME.asc()).seek("rain", "暴雨").limit(10).forEach(System.out::println);
// 查询方式2: 查询指定字段
SelectConditionStep<Record1<String>> where = dslContext.select(USER.REAL_NAME).from(USER).where(USER.ID.eq(2));
Record1<String> stringRecord1 = where.fetchOne();
System.out.println("SQL:");
// 打印SQL。在DSL.using()可以不传dataSource,此时JOOQ做纯SQLBuilder
System.out.println(where.getSQL(ParamType.INLINED));
System.out.println("realName: ");
System.out.println(stringRecord1);
}
@Resource
private DataSource dataSource;
private void initDatabase() {
jdbcTemplate.execute("DROP TABLE IF EXISTS user");
jdbcTemplate.execute("CREATE TABLE user(id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(16) UNIQUE ,real_name VARCHAR(32) CHARSET 'utf8')");
}
@Bean
public DataSource dataSource() {
return new HikariDataSource() {{
this.setJdbcUrl("jdbc:mysql://localhost/foo?characterEncoding=utf-8");
this.setUsername("root");
this.setPassword("root");
}};
}
}
. ____ _ __ _ _
/// / ___'_ __ _ _(_)_ __ __ _ / / / /
( ( )/___ | '_ | '_| | '_ // _` | / / / /
/// ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_/__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.0.RELEASE)
2018-12-11 15:04:05.021 INFO 18538 --- [ main] bj.mybatis.App : Starting App on MacBook-Air-2.local with PID 18538 (/Users/yuchao/temp/java/hellomaven/target/classes started by yuchao in /Users/yuchao/temp/java/hellomaven)
2018-12-11 15:04:05.027 INFO 18538 --- [ main] bj.mybatis.App : No active profile set, falling back to default profiles: default
2018-12-11 15:04:06.422 WARN 18538 --- [ main] o.m.s.mapper.ClassPathMapperScanner : No MyBatis mapper was found in '[bj.mybatis]' package. Please check your configuration.
2018-12-11 15:04:07.529 INFO 18538 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2018-12-11 15:04:07.709 INFO 18538 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2018-12-11 15:04:08.393 WARN 18538 --- [ main] reactor.netty.tcp.TcpResources : [http] resources will use the default LoopResources: DefaultLoopResources {prefix=reactor-http, daemon=true, selectCount=4, workerCount=4}
2018-12-11 15:04:08.393 WARN 18538 --- [ main] reactor.netty.tcp.TcpResources : [http] resources will use the default ConnectionProvider: PooledConnectionProvider {name=http, poolFactory=reactor.netty.resources.ConnectionProvider$$Lambda$282/589610983@112d1c8e}
2018-12-11 15:04:08.645 INFO 18538 --- [ main] bj.mybatis.App : Started App in 4.832 seconds (JVM running for 6.859)
2018-12-11 15:04:08.900 INFO 18538 --- [ main] org.jooq.Constants :
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@ @@ @@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@
@@@@@@@@@@@@@@@@ @@ @@ @@@@@@@@@@
@@@@@@@@@@ @@@@ @@ @@ @@@@@@@@@@
@@@@@@@@@@ @@ @@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@ @@ @@@@@@@@@@
@@@@@@@@@@ @@ @@ @@@@ @@@@@@@@@@
@@@@@@@@@@ @@ @@ @@@@ @@@@@@@@@@
@@@@@@@@@@ @@ @ @ @@@@@@@@@@
@@@@@@@@@@ @@ @@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Thank you for using jOOQ 3.11.5
Inserted user:
+----+--------+---------+
| id|username|real_name|
+----+--------+---------+
| 1|sky |九天 |
+----+--------+---------+
All records:
+----+--------+---------+
| id|username|real_name|
+----+--------+---------+
| 1|sky |九天 |
| 2|rain |暴雨 |
+----+--------+---------+
SEEK:
+----+--------+---------+
| id|username|real_name|
+----+--------+---------+
| 1|sky |九天 |
+----+--------+---------+
SQL:
select `foo`.`user`.`real_name` from `foo`.`user` where `foo`.`user`.`id` = 2
realName:
+---------+
|real_name|
+---------+
|暴雨 |
+---------+
2018-12-11 15:04:09.722 INFO 18538 --- [ Thread-16] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2018-12-11 15:04:09.738 INFO 18538 --- [ Thread-16] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.