简单研究下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&characterEncoding=utf8&autoReconnect=true&autoReconnectForPools=true&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=中国山西)]
关于其他的用法在之后实际运用一段时间后总结。