Jooq基本操作

简单研究下Jooq的基本操作,在使用一段时间后在做补充。

jooq和Mybatis一样,是dao层的框架,用于操作数据库。

也有和类似于MybatisGenerator的工程,可以实现导出bean和dao接口,目前了解到的是将导出项目的单独作为一个项目,然后将导出的文件拷贝到实际运用的项目。

参考git: https://github.com/qiao-zhi/jooq-code-generator

0. 假设数据库有三张表

1.user表

+--------------+--------------+------+-----+---------+----------------+
| Field        | Type         | Null | Key | Default | Extra          |
+--------------+--------------+------+-----+---------+----------------+
| id           | int(11)      | NO   | PRI | NULL    | auto_increment |
| username     | varchar(20)  | YES  |     | NULL    |                |
| password     | varchar(40)  | YES  |     | NULL    |                |
| userfullname | varchar(10)  | YES  |     | NULL    |                |
| createtime   | date         | YES  |     | NULL    |                |
| isdeleted    | varchar(2)   | YES  |     | NULL    |                |
| sex          | varchar(2)   | YES  |     | NULL    |                |
| address      | varchar(40)  | YES  |     | NULL    |                |
| roles        | varchar(255) | YES  |     | NULL    |                |
| userblank    | varchar(255) | YES  |     | NULL    |                |
+--------------+--------------+------+-----+---------+----------------+

2.country表

+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | int(11)      | NO   | PRI | NULL    | auto_increment |
| countryname | varchar(255) | YES  |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+

3.usercountry表

+-----------+---------+------+-----+---------+-------+
| Field     | Type    | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+-------+
| userid    | int(11) | NO   | PRI | NULL    |       |
| countryid | int(11) | NO   | PRI | NULL    |       |
+-----------+---------+------+-----+---------+-------+

1. 导出数据库表以及dao接口项目

  这个一般是类似于Mybatis的Generator工程一样,单独作为一个工程用于导出数据库相关信息。

1.pom增加映射

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.qlq</groupId>
    <artifactId>jooq</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>jooq</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        
        <!--引入 jooq-codegen -->
        <dependency>
            <groupId>org.jooq</groupId>
            <artifactId>jooq-codegen</artifactId>
            <version>3.12.4</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <!-- Use org.jooq for the Open Source Edition
                org.jooq.pro-java-8 for commercial editions with Java 8 support,
                org.jooq.trial for the free trial edition
                Note: Only the Open Source Edition is hosted on Maven Central.
                Import the others manually from your distribution -->
                <groupId>org.jooq</groupId>
                <artifactId>jooq-codegen-maven</artifactId>
                <version>3.12.4</version>
                <!-- The jOOQ code generation plugin is also executed in the generate-sources phase, prior to compilation -->
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <!-- This is a minimal working configuration. See the manual's section about the code generator for more details -->
                <configuration>
                    <!-- 这里使用配置文件 -->
                    <configurationFile>src/main/resources/jooqConfig.xml</configurationFile>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2.classpath,也就是resources下面新建jooqConfig.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.12.0.xsd">
    <!-- Configure the database connection here -->
    <jdbc>
        <driver>com.mysql.jdbc.Driver</driver>
        <url>jdbc:mysql://localhost:3306/test1?useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true&amp;autoReconnectForPools=true&amp;failOverReadOnly=false</url>
        <user>root</user>
        <password>123456</password>
    </jdbc>

    <generator>
        <!-- The default code generator. You can override this one, to generate your own code style.
             Supported generators:
             - org.jooq.codegen.JavaGenerator
             - org.jooq.codegen.ScalaGenerator
             Defaults to org.jooq.codegen.JavaGenerator -->
        <name>org.jooq.codegen.JavaGenerator</name>

        <database>
            <!-- The database type. The format here is:
                 org.jooq.meta.[database].[database]Database -->
            <name>org.jooq.meta.mysql.MySQLDatabase</name>

            <!-- The database schema (or in the absence of schema support, in your RDBMS this
                 can be the owner, user, database name) to be generated -->
            <!-- 数据库名 -->
            <inputSchema>test1</inputSchema>

            <!-- All elements that are generated from your schema
                 (A Java regular expression. Use the pipe to separate several expressions)
                 Watch out for case-sensitivity. Depending on your database, this might be important! -->
            <!-- 包含哪些表 -->
            <!--<includes>.*</includes>-->
            <includes>user| usercountry| country</includes>

            <!-- All elements that are excluded from your schema
                 (A Java regular expression. Use the pipe to separate several expressions).
                 Excludes match before includes, i.e. excludes have a higher priority -->
            <!-- 排除哪些表,这里支持正则表达式 ,多个条件可以用 | 连接符连接-->
            <!-- 例如:TEST | OTHERS 生成代码时就不会把叫做TEST和OTHERS的表包括进去了-->
            <excludes></excludes>
        </database>

        <!-- Optional: The programmatic or configurative generator strategy. -->
        <strategy>
            <matchers>
                <tables>
                    <table>
                        <tableClass>
                            <transform>UPPER</transform>
                        </tableClass>
                        <pojoClass>
                            <!-- <expression>*+Model</expression> -->
                        </pojoClass>
                    </table>
                </tables>
            </matchers>
        </strategy>
        <generate>
            <pojos>true</pojos>
            <daos>true</daos>
            <interfaces>true</interfaces>
            <jpaAnnotations>false</jpaAnnotations>
            <springAnnotations>false</springAnnotations>
        </generate>

        <target>
            <!-- The destination package of your generated classes (within the destination directory) -->
            <!-- 生成的代码存放的包名 -->
            <packageName>cn.qlq.jooq</packageName>

            <!-- The destination directory of your generated classes. Using Maven directory layout here -->
            <!-- 存放的路径 -->
            <directory>src/main/java/</directory>
        </target>
    </generator>
</configuration>

可以指定需要导出哪些表,如果是全部表可以用<includes>.*</includes>;也可以用 <includes>user| usercountry| country</includes> 导出指定的三个表,用|做分隔符。

3.导出表:

直接运行:

$ mvn compile

或者:

$ mvn jooq-codegen:generate

再或者用IDEA直接运行:

 4.查看生成的文件

目录结构如下:

 Test是数据库描述信息;Tables是所有的表的信息;Keys是约束;Indexs是索引信息。

2.Springboot中使用Jooq

主要测试简单的增删改查。

1.pom新增

        <!--引入 Jooq -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jooq</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jooq</groupId>
            <artifactId>jooq-meta</artifactId>
            <version>3.12.4</version>
        </dependency>

2.上面导出的dao实现类接口层加上注入Spring的注解

3.测试

测试类如下:

package test;

import cn.qlq.MySpringBootApplication;
import cn.qlq.jooq.tables.COUNTRY;
import cn.qlq.jooq.tables.USER;
import cn.qlq.jooq.tables.USERCOUNTRY;
import cn.qlq.jooq.tables.daos.CountryDao;
import cn.qlq.jooq.tables.daos.UserDao;
import cn.qlq.jooq.tables.daos.UsercountryDao;
import cn.qlq.jooq.tables.pojos.Country;
import cn.qlq.jooq.tables.pojos.User;
import cn.qlq.jooq.tables.pojos.Usercountry;
import cn.qlq.jooq.tables.records.UserRecord;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.jooq.Record4;
import org.jooq.Result;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MySpringBootApplication.class)
@ServletComponentScan("cn.qlq")
public class Jooqtest {

    @Autowired
    @Qualifier("userDao2")
    private UserDao userDao;

    @Autowired
    @Qualifier("countryDao2")
    private CountryDao countryDao;

    @Autowired
    private UsercountryDao userCountryDao;

    @Autowired
    private DSLContext context;

    @PostConstruct//表示在userDao构造完成之后执行
    private void createDao() {
        userDao = new UserDao(context.configuration());
        countryDao = new CountryDao(context.configuration());
        userCountryDao = new UsercountryDao(context.configuration());
    }

    @Test
    public void testAdd() {
        // 添加用户
        User user = new User();
        user.setId(1);
        user.setUsername("zhangsan");
        user.setUserfullname("张三");
        user.setAddress("测试地址");
        user.setSex("男");
        userDao.insert(user);

        // 添加城市,添加两个
        Country country = new Country();
        country.setId(1);
        country.setCountryname("中国北京");
        Country country2 = new Country();
        country2.setId(2);
        country2.setCountryname("中国山西");
        countryDao.insert(country, country2);

        // 维护关系
        Usercountry userCountry = new Usercountry();
        userCountry.setUserid(1);
        userCountry.setCountryid(1);
        Usercountry userCountry2 = new Usercountry();
        userCountry2.setUserid(1);
        userCountry2.setCountryid(2);
        userCountryDao.insert(userCountry, userCountry2);

        System.out.println("增加成功");
    }

    @Test
    public void testSelect() {
        List<User> users = userDao.findAll();
        System.out.println(users);
    }

    @Test
    public void testDelete() {
        userDao.deleteById(1);
        System.out.println("删除成功");
    }

    // =====S 使用dslContext操作
    private USER TABLE_USER = USER.USER;
    private COUNTRY TABLE_COUNTRY = COUNTRY.COUNTRY;
    private USERCOUNTRY TABLE_USER_COUNTRY = USERCOUNTRY.USERCOUNTRY;

    /**
     * DSL 查询单个
     */
    @Test
    public void testSelect2() {
        Result<UserRecord> users = context.selectFrom(TABLE_USER).where("id = 1").and(TABLE_USER.ID.equal(1)).orderBy(1).fetch();
        for (UserRecord userRecord : users) {
            System.out.println(userRecord);
        }

        System.out.println("=====");

        List<User> results = context.selectFrom(TABLE_USER).where("id = 1").and(TABLE_USER.ID.equal(1)).orderBy(1).fetchInto(User.class);
        System.out.println(results);
    }

    /**
     * 联合查询
     */
    @Test
    public void testSelect3() {
        // 简单的联合查询
        Result<Record4<Integer, String, String, String>> fetch = context.select(TABLE_USER.ID, TABLE_USER.USERNAME, TABLE_USER.USERFULLNAME, TABLE_COUNTRY.COUNTRYNAME)
                .from(TABLE_USER, TABLE_USER_COUNTRY, TABLE_COUNTRY)
                .where(TABLE_USER.ID.equal(TABLE_USER_COUNTRY.USERID)).and(TABLE_USER_COUNTRY.USERID.equal(TABLE_COUNTRY.ID)).fetch();
        System.out.println(fetch);

        System.out.println("====1====");

        // 处理结果塞到map中
        List<Map<String, Object>> results = new ArrayList<>();
        fetch.forEach(record -> {
            Map<String, Object> map = new HashMap<>();
            Field<?>[] fields = record.fields();
            for (Field field : fields) {
                Object value = record.getValue(field);
                map.put(field.getName(), value);
            }
            results.add(map);
        });
        System.out.println(results);

        System.out.println("====2====");

        // 查询直接映射到VO中
        List<UserCountryVO> userCountryVOS = context.select(TABLE_USER.ID, TABLE_USER.USERNAME, TABLE_USER.USERFULLNAME, TABLE_COUNTRY.COUNTRYNAME)
                .from(TABLE_USER, TABLE_USER_COUNTRY, TABLE_COUNTRY)
                .where(TABLE_USER.ID.equal(TABLE_USER_COUNTRY.USERID)).and(TABLE_USER_COUNTRY.COUNTRYID.equal(TABLE_COUNTRY.ID)).fetchInto(UserCountryVO.class);
        System.out.println(userCountryVOS);
    }
}

createDao方法内部的操作是必须的,否则会报一个错。

(1)testAdd  方法测试

(2)testSelect 方法测试结果如下:

[User (1, zhangsan, null, 张三, null, null, 男, 测试地址, null, null)]

(3)testSelect2 测试结果:

+----+--------+--------+------------+----------+---------+----+-------+------+---------+
|  id|username|password|userfullname|createtime|isdeleted|sex |address|roles |userblank|
+----+--------+--------+------------+----------+---------+----+-------+------+---------+
|   1|zhangsan|{null}  |张三          |{null}    |{null}   |男   |测试地址   |{null}|{null}   |
+----+--------+--------+------------+----------+---------+----+-------+------+---------+

=====
[User (1, zhangsan, null, 张三, null, null, 男, 测试地址, null, null)]

(4)测试联合查询:

1》新建VO对象

package test;

import lombok.Data;

@Data
public class UserCountryVO {

    private Long id;

    private String username;

    private String userfullname;

    private String countryname;
}

2》testSelect3  方法测试:  测试多个表的连接查询。Jooq对多表查询的语法还是比较符合SQL写法的,比较方便。

+----+--------+------------+-----------+
|  id|username|userfullname|countryname|
+----+--------+------------+-----------+
|   1|zhangsan|张三          |中国北京       |
|   1|zhangsan|张三          |中国北京       |
+----+--------+------------+-----------+

====1====
[{userfullname=张三, countryname=中国北京, id=1, username=zhangsan}, {userfullname=张三, countryname=中国北京, id=1, username=zhangsan}]
====2====
[UserCountryVO(id=1, username=zhangsan, userfullname=张三, countryname=中国北京), UserCountryVO(id=1, username=zhangsan, userfullname=张三, countryname=中国山西)]

  关于其他的用法在之后实际运用一段时间后总结。

原文地址:https://www.cnblogs.com/qlqwjy/p/13974439.html