Jooq新手在SpringBoot中接入Jooq

参考:https://segmentfault.com/a/1190000006748584?utm_source=tuicool&utm_medium=referral

JOOQ是啥

  JOOQ 是基于Java访问关系型数据库的工具包。JOOQ 既吸取了传统ORM操作数据的简单性和安全性,又保留了原生sql的灵活性,它更像是介于 ORMS和JDBC的中间层。对于喜欢写sql的码农来说,JOOQ可以完全满足你控制欲,可以是用Java代码写出sql的感觉来。就像官网说的那样 :

get back in control of your sql

1.Springboot整合jooq首先加入jar包依赖

<!-- mysql orm pool -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.41</version>
</dependency>
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>2.6.2</version>
</dependency>
<dependency>
    <groupId>org.jooq</groupId>
    <artifactId>jooq</artifactId>
    <version>3.9.1</version>
</dependency>
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/modeo?useUnicode=true&characterEncoding=UTF-8&useSSL=false
    username: modeo
    password: 123456

2.在项目根目录下建立一个文件夹generator目录下加入以下jar包以及建立mysql.xml(一会用到)

3.编辑mysql.xml文件

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.8.0.xsd">
<!-- 配置jdbc驱动连接 -->
<jdbc>
    <driver>com.mysql.jdbc.Driver</driver>
    <url>jdbc:mysql://localhost:3306/admin</url>
    <user>root</user>
    <password>123456</password>
</jdbc>
<generator>
    <!-- 代码生成器 -->
    <name>org.jooq.util.JavaGenerator</name>
    <database>
        <!-- 数据库类型 -->
        <name>org.jooq.util.mysql.MySQLDatabase</name>
        <!-- 数据库名 -->
        <inputSchema>admin</inputSchema>
        <!-- 生成包含,*表示包含所有内容 -->
        <includes>.*</includes>
        <!--剔除,此处未剔除 -->
        <excludes></excludes>
    </database>
    <target>
        <!-- 生成的代码所在的包结构 -->
        <packageName>org.test.jooq.generated</packageName>
        <!-- 生成的代码存放路径,默认会以src同目录开始 -->
        <directory>src/main/java/</directory>
    </target>


    <strategy>
        <matchers>
            <tables>
                <table>
                    <expression>^(.*)$</expression>
                    <tableClass>
                        <transform>PASCAL</transform>
                        <expression>$1</expression>
                    </tableClass>
                    <recordClass>
                        <transform>PASCAL</transform>
                        <expression>$1_P_O</expression>
                    </recordClass>
                </table>
            </tables>
        </matchers>
    </strategy>


</generator>

</configuration>  

4.创建MysqlManager数据库操作工具

public class MysqlManager implements Closeable {
    private static final String DB_DRIVER_NAME = "spring.datasource.driver-class-name";
    private static final String DB_URL = "spring.datasource.url";
    private static final String DB_USERNAME = "spring.datasource.username";
    private static final String DB_PASSWORD = "spring.datasource.password";

    /**
     * Singleton
     */
    private static final MysqlManager INSTANCE = new MysqlManager();

    /**
     * database configuration
     */
    private Configuration configuration = null;
    /**
     * database source
     */
    private HikariDataSource dataSource = null;

    /**
     * get DSL context
     *
     * @return DSLContext
     */
    public DSLContext getContext() {
        return DSL.using(this.configuration);
    }

    /**
     * Constructor
     */
    private MysqlManager() {
        this.dataSource = new HikariDataSource();

        this.dataSource.setDriverClassName(Config.getProperty(DB_DRIVER_NAME));
        this.dataSource.setJdbcUrl(Config.getProperty(DB_URL));
        this.dataSource.setUsername(Config.getProperty(DB_USERNAME));
        this.dataSource.setPassword(Config.getProperty(DB_PASSWORD));

        // 设置连接池的最大/最小 size
        this.dataSource.addDataSourceProperty("maxConnectionsPerPartition", "5");
        this.dataSource.addDataSourceProperty("minConnectionsPerPartition", "1");
        this.dataSource.addDataSourceProperty("idleConnectionTestPeriodInMinutes", "10");
        this.dataSource.addDataSourceProperty("maxConnectionAgeInSeconds", "3600");
        this.dataSource.addDataSourceProperty("idleMaxAgeInMinutes", "300");
        this.dataSource.addDataSourceProperty("cachePrepStmts", "true");
        this.dataSource.addDataSourceProperty("prepStmtCacheSize", "250");
        this.dataSource.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        this.dataSource.addDataSourceProperty("connectionTimeout", "3000");

        TransactionAwareDataSourceProxy proxy = new TransactionAwareDataSourceProxy(this.dataSource);
        DataSourceTransactionManager txMgr = new DataSourceTransactionManager(this.dataSource);
        this.configuration = new DefaultConfiguration().set(new DataSourceConnectionProvider(proxy))
                .set(new SpringTransactionProvider(txMgr)).set(SQLDialect.MYSQL);
    }

    /**
     * Singleton
     *
     * @return instance
     */
    public static MysqlManager getInstance() {
        return INSTANCE;
    }

    /**
     * transaction
     *做事物处理时用
     * @param runnable
     */
    public static void transaction(Runnable runnable) {
        DSLContext context = MysqlManager.getInstance().getContext();
        context.transaction(config -> runnable.run());
    }

    /**
     * Closes this stream and releases any system resources associated
     * with it. If the stream is already closed then invoking this
     * method has no effect.
     *
     * <p> As noted in {@link AutoCloseable#close()}, cases where the
     * close may fail require careful attention. It is strongly advised
     * to relinquish the underlying resources and to internally
     * <em>mark</em> the {@code Closeable} as closed, prior to throwing
     * the {@code IOException}.
     *
     * @throws IOException if an I/O error occurs
     */
    @Override
    public void close() throws IOException {
        if (this.dataSource != null && !this.dataSource.isClosed()) {
            this.dataSource.close();
            this.dataSource = null;
        }

        this.configuration = null;
    }
}

5.在linux系统下在创建的generator目录下运行以下命令就会生成数据库表对应的操作对象(在mysql.xml配置的路径下)

cd generator
java -classpath jooq-3.9.1.jar:jooq-meta-3.9.1.jar:jooq-codegen-3.9.1.jar:mysql-connector-java-5.1.41.jar:. org.jooq.util.GenerationTool mysql.xml

6.具体的数据库操作案例:

(1.)使用事物处理

private static boolean removeSubscribedSymbol(String deviceId, List<MarketSymbolVO> exchangeSymbols) {
    if (exchangeSymbols == null || exchangeSymbols.isEmpty()) {
        return true;
    }

    DSLContext context = MysqlManager.getInstance().getContext();
    GuestSubscribeMarket table = GuestSubscribeMarket.GUEST_SUBSCRIBE_MARKET;
    MysqlManager.transaction(() -> {
        for (MarketSymbolVO item : exchangeSymbols) {
            context.deleteFrom(table).where(table.DEVICE_ID.eq(deviceId), table.TYPE.eq(item.getType()),
                    table.TARGET_ID.eq(item.getId())).execute();
        }
    });

    return true;
}

(2)一般的操作

public static boolean hasSubscribedSymbol(String deviceId) {
    DSLContext context = MysqlManager.getInstance().getContext();
    GuestSubscribeMarket table = GuestSubscribeMarket.GUEST_SUBSCRIBE_MARKET;

    return context.selectFrom(table).where(table.DEVICE_ID.eq(deviceId)).fetchAny() != null;
}

(3)jooq支持纯sql的模式

/**
 * @param period
 * @param coinId
 * @return
 */
public static List<CoinKlineDO> listCoinKlineDO(String period, int coinId) {
    DSLContext context = MysqlManager.getInstance().getContext();
    LocalDate localDate = LocalDate.now(ZoneId.of("GMT"));
    Date now = Date.valueOf(localDate);
    String sql =
            "select * from " + DEFAULT_COIN_KLINE_TABLE + period + " where `coin_id` = ? and `date` <= ? order " +
                    "by `date` desc limit 240";
    List<Record> records = context.fetch(sql, coinId, now);

    return records.stream().map(record -> {
        CoinKlineDO item = new CoinKlineDO();
        item.setAmount((String) record.getValue("amount"));
        item.setOpen((String) record.getValue("open"));
        item.setHigh((String) record.getValue("high"));
        item.setLow((String) record.getValue("low"));
        item.setClose((String) record.getValue("close"));
        item.setTime(((Date) record.getValue("date")).getTime());
        return item;
    }).collect(Collectors.toList());
}
/**
 * add record
 *
 * @param table
 * @param pairId
 * @param item
 * @return
 */
public static boolean addRecord(String table, int pairId, MarketKlineDO item) {
    DSLContext context = MysqlManager.getInstance().getContext();

    InsertQuery<?> query = context.insertQuery(DSL.table(table));
    query.addValue(DSL.field("`pair_id`", Integer.class), pairId);
    query.addValue(DSL.field("`time`", Timestamp.class), new Timestamp(item.getTime()));
    query.addValue(DSL.field("`open`", String.class), item.getOpen());
    query.addValue(DSL.field("`high`", String.class), item.getHigh());
    query.addValue(DSL.field("`low`", String.class), item.getLow());
    query.addValue(DSL.field("`close`", String.class), item.getClose());
    query.addValue(DSL.field("`amount`", String.class), item.getAmount());
    query.addValue(DSL.field("`create_at`", Timestamp.class), new Timestamp(System.currentTimeMillis()));

    return query.execute() > 0;
}
/**
 * add record
 *
 * @param table
 * @param pairId
 * @param items
 * @return
 */
public static boolean addRecords(String table, int pairId, List<MarketKlineDO> items) {
    final boolean[] addRet = {true};
    MysqlManager.transaction(() -> {
        for (MarketKlineDO item : items) {
            boolean ret = addRecord(table, pairId, item);
            if (!ret) {
                addRet[0] = false;
                break;
            }
        }
    });

    return addRet[0];
}

展开阅读全文

没有更多推荐了,返回首页