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=中國山西)]

 

  關於其他的用法在之后實際運用一段時間后總結。

 

補充:關於查詢不到數據返回空數據的問題

jooq查集合沒數據的時候返回的是空集合,查單個bean的時候差不到的時候返回的是null。這也符合大多數框架的設計原則。

補充:Oracle如果字段有默認值,在插入或者修改的時候設為null的時候默認值不會生效。這時候結合Jooq需要設置字段不允許為null,在插入的時候Jooq會插入默認值 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM