pom.xml 檔案配置
引入
mybatis generator
<properties>
<mysql.connector.version>5.1.44</mysql.connector.version>
<mybatis.generator.version>1.3.5</mybatis.generator.version>
<mybatis.spring.version>1.3.1</mybatis.spring.version>
<mybatis.version>3.4.4</mybatis.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>${mybatis.generator.version}</version>
<configuration>
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.connector.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>${mybatis.generator.version}</version>
</dependency>
<dependency>
<groupId>com.github.oceanc</groupId>
<artifactId>mybatis3-generator-plugin</artifactId>
<version>0.4.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
<resources>
<resource>
<!--src/main/java 下的 xml 檔案打包時也加入-->
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.*</include>
</includes>
<excludes>
<!--<exclude>test/**/*.*</exclude> -->
</excludes>
</resource>
</resources>
</build>
-
自動生成代碼的核心配置檔案<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
的路徑generatorConfig.xml
-
生成哪種資料庫的代碼,不可省略mysql-connector-java
-
引入第三方的com.github.oceanc
,能夠生成常用的查詢文法jar
-
标簽配置是為了将resources
打包進mybatis 文法 xml 檔案
包,缺少war
檔案代碼是無法執行的xml
-
自動生成可執行代碼的核心org.mybatis.generator
,不可缺少jar
org.mybatis.generator 自帶生成代碼插件
-
org.mybatis.generator.plugins.CachePlugin
二級緩存相關,需要更深入了解一下
-
org.mybatis.generator.plugins.CaseInsensitiveLikePlugin
對字元串比對生成大小寫敏感的方法
-
org.mybatis.generator.plugins.EqualsHashCodePlugin
重寫
中model
和equals
方法,這對比兩個對象的值是否相等很在意義。這個重寫可以通過hashCode
自帶的幫助方法解決,Intellj
-->ALT+Insert
。各處統一使用相同的生成方法即可equals() and hashCode()
-
org.mybatis.generator.plugins.FluentBuilderMethodsPlugin
生成
方法,可以簡潔的指派withXxx()
。這個功能可以通過new MyDomain().withFoo("Test").withBar(4711);
的插件Intellj
實作,使用InnerBuilder
模式。Builder
- org.mybatis.generator.plugins.MapperConfigPlugin
架構使用的配置檔案。感覺沒有什麼用處,生成的配置檔案也沒有生成什麼有用的東西MyBatis 3.x
- org.mybatis.generator.plugins.RenameExampleClassPlugin
預設生成的查詢類是以mybatis
結尾,往往都使用如下配置改成Example
結尾Criteria
<plugin type="org.mybatis.generator.plugins.RenameExampleClassPlugin">
<property name="searchString" value="Example$" />
<property name="replaceString" value="Criteria" />
</plugin>
-
org.mybatis.generator.plugins.RowBoundsPlugin
分頁
-
org.mybatis.generator.plugins.SerializablePlugin
繼承序列化
- org.mybatis.generator.plugins.SqlMapConfigPlugin
iBATIS 2.x
<plugin type = "org.mybatis.generator.plugins.SqlMapConfigPlugin">
<property name="fileName" value="test.xml"/>
<property name="targetPackage" value="com.nd.mybatis"/>
<property name="targetProject" value="src/main/java"/>
</plugin>
- org.mybatis.generator.plugins.ToStringPlugin
model
方法。這個可以通過toString
完成,Intellj
ALT+insert
toString()
-
org.mybatis.generator.plugins.VirtualPrimaryKeyPlugin
如果表沒有主鍵,
有部分方法不會生成,配置幾個虛拟的主鍵,即使在資料庫中并不是主鍵也可以配置。配置方案mybatis
<table tableName="foo">
<property name="virtualKeyColumns" value="ID1, ID2" />
</table>
com.github.oceanc 支援生成代碼插件
受sql dialect的限制,多數plugin目前僅支援 Mysql 5.x
Download
在 Maven Central 上最新的釋出版本是:
<dependency>
<groupId>com.github.oceanc</groupId>
<artifactId>mybatis3-generator-plugin</artifactId>
<version>0.4.0</version>
</dependency>
mybatis3-generator-plugins目前提供了如下可用插件:
- com.github.oceanc.mybatis3.generator.plugin.BatchInsertPlugin
- com.github.oceanc.mybatis3.generator.plugin.JacksonAnnotationPlugin
- com.github.oceanc.mybatis3.generator.plugin.JacksonToJsonPlugin
- com.github.oceanc.mybatis3.generator.plugin.LombokAnnotationPlugin
- com.github.oceanc.mybatis3.generator.plugin.MinMaxPlugin
- com.github.oceanc.mybatis3.generator.plugin.OptimisticLockAutoIncreasePlugin
- com.github.oceanc.mybatis3.generator.plugin.PaginationPlugin
- com.github.oceanc.mybatis3.generator.plugin.SliceTablePlugin
- com.github.oceanc.mybatis3.generator.plugin.SumSelectivePlugin
- com.github.oceanc.mybatis3.generator.plugin.UpdateSqlTextOfUpdateSelectivePlugin
- com.github.oceanc.mybatis3.generator.plugin.WhereSqlTextPlugin
使用
在
MyBatis GeneratorXML Configuration File中添加你需要用到的
<plugin>
元素:
<context id="MysqlTables" targetRuntime="MyBatis3">
<plugin type = "com.github.oceanc.mybatis3.generator.plugin.BatchInsertPlugin" />
<plugin type = "com.github.oceanc.mybatis3.generator.plugin.JacksonAnnotationPlugin" />
<plugin type = "com.github.oceanc.mybatis3.generator.plugin.JacksonToJsonPlugin" />
<plugin type = "com.github.oceanc.mybatis3.generator.plugin.LombokAnnotationPlugin" />
<plugin type = "com.github.oceanc.mybatis3.generator.plugin.MinMaxPlugin" />
<plugin type = "com.github.oceanc.mybatis3.generator.plugin.OptimisticLockAutoIncreasePlugin" />
<plugin type = "com.github.oceanc.mybatis3.generator.plugin.PaginationPlugin" />
<plugin type = "com.github.oceanc.mybatis3.generator.plugin.SliceTablePlugin" />
<plugin type = "com.github.oceanc.mybatis3.generator.plugin.SumSelectivePlugin" />
<plugin type = "com.github.oceanc.mybatis3.generator.plugin.UpdateSqlTextOfUpdateSelectivePlugin" />
<plugin type = "com.github.oceanc.mybatis3.generator.plugin.WhereSqlTextPlugin" />
</context>
為了舉例,假設我們建立一張簡單的賬戶表,并命名為
Account
。DDL如下:
CREATE TABLE `Account` (
`id` bigint(16) NOT NULL,
`create_time` timestamp NOT NULL,
`name` varchar(64) DEFAULT NULL,
`age` tinyint(3) DEFAULT NULL,
`version` int(11) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
如果使用了
SliceTablePlugin
,為了其産生的作用始終有效,推薦将其放置在自定義
<plugin>
聲明的第一條,如上例所示。這麼做的原因是,其他
plugin(BatchInsertPlugin、MinMaxPlugin、和SumSelectivePlugin)
會通過檢測
SliceTablePlugin
是否應用,來适配其效果。
SliceTablePlugin
當資料庫單表資料量過大時,可以通過水準拆分把單表分解為多表。例如,若
Account
表中的預期資料量過大時(也許5、6億),可以把一張
Account
表分解為多張
Account
表。SliceTablePlugin并不會自動建立和執行拆分後的DDL,是以必須手工建立DDL并按下述約定修改表名。
SliceTablePlugin
目前支援兩種分表命名方式:
- 對指定列取模。拆分後的表名為
。如:Account_0、Account_1、Account_3 ......原表名_N
- 對指定的時間類型列,按單自然月拆分。拆分後的表名為
。如:Account_201501、Account_201502 ...... Account_201512原表名_yyyyMM
Xml config
<table tableName="Account_0" domainObjectName="Account">
<property name="sliceMod" value="97"/>
<property name="sliceColumn" value="id"/>
</table>
-
指按取模方式分表,sliceMod
是取模的模數97
-
指取模所使用的列,sliceColumn
是具體列名id
- 利用自然月
Account
字段做拆分:create_time
<table tableName="Account_0" domainObjectName="Account">
<property name="sliceMonth" value="1"/>
<property name="sliceColumn" value="create_time"/>
</table>
-
指按自然月分表,sliceMonth
指按單個自然月。Note:目前隻支援按單月分表,此處的值 1 無實際意義1
-
指時間類型的列,sliceColumn
create_time
Java sample
- insert
AccountMapper mapper = ...
Account record = new Account();
record.setAge(33);
record.setId(101);
record.setCreateTime(new Date());
mapper.insert(record);
// or mapper.insertSelective(record)
- 通過取模分表時,必須調用
并傳入合适的參數setId
- 通過自然月分表時,必須調用
setCreateTime
- read
AccountMapper mapper = ...
AccountExample example = new AccountExample();
example.partitionFactorId(id).createCriteria().andAgeEqualTo(33);
// or example.partitionFactorCreateTime(new Date()).createCriteria().andAgeEqualTo(33);
List<Account> as = mapper.selectByExample(example);
- 通過取模分表時,
方法表示分表因子是partitionFactorId
字段,必須調用該方法并傳入合适的參數Id
- 通過自然月分表時,
partitionFactorCreateTime
createTime
- update
AccountMapper mapper = ...
Account record = new Account();
record.setAge(33);
AccountExample example = new AccountExample();
example.partitionFactorId(id).createCriteria().andAgeEqualTo(33);
// or example.partitionFactorCreateTime(new Date()).createCriteria().andAgeEqualTo(33);
mapper.updateByExampleSelective(record, example);
上例的用法和read操作一樣,在example對象上必須調用
partitionFactorId
或
partitionFactorCreateTime
方法。
除此之外,還可以用如下方式進行update:
AccountMapper mapper = ...
Account record = new Account();
record.setCreateTime(new Date());
record.setId(101);
// or record.setCreateTime(new Date());
AccountExample example = new AccountExample();
example.createCriteria().andAgeEqualTo(33);
mapper.updateByExampleSelective(record, example);
由于在record對象調用了
setId
setCreateTime
,就無須在example對象指定分表因子。
- delete
AccountMapper mapper = ...
AccountExample example = new AccountExample();
example.partitionFactorId(id).createCriteria().andAgeEqualTo(33);
// or example.partitionFactorCreateTime(new Date()).createCriteria().andVersionEqualTo(0);
mapper.deleteByExample(example);
-
方法表示分表因子是Id字段,必須調用該方法并傳入合适的參數partitionFactorId
-
方法表示分表因子是createTime字段,必須調用該方法并傳入合适的參數partitionFactorCreateTime
-
other
當無法獲得分表因子的值時、或者确定所操作的表名時,可以通過:
-
取代record.setTableNameSuffix(...)
record.setId(...)
record.setId(...)
-
example.setTableNameSuffix(...)
example.partitionFactorId(...)
WARNING:由于
setTableNameSuffix
的參數是
String
類型,在
Mybatis3
mapper xml
中生成
${}
變量,這種變量不會做
sql
轉義,而直接嵌入到
sql
語句中。如果以使用者輸入作為
setTableNameSuffix
的參數,會導緻潛在的
SQL Injection
攻擊,需謹慎使用。
BatchInsertPlugin
該
plugin
是為了增加批量
insert
的功能。特别适用于初始化資料、或遷移資料。
AccountMapper mapper = ...
List<Account> as = new ArrayList<>();
as.add(...)
mapper.batchInsert(as);
SliceTablePlugin
,則需要對
List
中每一個
Account
執行個體設定分表因子:
AccountMapper mapper = ...
List<Account> as = new ArrayList<>();
for (Account account : accounts) {
account.setId(...);
// or account.setCreateTime(...);
}
mapper.batchInsert(as);
-
setId
-
setCreateTime
JacksonAnnotationPlugin
plugin
是為生成的
model
類添加
jackson@JsonProperty
、
@JsonIgnore
、 和
@JsonFormat
注解。若使用此插件,需要額外依賴
jackson 2.5 +
。(這個插件沒有什麼必要啊,手工添加更加友善)
<table>
元素中添加四個
<property>
(可選的):
<table tableName="Account_0" domainObjectName="Account">
<property name="jacksonColumns" value="name,age"/>
<property name="jacksonProperties" value="nickName,realAge"/>
<property name="jacksonFormats" value="create_time@yyyy-MM-dd HH:mm:ss"/>
<property name="jacksonIgnores" value="id,version"/>
</table>
-
指需要添加jacksonColumns
注解的列,由@JsonProperty
分割的列名組成。該,
必須和<property>
成對出現jacksonProperties
-
指jacksonProperties
注解所需的參數值,由@JsonProperty
分割,這些值的數量和順序必須和,
的值一一對應。該jacksonColumns
<property>
jacksonColumns
-
jacksonFormats
注解的列,值由@JsonFormat
分割的鍵值對組成,鍵值對由,
分割,鍵為列名,值為@
所需參數@JsonFormat
-
jacksonIgnores
@JsonIgnore
分割的列名組成,
public class Account implements Serializable {
@JsonIgnore
private Long id;
@JsonProperty("nickName")
private String name;
@JsonProperty("realAge")
private Integer age;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonIgnore
private Long version;
}
JacksonToJsonPlugin
plugin
model
toJson
toJson
方法的實作依賴于
。若使用此插件,需要額外依賴
jackson 2.5 +
。(這個插件沒有必要使用,并且會有性能的問題,因為生成的
toJson
方法每次被調用都重新
new ObjectMapper
。
ObjectMapper
是線程安全的,完全可以做一個全局的變量)
public class Account implements Serializable {
public String toJson() throws IOException {
... ...
}
}
LombokAnnotationPlugin
plugin
model
lombok 注解,避免了
java bean
中繁瑣的
setter
getter
。生成的代碼看起來也更幹淨、緊湊。若使用此插件,需要額外依賴
lombok
。(這個插件可用,可不用,因為手工添加幾個注解也是簡單的)
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.8</version>
</dependency>
@Data
public class Account implements Serializable {
private Long id;
... ...
}
MinMaxPlugin
<table>
<property>
(可選的)。(這個支援不好,生成的方法名稱不友好,以逗号分隔沒有起到作用)
<table tableName="Account_0" domainObjectName="Account">
<property name="minColumns" value="id,version"/>
<property name="maxColumns" value="id,version"/>
</table>
-
是可進行min操作的列,值由minColumns
,
-
是可進行max操作的列,值由maxColumns
,
AccountMapper mapper = ...
AccountExample example = new AccountExample();
example.createCriteria().andAgeEqualTo(33);
long min = mapper.minIdByExample(example);
long max = mapper.maxIdByExample(example);
SliceTablePlugin
,别忘了對分表因子指派:
example.partitionFactorCreateTime(...)
OptimisticLockAutoIncreasePlugin
在處理并發寫操作時,如果資料競争較低,通常會采用樂觀鎖,避免并發問題的同時獲得較好的性能。實作樂觀鎖的一般方式是在資料中添加版本資訊,就像
Account
表中的
version
列。當寫操作成功時,版本資訊也相應遞增。該
plugin
就是解決
version
自動遞增問題的,可以避免手動對
version+1
<table>
元素中添加一個
<property>
<table tableName="Account_0" domainObjectName="Account">
<property name="optimisticLockColumn" value="version"/>
</table>
-
指具有版本資訊語義的列,optimisticLockColumn
是具體的列名version
AccountMapper mapper = ...
Account record = new Account();
record.setName("tom");
// record.setVersion(1) 無須手工對version進行指派
AccountExample example = new AccountExample();
example.createCriteria().andAgeEqualTo(33);
mapper.updateByExampleSelective(record, example);
SliceTablePlugin
example.partitionFactorId(...)
PaginationPlugin
這個與
org.mybatis.generator.plugins.RowBoundsPlugin
的功能是類似的
AccountMapper mapper = ...
AccountExample example = new AccountExample();
example.page(0, 2).createCriteria().andAgeEqualTo(33);
List<Account> as = mapper.selectByExample(example);
SliceTablePlugin
example.partitionFactorCreateTime(...)
SumSelectivePlugin
AccountMapper mapper = ...
AccountExample example = new AccountExample();
example.sumAge().createCriteria().andVersionEqualTo(0);
long sum = mapper.sumByExample(example);
SliceTablePlugin
example.partitionFactorCreateTime(...)
UpdateSqlTextOfUpdateSelectivePlugin
AccountMapper mapper = ...
Account record = new Account();
record.setUpdateSql("version = version + 1")
record.setAge(33);
AccountExample example = new AccountExample();
example.createCriteria().andAgeEqualTo(22);
mapper.updateByExampleSelective(record.setAge, example);
SliceTablePlugin
example.partitionFactorCreateTime(...)
setUpdateSql
String
Mybatis3
mapper xml
${}
sql
sql
setUpdateSql
SQL Injection
WhereSqlTextPlugin
AccountMapper mapper = ...
int v = 1;
AccountExample example = new AccountExample();
example.createCriteria().andAgeEqualTo(33).addConditionSql("version =" + v + " + 1");
List<Account> as = mapper.selectByExample(example);
SliceTablePlugin
example.partitionFactorCreateTime(...)
setUpdateSql
String
Mybatis3
mapper xml
${}
sql
sql
setUpdateSql
SQL Injection
本篇部落客要來自:
https://github.com/oceanc/mybatis3-generator-plugins,其他部分内容來自官網:
http://www.mybatis.org/generator/reference/plugins.html