Mybatis
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
快速入门
引入依赖
1<?xml version="1.0" encoding="UTF-8"?>
2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4 <modelVersion>4.0.0</modelVersion>
5 <parent>
6 <groupId>org.springframework.boot</groupId>
7 <artifactId>spring-boot-starter-parent</artifactId>
8 <version>2.1.2.RELEASE</version>
9 <relativePath/> <!-- lookup parent from repository -->
10 </parent>
11 <groupId>geektime.spring.data</groupId>
12 <artifactId>mybatis-demo</artifactId>
13 <version>0.0.1-SNAPSHOT</version>
14 <name>mybatis-demo</name>
15 <description>Demo project for Spring Boot</description>
16
17 <properties>
18 <java.version>1.8</java.version>
19 </properties>
20
21 <dependencies>
22 <dependency>
23 <groupId>org.springframework.boot</groupId>
24 <artifactId>spring-boot-starter</artifactId>
25 </dependency>
26 <dependency>
27 <groupId>org.mybatis.spring.boot</groupId>
28 <artifactId>mybatis-spring-boot-starter</artifactId>
29 <version>1.3.2</version>
30 </dependency>
31 <dependency>
32 <groupId>org.joda</groupId>
33 <artifactId>joda-money</artifactId>
34 <version>LATEST</version>
35 </dependency>
36
37 <dependency>
38 <groupId>com.h2database</groupId>
39 <artifactId>h2</artifactId>
40 <scope>runtime</scope>
41 </dependency>
42 <dependency>
43 <groupId>org.projectlombok</groupId>
44 <artifactId>lombok</artifactId>
45 <optional>true</optional>
46 </dependency>
47 <dependency>
48 <groupId>org.springframework.boot</groupId>
49 <artifactId>spring-boot-starter-test</artifactId>
50 <scope>test</scope>
51 </dependency>
52 </dependencies>
53
54 <build>
55 <plugins>
56 <plugin>
57 <groupId>org.springframework.boot</groupId>
58 <artifactId>spring-boot-maven-plugin</artifactId>
59 </plugin>
60 </plugins>
61 </build>
62</project>
application.properties
1# 加载mapper.xml映射文件
2#mybatis.mapper-locations=classpath*:mapper/**/*.xml
3# 别名的扫描
4#mybatis.type-aliases-package=类型别名的包名
5# 转换类的包扫描
6mybatis.type-handlers-package=geektime.spring.data.mybatisdemo.handler
7# 下划线转驼峰
8mybatis.configuration.map-underscore-to-camel-case=true
schema.sql
1create table t_coffee (
2 id bigint not null auto_increment,
3 name varchar(255),
4 price bigint not null,
5 create_time timestamp,
6 update_time timestamp,
7 primary key (id)
8);
MoneyTypeHandler
1package geektime.spring.data.mybatisdemo.handler;
2
3import org.apache.ibatis.type.BaseTypeHandler;
4import org.apache.ibatis.type.JdbcType;
5import org.joda.money.CurrencyUnit;
6import org.joda.money.Money;
7
8import java.sql.CallableStatement;
9import java.sql.PreparedStatement;
10import java.sql.ResultSet;
11import java.sql.SQLException;
12
13/**
14 * 在 Money 与 Long 之间转换的 TypeHandler,处理 CNY 人民币
15 */
16public class MoneyTypeHandler extends BaseTypeHandler<Money> {
17 @Override
18 public void setNonNullParameter(PreparedStatement ps, int i, Money parameter, JdbcType jdbcType) throws SQLException {
19 ps.setLong(i, parameter.getAmountMinorLong());
20 }
21
22 @Override
23 public Money getNullableResult(ResultSet rs, String columnName) throws SQLException {
24 return parseMoney(rs.getLong(columnName));
25 }
26
27 @Override
28 public Money getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
29 return parseMoney(rs.getLong(columnIndex));
30 }
31
32 @Override
33 public Money getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
34 return parseMoney(cs.getLong(columnIndex));
35 }
36
37 private Money parseMoney(Long value) {
38 return Money.of(CurrencyUnit.of("CNY"), value / 100.0);
39 }
40}
Coffee
1package geektime.spring.data.mybatisdemo.model;
2
3import lombok.AllArgsConstructor;
4import lombok.Builder;
5import lombok.Data;
6import lombok.NoArgsConstructor;
7import org.joda.money.Money;
8
9import java.util.Date;
10
11@Data
12@AllArgsConstructor
13@NoArgsConstructor
14@Builder
15public class Coffee {
16 private Long id;
17 private String name;
18 private Money price;
19 private Date createTime;
20 private Date updateTime;
21}
CoffeeMapper
1package geektime.spring.data.mybatisdemo.mapper;
2
3import geektime.spring.data.mybatisdemo.model.Coffee;
4import org.apache.ibatis.annotations.Insert;
5import org.apache.ibatis.annotations.Mapper;
6import org.apache.ibatis.annotations.Options;
7import org.apache.ibatis.annotations.Param;
8import org.apache.ibatis.annotations.Result;
9import org.apache.ibatis.annotations.Results;
10import org.apache.ibatis.annotations.Select;
11
12/**
13 * 提示:insert、delete、update返回的是影响的记录的条数,而不是主键。
14 */
15@Mapper
16public interface CoffeeMapper {
17 @Insert("insert into t_coffee (name, price, create_time, update_time)"
18 + "values (#{name}, #{price}, now(), now())")
19 //使用数据库生成的key
20 @Options(useGeneratedKeys = true)
21 int save(Coffee coffee);
22
23 @Select("select * from t_coffee where id = #{id}")
24 @Results({
25 @Result(id = true, column = "id", property = "id"),
26 @Result(column = "create_time", property = "createTime"),
27 // map-underscore-to-camel-case = true 可以实现一样的效果
28 // @Result(column = "update_time", property = "updateTime"),
29 })
30 Coffee findById(@Param("id") Long id);
31}
启动类
1package geektime.spring.data.mybatisdemo;
2
3import geektime.spring.data.mybatisdemo.mapper.CoffeeMapper;
4import geektime.spring.data.mybatisdemo.model.Coffee;
5import lombok.extern.slf4j.Slf4j;
6import org.joda.money.CurrencyUnit;
7import org.joda.money.Money;
8import org.mybatis.spring.annotation.MapperScan;
9import org.springframework.beans.factory.annotation.Autowired;
10import org.springframework.boot.ApplicationArguments;
11import org.springframework.boot.ApplicationRunner;
12import org.springframework.boot.SpringApplication;
13import org.springframework.boot.autoconfigure.SpringBootApplication;
14
15@SpringBootApplication
16@Slf4j
17//扫描所有Mapper映射
18@MapperScan("geektime.spring.data.mybatisdemo.mapper")
19public class MybatisDemoApplication implements ApplicationRunner {
20 @Autowired
21 private CoffeeMapper coffeeMapper;
22
23 public static void main(String[] args) {
24 SpringApplication.run(MybatisDemoApplication.class, args);
25 }
26
27 @Override
28 public void run(ApplicationArguments args) throws Exception {
29 //保存一种咖啡:特浓
30 Coffee c = Coffee.builder().name("espresso")
31 .price(Money.of(CurrencyUnit.of("CNY"), 20.0)).build();
32 int count = coffeeMapper.save(c);
33 log.info("Save {} Coffee: {}", count, c); //除了已设置属性和回填属性,其他的属性不会自动回填
34 //Save 1 Coffee: Coffee(id=1, name=espresso, price=CNY 20.00, createTime=null, updateTime=null)
35
36 //保存一种咖啡:拿铁
37 c = Coffee.builder().name("latte")
38 .price(Money.of(CurrencyUnit.of("CNY"), 25.0)).build();
39 count = coffeeMapper.save(c);
40 log.info("Save {} Coffee: {}", count, c);
41 //Save 1 Coffee: Coffee(id=2, name=latte, price=CNY 25.00, createTime=null, updateTime=null)
42
43 //查询咖啡:根据ID
44 c = coffeeMapper.findById(c.getId());
45 log.info("Find Coffee: {}", c);
46 //Find Coffee: Coffee(id=2, name=latte, price=CNY 25.00, createTime=Fri Jan 10 17:36:35 CST 2020, updateTime=Fri Jan 10 17:36:35 CST 2020)
47 }
48}
MyBatis Generator (Maven Plugin)
根据数据库表生成相关代码。
- POJO
- Mapper 接口类
- SQL Map XML
pom.xml
1<?xml version="1.0" encoding="UTF-8"?>
2<project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <modelVersion>4.0.0</modelVersion>
6
7 <groupId>com.songguoliang</groupId>
8 <artifactId>spring-boot-mybatis-generator-mysql</artifactId>
9 <version>1.0-SNAPSHOT</version>
10
11 <name>spring-boot-mybatis-generator-mysql</name>
12 <description>Spring Boot教程(十五):Spring Boot集成mybatis generator自动生成代码插件</description>
13 <parent>
14 <groupId>org.springframework.boot</groupId>
15 <artifactId>spring-boot-starter-parent</artifactId>
16 <version>2.1.2.RELEASE</version>
17 <relativePath/> <!-- lookup parent from repository -->
18 </parent>
19 <properties>
20 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
21 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
22 <java.version>1.8</java.version>
23 </properties>
24
25 <dependencies>
26 <!-- mybatis ,添加此依赖只为了生成的代码idea不提示错误而已,和mybatis generator没有关系-->
27 <dependency>
28 <groupId>org.mybatis.spring.boot</groupId>
29 <artifactId>mybatis-spring-boot-starter</artifactId>
30 <version>1.3.2</version>
31 </dependency>
32
33 <dependency>
34 <groupId>org.projectlombok</groupId>
35 <artifactId>lombok</artifactId>
36 <version>1.16.10</version>
37 <scope>provided</scope>
38 </dependency>
39 <!-- mysql -->
40 <dependency>
41 <groupId>mysql</groupId>
42 <artifactId>mysql-connector-java</artifactId>
43 </dependency>
44 </dependencies>
45
46 <build>
47 <plugins>
48 <!--mybatis自动生成代码插件-->
49 <plugin>
50 <groupId>org.mybatis.generator</groupId>
51 <artifactId>mybatis-generator-maven-plugin</artifactId>
52 <version>1.3.6</version>
53 <configuration>
54 <!-- 是否覆盖,true表示会替换生成的JAVA文件,false则不覆盖,为了方便查看效果,此处改成不覆盖 -->
55 <overwrite>false</overwrite>
56 </configuration>
57 <dependencies>
58 <!--mysql驱动包-->
59 <dependency>
60 <groupId>mysql</groupId>
61 <artifactId>mysql-connector-java</artifactId>
62 <version>8.0.13</version>
63 </dependency>
64 </dependencies>
65 </plugin>
66 </plugins>
67 </build>
68</project>
createTable.sql
1SET NAMES utf8mb4;
2SET FOREIGN_KEY_CHECKS = 0;
3
4-- ----------------------------
5-- Table structure for tbl_user
6-- ----------------------------
7DROP TABLE IF EXISTS `tbl_user`;
8CREATE TABLE `tbl_user` (
9 `user_id` bigint(20) NOT NULL,
10 `user_name` varchar(50) DEFAULT NULL,
11 `user_age` int(11) DEFAULT NULL,
12 PRIMARY KEY (`user_id`)
13) ENGINE=InnoDB DEFAULT CHARSET=utf8;
14
15-- ----------------------------
16-- Records of tbl_user
17-- ----------------------------
18BEGIN;
19INSERT INTO `tbl_user` VALUES (1, '张三', 27);
20INSERT INTO `tbl_user` VALUES (2, '李四', 30);
21INSERT INTO `tbl_user` VALUES (3, '王五', 20);
22COMMIT
23
24SET FOREIGN_KEY_CHECKS = 1;
application.properties
1spring.datasource.url=jdbc:mysql://192.168.31.201:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
2spring.datasource.username=root
3spring.datasource.password=123456
4spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
5mybatis.mapper-locations=classpath:**/*Mapper.xml
6mybatis.type-aliases-package=com.songguoliang.springboot.entity
7mybatis.configuration.map-underscore-to-camel-case=true
8logging.level.com.songguoliang.mybatis=debug
src/main/resources/generatorConfig.xml
1
运行插件
发现生成 POJO、Mapper Dao、Mapper XML 。
MyBatis Generator (Java 程序)
**引入依赖 **
1<dependency>
2 <groupId>org.mybatis.spring.boot</groupId>
3 <artifactId>mybatis-spring-boot-starter</artifactId>
4 <version>1.3.0</version>
5 </dependency>
6
7 <dependency>
8 <groupId>org.mybatis.generator</groupId>
9 <artifactId>mybatis-generator-core</artifactId>
10 <scope>test</scope>
11 <version>1.3.2</version>
12 <optional>true</optional>
13 </dependency>
14
15 <dependency>
16 <groupId>commons-io</groupId>
17 <artifactId>commons-io</artifactId>
18 <version>2.5</version>
19 </dependency>
引入插件
test/java/org.mybatis.generator.plugins 包下
AddLimitOffsetPlugin
1package org.mybatis.generator.plugins;
2
3import org.mybatis.generator.api.IntrospectedTable;
4import org.mybatis.generator.api.PluginAdapter;
5import org.mybatis.generator.api.dom.java.*;
6import org.mybatis.generator.api.dom.xml.Attribute;
7import org.mybatis.generator.api.dom.xml.TextElement;
8import org.mybatis.generator.api.dom.xml.XmlElement;
9
10import java.util.List;
11
12public class AddLimitOffsetPlugin extends PluginAdapter {
13
14 public boolean validate(List<String> warnings) {
15 return true;
16 }
17
18 public boolean modelExampleClassGenerated(TopLevelClass topLevelClass,
19 IntrospectedTable introspectedTable) {
20 FullyQualifiedJavaType offsetType = new FullyQualifiedJavaType(
21 "javax.annotation.Generated");
22 topLevelClass.addImportedType(offsetType);
23 topLevelClass.addAnnotation("@Generated(\"" + introspectedTable.getTableConfiguration().getTableName() + "\")");
24 PrimitiveTypeWrapper integerWrapper = FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper();
25
26 Field limit = new Field();
27 limit.setName("limit");
28 limit.setVisibility(JavaVisibility.PRIVATE);
29 limit.setType(integerWrapper);
30 topLevelClass.addField(limit);
31
32 Method limitSet = new Method();
33 limitSet.setVisibility(JavaVisibility.PUBLIC);
34 limitSet.setName("setLimit");
35 limitSet.addParameter(new Parameter(integerWrapper, "limit"));
36 limitSet.addBodyLine("this.limit = limit;");
37 topLevelClass.addMethod(limitSet);
38
39 Method limitGet = new Method();
40 limitGet.setVisibility(JavaVisibility.PUBLIC);
41 limitGet.setReturnType(integerWrapper);
42 limitGet.setName("getLimit");
43 limitGet.addBodyLine("return limit;");
44 topLevelClass.addMethod(limitGet);
45
46 Field offset = new Field();
47 offset.setName("offset");
48 offset.setVisibility(JavaVisibility.PRIVATE);
49 offset.setType(integerWrapper);
50 topLevelClass.addField(offset);
51
52 Method offsetSet = new Method();
53 offsetSet.setVisibility(JavaVisibility.PUBLIC);
54 offsetSet.setName("setOffset");
55 offsetSet.addParameter(new Parameter(integerWrapper, "offset"));
56 offsetSet.addBodyLine("this.offset = offset;");
57 topLevelClass.addMethod(offsetSet);
58
59 Method offsetGet = new Method();
60 offsetGet.setVisibility(JavaVisibility.PUBLIC);
61 offsetGet.setReturnType(integerWrapper);
62 offsetGet.setName("getOffset");
63 offsetGet.addBodyLine("return offset;");
64 topLevelClass.addMethod(offsetGet);
65
66 return true;
67 }
68
69 public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(
70 XmlElement element, IntrospectedTable introspectedTable) {
71 XmlElement isNotNullElement = new XmlElement("if");
72 isNotNullElement.addAttribute(new Attribute("test", "limit > 0"));
73 isNotNullElement.addElement(new TextElement("limit ${limit}"));
74 element.getElements().add(isNotNullElement);
75
76 isNotNullElement = new XmlElement("if");
77 isNotNullElement.addAttribute(new Attribute("test", "offset > 0"));
78 isNotNullElement.addElement(new TextElement("offset ${offset}"));
79 element.getElements().add(isNotNullElement);
80 return true;
81 }
82}
Generator
1package org.mybatis.generator.plugins;
2
3import org.apache.commons.io.IOUtils;
4import org.junit.Test;
5import org.mybatis.generator.api.MyBatisGenerator;
6import org.mybatis.generator.api.ProgressCallback;
7import org.mybatis.generator.config.Configuration;
8import org.mybatis.generator.config.Context;
9import org.mybatis.generator.config.xml.ConfigurationParser;
10import org.mybatis.generator.internal.DefaultShellCallback;
11
12import java.io.*;
13import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.List;
16import java.util.regex.Matcher;
17import java.util.regex.Pattern;
18
19/**
20 * mybatis代码生成插件调用者.
21 */
22public class Generator {
23
24 @Test
25 public void generate() throws Exception {
26 List<String> warnings = new ArrayList<String>();
27 boolean overwrite = true;
28
29 InputStream stream = Generator.class.getClassLoader().getResourceAsStream("generatorConfig.xml");
30
31 ConfigurationParser cp = new ConfigurationParser(warnings);
32 InputStreamReader reader = new InputStreamReader(stream, "utf-8");
33 BufferedReader bufferedReader = new BufferedReader(reader);
34
35 String line = bufferedReader.readLine();
36 StringBuffer buffer = new StringBuffer();
37 while (line != null) {
38 buffer.append(line + "\n");
39 line = bufferedReader.readLine();
40 }
41 String xmlWithParam = buffer.toString();
42
43 System.out.println("------- xml config begin -------");
44 System.out.println(xmlWithParam);
45 System.out.println("------- xml config end -------");
46
47 final Configuration config = cp.parseConfiguration(new ByteArrayInputStream(xmlWithParam.getBytes("utf-8")));
48 DefaultShellCallback callback = new DefaultShellCallback(overwrite);
49 MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
50 System.out.println("------- generator begin -------");
51 ProgressCallback cb = new ProgressCallback() {
52 private Pattern SqlProviderPattern = Pattern.compile("\\w*SqlProvider\\.java");
53 private List<String> taskNames = new ArrayList();
54
55 @Override
56 public void startTask(String taskName) {
57 /*
58 * 输出这些信息从而知道 生成那些类了
59 * Generating Example class for table demo
60 * Generating Primary Key class for table demo
61 * Generating Record class for table demo
62 * Generating Mapper Interface for table demo
63 * Generating SQL Provider for table demo
64 * Saving file DemoExample.java
65 * Saving file DemoKey.java Saving file Demo.java
66 * Saving file DemoMapper.java
67 * Saving file DemoSqlProvider.java
68 */
69 // System.out.println(taskName);
70 taskNames.add( taskName);
71 }
72
73 @Override
74 public void saveStarted(int arg0) {}
75
76 @Override
77 public void introspectionStarted(int arg0) {}
78
79 @Override
80 public void generationStarted(int arg0) {}
81
82 @Override
83 public void done() {
84 for(String taskName : taskNames){
85 Matcher matcher = SqlProviderPattern.matcher(taskName);
86 if (matcher.find()) {
87 final String SqlProviderFilename = matcher.group();
88 System.out.println("处理生成文件,selectByExample 增加mysql分页: " + SqlProviderFilename);
89 List<Context> contexts = config.getContexts();
90 FilenameFilter filter = new FilenameFilter() {
91 @Override
92 public boolean accept(File dir, String name) {
93 return SqlProviderFilename.equalsIgnoreCase(name);
94 }
95 };
96 boolean done = false;
97 for (Context ctx : contexts) {
98 if(done){
99 break;
100 }
101 String targetProject = ctx.getJavaClientGeneratorConfiguration().getTargetProject();
102 String targetPackage = ctx.getJavaClientGeneratorConfiguration().getTargetPackage();
103 String dir = targetProject.replaceAll("\\.", "\\\\") + "\\" + targetPackage.replaceAll("\\.", "\\\\");
104 System.out.println(System.getProperty("user.dir") + dir);
105 File mapperDir = new File(System.getProperty("user.dir"), dir);
106 File[] files = mapperDir.listFiles(filter);
107 if (files != null && files.length > 0) {
108 File sqlProviderFile = files[0];
109 try {
110 Generator.addMysqlLimit(sqlProviderFile);
111 done = true;
112 } catch (Exception e) {
113 e.printStackTrace();
114 }
115 }
116 }
117 if(!done){
118 System.out.println("转换失败!!!! selectByExample 增加mysql分页: " + SqlProviderFilename);
119 } else {
120 System.out.println("转换成功!!!! selectByExample 增加mysql分页: " + SqlProviderFilename);
121 }
122 }
123 }
124 }
125
126 @Override
127 public void checkCancel() throws InterruptedException {}
128 };
129 myBatisGenerator.generate(cb);
130 for (String warning : warnings) {
131 System.out.println(warning);
132 }
133 System.out.println("------- generator end -------");
134 // System.out.println(config.getClassPathEntries());
135 }
136
137 private static void addMysqlLimit(File sqlProviderFile) throws Exception {
138 /*
139 * 这是自动生成的selectByExample 中的代码片段
140 if (example != null && example.getOrderByClause() != null) {
141 ORDER_BY(example.getOrderByClause()); // 整个文件唯一
142 }
143
144 return SQL();
145
146 * 将return SQL()改为下面片段即可:
147
148 String sqlString = SQL();
149 if (example != null && example.getLimit() != null) {
150 sqlString += " limit " + example.getLimit();
151 }
152 if (example != null && example.getOffset() != null) {
153 sqlString += " offset " + example.getOffset();
154 }
155 return sqlString;
156 */
157 BufferedReader reader = new BufferedReader( new FileReader(sqlProviderFile));
158 List<String> lines = IOUtils.readLines(reader);
159 reader.close();
160 String limitString = " String sqlString = SQL();\n" +
161 " if (example != null && example.getLimit() != null) {\n" +
162 " sqlString += \" limit \" + example.getLimit();\n" +
163 " }\n" +
164 " if (example != null && example.getOffset() != null) {\n" +
165 " sqlString += \" offset \" + example.getOffset();\n" +
166 " }\n" +
167 " return sqlString;";
168 ArrayList<String> newLines = new ArrayList<String>();
169
170
171 for (int i=0; i< lines.size();++i) {
172 String line = lines.get(i);
173 newLines.add(line );
174 if(line.replaceAll(" ", "") .equalsIgnoreCase("ORDER_BY(example.getOrderByClause());")) {
175 // 添加下一行大括号和空白行
176 ++i;
177 newLines.add(lines.get(i));
178 ++i;
179 newLines.add(lines.get(i));
180
181 ++i; // 跳过 return SQL();
182 newLines.addAll(Arrays.asList( limitString.split("\n")));
183 }
184 }
185
186// for (String line : newLines) {
187// System.out.println(line);
188// }
189 FileOutputStream writer = new FileOutputStream(sqlProviderFile);
190 IOUtils.writeLines(newLines, "\n",writer,"UTF-8");
191 writer.close();
192 }
193
194 public static void main(String[] args) throws Exception {
195 new Generator().generate();
196 }
197}
generatorConfig.xml 配置文件
test/resources/generatorConfig.xml
1<?xml version="1.0" encoding="UTF-8" ?>
2<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
3<generatorConfiguration>
4
5 <context id="entmobile" targetRuntime="MyBatis3">
6
7 <plugin type="org.mybatis.generator.plugins.AddLimitOffsetPlugin" />
8 <plugin type="org.mybatis.generator.plugins.ToStringPlugin" />
9
10 <commentGenerator>
11 <property name="suppressDate" value="true" />
12 <!-- remove comments -->
13 <property name="suppressAllComments" value="true" />
14 </commentGenerator>
15
16 <jdbcConnection driverClass="com.mysql.jdbc.Driver"
17 connectionURL="jdbc:mysql://192.168.31.201:3306/shop?useUnicode=true&characterEncoding=UTF-8&useSSL=false"
18 userId="root" password="123456" />
19
20 <!-- java type resolver -->
21 <javaTypeResolver>
22 <property name="forceBigDecimals" value="false" />
23 </javaTypeResolver>
24
25 <!-- gem entity -->
26 <!-- data -->
27 <javaModelGenerator targetPackage="com.xdclass.couponapp.domain"
28 targetProject="./src/main/java">
29 <property name="enableSubPackages" value="true" />
30 <property name="trimStrings" value="false" />
31 </javaModelGenerator>
32
33 <!-- //////////////////////////////////////////////////////////////////////////////////////////////////////////////// -->
34 <!-- gem annotated mapper -->
35 <!-- data -->
36 <javaClientGenerator type="ANNOTATEDMAPPER"
37 targetPackage="com.xdclass.couponapp.mapper"
38 targetProject="./src/main/java">
39 <property name="enableSubPackages" value="true" />
40 </javaClientGenerator>
41
42 <table tableName="t_user_coupon">
43 <generatedKey column="id" sqlStatement="JDBC"/>
44 </table>
45
46 <table tableName="t_coupon">
47 <generatedKey column="id" sqlStatement="JDBC"/>
48 </table>
49
50 </context>
51</generatorConfiguration>
运行 Generator 生成逆向工程
example 简介
example 是 mybatis-generator 生成的工具包,用于构建查询语句。
- Example 类可以用来生成一个几乎无限的 where 子句。
- Example 类包含一个内部静态类 Criteria 包含一个用 anded 组合在 where 子句中的条件列表。 Example 类包含一个 List 属性,所有内部类 Criteria 中的子句会用 ored 组合在一起。 使用不同属性的 Criteria 类允许您生成无限类型的 where 子句。
- 创建 Criteria 对象 可以使用 Example 类中的 createCriteria() 或者 or() . 如果 Criteria 对象是用 createCriteria() 创建的,它会自动为 List 属性添加一个 Criteria 对象 - 这使得它更容易写一个简单的 where 子句, 如果您不需要 or 或者其他几个子句组合的话。 用 or(Criteria criteria) 方法创建 Criteria 对象, 方法里的 criteria 对象会被添加进 Criteria 对象的列表中。
启动类
1package com.songguoliang.springboot;
2
3import com.songguoliang.springboot.entity.User;
4import com.songguoliang.springboot.entity.UserExample;
5import com.songguoliang.springboot.mapper.UserMapper;
6import lombok.extern.slf4j.Slf4j;
7import org.mybatis.spring.annotation.MapperScan;
8import org.springframework.beans.factory.annotation.Autowired;
9import org.springframework.boot.ApplicationArguments;
10import org.springframework.boot.ApplicationRunner;
11import org.springframework.boot.SpringApplication;
12import org.springframework.boot.autoconfigure.SpringBootApplication;
13import java.util.List;
14
15@SpringBootApplication
16@MapperScan("com.songguoliang.springboot.mapper")
17@Slf4j
18public class MybatisGeneratorDemoApplication implements ApplicationRunner {
19 @Autowired
20 private UserMapper userMapper;
21
22 public static void main(String[] args) {
23 SpringApplication.run(MybatisGeneratorDemoApplication.class,args);
24 }
25
26 @Override
27 public void run(ApplicationArguments applicationArguments) throws Exception {
28 playWithArtifacts();
29 }
30
31 private void playWithArtifacts() {
32 User tutu = new User().withUserId(4l)
33 .withUserName("秃秃")
34 .withUserAge(30);
35 userMapper.insert(tutu);
36 log.info("User {}", tutu);
37 //User User [Hash = 95322593, userId=4, userName=秃秃, userAge=30]
38
39 UserExample userExample = new UserExample();
40 userExample.createCriteria().andUserAgeEqualTo(30);
41 List<User> users = userMapper.selectByExample(userExample);
42 users.forEach(e -> log.info("selectByExample: {}", e));
43 //selectByExample: User [Hash = 1611221523, userId=2, userName=李四, userAge=30]
44 //selectByExample: User [Hash = 1523510420, userId=4, userName=秃秃, userAge=30]
45
46 }
47}
MyBatis PageHelp
PageHelper-Spring-Boot-Starter 帮助你集成分页插件到 Spring Boot。
官网
- 支持多种数据库
- 支持多种分页方式
- SpringBoot 支持
引入依赖
1<dependency>
2 <groupId>com.github.pagehelper</groupId>
3 <artifactId>pagehelper-spring-boot-starter</artifactId>
4 <version>1.2.10</version>
5 </dependency>
application.properties
1mybatis.type-handlers-package=geektime.spring.data.mybatisdemo.handler
2mybatis.configuration.map-underscore-to-camel-case=true
3
4# pagehelper
5pagehelper.offset-as-page-num=true
6pagehelper.reasonable=true
7pagehelper.page-size-zero=true
8pagehelper.support-methods-arguments=true
data.sql
1insert into t_coffee (name, price, create_time, update_time) values ('espresso', 2000, now(), now());
2insert into t_coffee (name, price, create_time, update_time) values ('latte', 2500, now(), now());
3insert into t_coffee (name, price, create_time, update_time) values ('capuccino', 2500, now(), now());
4insert into t_coffee (name, price, create_time, update_time) values ('mocha', 3000, now(), now());
5insert into t_coffee (name, price, create_time, update_time) values ('macchiato', 3000, now(), now());
CoffeeMapper
1package geektime.spring.data.mybatisdemo;
2
3import com.github.pagehelper.PageInfo;
4import geektime.spring.data.mybatisdemo.mapper.CoffeeMapper;
5import geektime.spring.data.mybatisdemo.model.Coffee;
6import lombok.extern.slf4j.Slf4j;
7import org.apache.ibatis.session.RowBounds;
8import org.mybatis.spring.annotation.MapperScan;
9import org.springframework.beans.factory.annotation.Autowired;
10import org.springframework.boot.ApplicationArguments;
11import org.springframework.boot.ApplicationRunner;
12import org.springframework.boot.SpringApplication;
13import org.springframework.boot.autoconfigure.SpringBootApplication;
14
15import java.util.List;
16
17@SpringBootApplication
18@Slf4j
19@MapperScan("geektime.spring.data.mybatisdemo.mapper")
20public class MybatisDemoApplication implements ApplicationRunner {
21 @Autowired
22 private CoffeeMapper coffeeMapper;
23
24 public static void main(String[] args) {
25 SpringApplication.run(MybatisDemoApplication.class, args);
26 }
27
28 @Override
29 public void run(ApplicationArguments args) throws Exception {
30 //RowBounds演示:每页大小3,第一页
31 coffeeMapper.findAllWithRowBounds(new RowBounds(1, 3))
32 .forEach(c -> log.info("Page(1) Coffee {}", c));
33 //Page(1) Coffee Coffee(id=1, name=espresso, price=CNY 20.00, createTime=Sun Jan 12 14:17:45 CST 2020, updateTime=Sun Jan 12 14:17:45 CST 2020)
34 //Page(1) Coffee Coffee(id=2, name=latte, price=CNY 25.00, createTime=Sun Jan 12 14:17:45 CST 2020, updateTime=Sun Jan 12 14:17:45 CST 2020)
35 //Page(1) Coffee Coffee(id=3, name=capuccino, price=CNY 25.00, createTime=Sun Jan 12 14:17:45 CST 2020, updateTime=Sun Jan 12 14:17:45 CST 2020)
36
37 //RowBounds演示:每页大小3,第二页
38 coffeeMapper.findAllWithRowBounds(new RowBounds(2, 3))
39 .forEach(c -> log.info("Page(2) Coffee {}", c));
40 //Page(2) Coffee Coffee(id=4, name=mocha, price=CNY 30.00, createTime=Sun Jan 12 14:17:45 CST 2020, updateTime=Sun Jan 12 14:17:45 CST 2020)
41 //Page(2) Coffee Coffee(id=5, name=macchiato, price=CNY 30.00, createTime=Sun Jan 12 14:17:45 CST 2020, updateTime=Sun Jan 12 14:17:45 CST 2020)
42 log.info("===================");
43
44 //RowBounds演示:每页大小0,第一页(相当于取出所有记录)
45 coffeeMapper.findAllWithRowBounds(new RowBounds(1, 0))
46 .forEach(c -> log.info("Page(1) Coffee {}", c));
47 log.info("===================");
48
49 //findAllWithParam演示:每页大小3,第一页
50 coffeeMapper.findAllWithParam(1, 3)
51 .forEach(c -> log.info("Page(1) Coffee {}", c));
52
53 //PageInfo演示:每页大小3,第二页
54 List<Coffee> list = coffeeMapper.findAllWithParam(2, 3);
55 PageInfo page = new PageInfo(list);
56 log.info("PageInfo: {}", page);
57 //PageInfo: PageInfo{pageNum=2, pageSize=3, size=2, startRow=4, endRow=5, total=5, pages=2, list=Page{count=true, pageNum=2, pageSize=3, startRow=3, endRow=6, total=5, pages=2, reasonable=true, pageSizeZero=true}[Coffee(id=4, name=mocha, price=CNY 30.00, createTime=Sun Jan 12 14:17:45 CST 2020, updateTime=Sun Jan 12 14:17:45 CST 2020), Coffee(id=5, name=macchiato, price=CNY 30.00, createTime=Sun Jan 12 14:17:45 CST 2020, updateTime=Sun Jan 12 14:17:45 CST 2020)], prePage=1, nextPage=0, isFirstPage=false, isLastPage=true, hasPreviousPage=true, hasNextPage=false, navigatePages=8, navigateFirstPage=1, navigateLastPage=2, navigatepageNums=[1, 2]}
58 }
59}
PageInfo
1PageInfo: PageInfo{
2 pageNum=2, //当前页码
3 pageSize=3,//每页记录数
4 size=2,//当前页的记录数
5 startRow=4,//当前页在数据库中的起始行
6 endRow=5,//当前页在数据库中的结束行
7 total=5,//总记录数
8 pages=2, //总页数
9 list=Page{
10 count=true,
11 pageNum=2,
12 pageSize=3,
13 startRow=3,
14 endRow=6,
15 total=5,
16 pages=2,
17 reasonable=true,
18 pageSizeZero=true
19 }[
20 Coffee(id=4,
21 name=mocha,
22 price=CNY30.00,
23 createTime=SunJan1214: 17: 45CST2020,
24 updateTime=SunJan1214: 17: 45CST2020),
25 Coffee(id=5,
26 name=macchiato,
27 price=CNY30.00,
28 createTime=SunJan1214: 17: 45CST2020,
29 updateTime=SunJan1214: 17: 45CST2020)
30 ],
31 prePage=1,
32 nextPage=0,
33 isFirstPage=false,
34 isLastPage=true,
35 hasPreviousPage=true,
36 hasNextPage=false,
37 navigatePages=8,
38 navigateFirstPage=1,
39 navigateLastPage=2,
40 navigatepageNums=[
41 1,
42 2
43 ]
44}