MyBatisPlus
1. Introduction
1.1 what is MyBatisPlus
MyBatisPlus is an enhancement tool for MyBatis. Based on MyBatis, it only makes enhancements without changes. It is born to simplify development and improve efficiency.
Official website: https://baomidou.com/

vision
Our vision is to be the best partner of MyBatis, just like Contra 1P and 2P in, and the efficiency is doubled.

1.2 features of mybatisplus
- No invasion: it is only enhanced without change, and its introduction will not affect the existing project, which is as smooth as silk
- Low loss: the basic CURD will be injected automatically upon startup, with basically no loss of performance and direct object-oriented operation
- Powerful crud operation: built in general Mapper and general Service, most CRUD operations of a single table can be realized only through a small number of configurations, and there is a powerful condition constructor to meet various use requirements
- Support Lambda formal call: it is convenient to write various query conditions through Lambda expression, and there is no need to worry about wrong fields
- Support automatic generation of primary key: support up to 4 primary key strategies (including distributed unique ID generator - Sequence), which can be configured freely to perfectly solve the primary key problem
- Built in code generator: code or Maven plug-in can be used to quickly generate Mapper, Model, Service and Controller layer code, support template engine, and have more custom configurations for you to use
- Built in paging plug-in: Based on MyBatis physical paging, developers do not need to care about specific operations. After configuring the plug-in, writing paging is equivalent to ordinary List query
- The paging plug-in supports multiple databases: MySQL, MariaDB, Oracle, DB2, H2, HSQL, SQLite, Postgre, SQLServer and other databases
- Built in performance analysis plug-in: it can output Sql statements and their execution time. It is recommended to enable this function during development and testing to quickly find out slow queries
1.3 frame structure

2. Quick start
2.1 creating database
Create database mybatis_plus
Create user table
USE `mybatis_plus`; DROP TABLE IF EXISTS user; CREATE TABLE user ( id BIGINT(20) NOT NULL COMMENT 'Primary key ID', name VARCHAR(30) NULL DEFAULT NULL COMMENT 'full name', age INT(11) NULL DEFAULT NULL COMMENT 'Age', email VARCHAR(50) NULL DEFAULT NULL COMMENT 'mailbox', PRIMARY KEY (id) ); -- In a real development environment,Plus version(Optimistic lock),deleted(Logical deletion),gmt_create,gmt_modified
insert data
DELETE FROM user; INSERT INTO user (id, name, age, email) VALUES (1, 'Jone', 18, 'test1@baomidou.com'), (2, 'Jack', 20, 'test2@baomidou.com'), (3, 'Tom', 28, 'test3@baomidou.com'), (4, 'Sandy', 21, 'test4@baomidou.com'), (5, 'Billie', 24, 'test5@baomidou.com');
2.2 creating a SpringBoot project
- Import lombok and mysql dependencies.


- Import dependencies for MyBatisPlus
<!--mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3.1</version> </dependency>
Note: when we use MyBatisPlus, try not to import mybatis at the same time
2.3 write configuration file and connect to database
# DataSource Config spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8 username: root password: 123456
2.4 writing entity classes and DAO layers
In the traditional writing method, the dao layer needs to connect mybatis and configure mapper XML file.
After using MyBatisPlus
- pojo
package com.bamao.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class User { private Long id; private String name; private Integer age; private String email; }
- mapper interface
package com.bamao.mapper; import com.bamao.pojo.User; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.springframework.stereotype.Repository; //Inherit the basic class BaseMapper on the corresponding mapper @Repository public interface UserMapper extends BaseMapper<User> { // All CRUD operations have been written automatically // You don't have to write a lot of documents as before }
2.5 add @ MapperScan annotation in SpringBoot startup class
You need to scan all interfaces under our Mapper package on the main startup class MybatisPlusApplication
@SpringBootApplication @MapperScan("com.bamao.mapper") public class MybatisplusApplication { public static void main(String[] args) { SpringApplication.run(MybatisplusApplication.class, args); } }
2.6 test in test class
@SpringBootTest class MybatisplusApplicationTests { @Autowired UserMapper userMapper; @Test void contextLoads() { System.out.println(("----- selectAll method test ------")); List<User> userList = userMapper.selectList(null); userList.forEach(System.out::println); } }
Note: the parameter of the selectList() method in UserMapper is Mapper's built-in conditional Wrapper, so it is unconditional if it is not filled in
- The output results are as follows

3. Configure log
All sql is invisible. We want to know how it is executed. We must look at the log.
# Configuration log (default console output) mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

4. CRUD and extension
4.1 insert data
Test code
// Test insert data @Test public void testInsert() { User user = new User(); user.setName("eighty fen"); user.setAge(18); user.setEmail("bamao@qq.com"); // Note: ID is not set int insertResult = userMapper.insert(user); System.out.println(insertResult); System.out.println(user); }
Output results

As you can see here, MyBatisPlus automatically helps us generate IDS, which are globally unique.
4.2 primary key generation strategy (that is, the algorithm for generating globally unique IDs)
Generation of unique id of distributed system: https://www.cnblogs.com/haoxinyue/p/5208136.html
- Database self growth sequence
- UUID
- Snowflake algorithm
- ......
Snowflake algorithm (Twitter's snowflake algorithm)
snowflake is Twitter's open source distributed ID generation algorithm, and the result is a long ID. Its core idea is to use 41 bit as the number of milliseconds, 10 bit as the machine ID (5 bits are the data center and 5 bit machine ID), 12 bit as the serial number within milliseconds (meaning that each node can generate 4096 IDS per millisecond), and finally there is a symbol bit, which is always 0. It is almost the only one in the world.
@TableId annotation
@TableId is a primary key specific annotation. If the field in the table in the data is id, but the entity class is userId, you need to mark this annotation on userId.

@There are two attributes in the TableId annotation, where value maps the name of the primary key field and type sets the generation strategy of the primary key.

The main generation strategies include the above types and have the following meanings:
- AUTO: database self increment
- None: automatically generate primary key using snowflake algorithm (default)
- INPUT: manually assigned by the developer
- ID_ WORKER: use mp automatic assignment and adopt snowflake algorithm
Use primary key auto increment
- @ TableId(type = IdType.AUTO) on entity class field

- Database fields must be self incremented
- Run again to see the output

4.3 update data
Let's start with the conclusion that dynamic Sql is used in MyBatisPlus.
Update data
// Test update data @Test public void testUpdate() { User user = new User(); user.setId(1409883511660752897L); user.setAge(20); userMapper.updateById(user); }
Update results:

Dynamic SQL
- View SQL statements
- Modify test code:
// Test update data @Test public void testUpdate() { User user = new User(); user.setId(1409883511660752897L); user.setAge(18); user.setEmail("bamao@qq.com"); userMapper.updateById(user); }
- Review the SQL statement again
4.4 automatic filling
Alibaba java development manual points out that the creation and modification of any data requires time. Then we hope that this field can be generated automatically without manual updating.
There are two ways to do this.
4.4.1 modify on the database (not recommended)
1. Add the field create in the table_ time , update_ time
2. Synchronize entity classes and insert data
- Add field in entity class
private Date createTime; private Date updateTime;
- Insert new data
@Test public void testInsert2() { User user = new User(); user.setName("forty fen"); user.setAge(18); user.setEmail("simao@qq.com"); // Note: ID is not set int insertResult = userMapper.insert(user); System.out.println(insertResult); System.out.println(user); }
3. View results
4. Run the update data operation again to view the results
You can see that the update time updates over time, but the creation time does not change.
4.4.2 code level
1. Delete database default value and automatic update
2. Add annotation @ TableField on the entity class field attribute
@TableField is a field annotation (non primary key) and has several common properties
attribute | type | Must specify | Default value | describe |
---|---|---|---|---|
value | String | no | "" | Database field name |
fill | Enum | no | FieldFill.DEFAULT | Field auto fill policy |
... | ... | ... | ... | ... |
You can see that the fill attribute is used for automatic filling. The fill values are as follows:
value | describe |
---|---|
DEFAULT | Do not process by default |
INSERT | Fill fields on insertion |
UPDATE | Fill in fields when updating |
INSERT_UPDATE | Fill in fields when inserting and updating |
Therefore, we should add @ TableField(fill = FieldFill.INSERT) to the createTime attribute and @ TableField(fill = FieldFill.INSERT_UPDATE) to the updateTime attribute.
@Data @AllArgsConstructor @NoArgsConstructor public class User { @TableId(type = IdType.AUTO) private Long id; private String name; private Integer age; private String email; @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; }
3. Write the processor to handle this annotation
Now we only know to modify this property during insertion / update, but we don't know what the modified value is, so we need to write the processor to write the modified value.
package com.bamao.handler; import java.util.Date; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; @Slf4j @Component //Add the processor to the IOC container public class MyMetaObjectHandler implements MetaObjectHandler { //Population policy at insertion @Override public void insertFill(MetaObject metaObject) { log.info("Start insert fill ..."); Date date = new Date(); // Setfieldvalbyname (field name, updated value, metaObject) this.setFieldValByName("createTime", date, metaObject); this.setFieldValByName("updateTime", date, metaObject); } //Population policy when updating @Override public void updateFill(MetaObject metaObject) { log.info("Start update fill ..."); Date date = new Date(); // Setfieldvalbyname (field name, updated value, metaObject) this.setFieldValByName("updateTime", date, metaObject); } }
4. Test insertion
@Test public void testInsert3() { User user = new User(); user.setName("Hai Hai"); user.setAge(1); user.setEmail("haihai@qq.com"); userMapper.insert(user); }
- Output results

5. Test update
// Test update data @Test public void testUpdate() { User user = new User(); user.setId(1409883511660752897L); user.setAge(18); user.setEmail("bamao@qq.com"); userMapper.updateById(user); }
- Output results
4.5 optimistic lock & pessimistic lock
Optimistic locking always assumes the best situation. Every time you go to get the data, you think others will not modify it, so you won't lock it. However, when updating, you will judge whether others have updated the data during this period. You can use the version number mechanism and CAS algorithm. Optimistic locking is suitable for multi read applications, which can improve throughput.
Pessimistic lock always assumes the worst case. Every time you get the data, you think others will modify it, so you lock it every time you get the data, so that others will block the data until they get the lock (shared resources are only used by one thread at a time, other threads are blocked, and then transfer the resources to other threads after they are used up).
Version number mechanism of optimistic lock
Generally, A data version number field is added to the data table to indicate the number of times the data has been modified. When the data is modified, the version value will be added by one. When thread A wants to update the data value, it will also read the version value while reading the data. When submitting the update, if the version value just read is equal to the version value in the current database, it will not be updated. Otherwise, retry the update operation until the update is successful.
-
When fetching records, get the current version
-
When updating, bring this version
-
When updating, set version = newVersion where version = oldVersion
-
If the version is incorrect, the update fails
Optimistic lock test
1. Add a version field to the database
2. Add the corresponding field to the entity class
@Version // Optimistic lock annotation private int version;
3. Register components
@Configuration @MapperScan("com.bamao.mapper") public class MyBatisPlusConfig { // Optimistic lock @Bean public MybatisPlusInterceptor mybatisPlusOptimisticLockerInnerInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor; } }
4. Update data
// Test lock update data @Test public void testVersionUpdate() { // 1. Query user information User user = userMapper.selectById(1409883511660752897L); // 2. Modify user information user.setName("Bamao 2"); user.setAge(20); // 3. Perform the update operation userMapper.updateById(user); }
5. Observe SQL statements
6. Operation results
4.6 query operation
4.6.1 single query
code
// Test a single query @Test public void testSelectById() { User user = userMapper.selectById(1L); System.out.println(user); }
Output results
4.6.2 multiple queries
code
// Test multiple queries @Test public void testSelectByBatchId() { List<Long> queryList = new ArrayList<>(); queryList.add(1L); queryList.add(2L); queryList.add(3L); List<User> users = userMapper.selectBatchIds(queryList); users.forEach(System.out::println); }
Output results
4.6.3 condition query (Map encapsulation)
code
// Test condition query @Test public void testSelectByMap() { Map<String, Object> map = new HashMap<>(); map.put("name","Bamao 2"); List<User> users = userMapper.selectByMap(map); users.forEach(System.out::println); }
Output results
4.7 paging query
MyBatisPlus has built-in paging plug-in, which can be used directly. ( https://baomidou.com/guide/page.html)
1. Configure interceptor
@Configuration @MapperScan("com.bamao.mapper") public class MyBatisPlusConfig { // Optimistic lock @Bean public MybatisPlusInterceptor mybatisPlusOptimisticLockerInnerInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor; } // paging @Bean public MybatisPlusInterceptor mybatisPlusPaginationInnerInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2)); return interceptor; } }
Carefully observe that the two beans return the same type, so it can be simplified
@Configuration @MapperScan("com.bamao.mapper") public class MyBatisPlusConfig { // //Optimistic lock // @Bean // public MybatisPlusInterceptor mybatisPlusOptimisticLockerInnerInterceptor() { // MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); // mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // return mybatisPlusInterceptor; // } @Bean public MybatisPlusInterceptor mybatisPlusPaginationInnerInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // Add paging interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2)); // Add optimistic lock interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } }
2. Use the Page object directly
// Test paging @Test public void testPage() { // Parameter 1: current page // Parameter 2: page size // After using the paging plug-in, all paging operations become simple Page<User> page = new Page<>(1,5); userMapper.selectPage(page, null); page.getRecords().forEach(System.out::println); System.out.println(page.getTotal()); }
3. Observe SQL statements
4. Output results
4.8 delete
As like as two peas, the code is only posted.
4.8.1 single deletion
// Test single deletion @Test public void testDelete(){ userMapper.deleteById(6L); }
4.8.2 batch deletion
// Test batch deletion @Test public void testDeleteByBatchId(){ List<Long> deleteList = new ArrayList<>(); deleteList.add(7L); deleteList.add(8L); deleteList.add(9L); userMapper.deleteBatchIds(deleteList); }
4.8.3 delete by Map condition
//Delete by map @Test public void testDeleteByMap(){ Map<String, Object> map = new HashMap<>(); map.put("name","Nonexistent Name"); userMapper.deleteByMap(map); }
4.9 logical deletion
Physical deletion is the actual deletion from the database. Corresponding SQL statement: delete from table name where condition. Executing this statement means that the information in the database is completely deleted and cannot be recovered.
The essence of logical deletion is modification. The so-called logical deletion is not real deletion, but modifying the corresponding is_delete or status field in the table. For example, 0 is not deleted and 1 is deleted. Logically, the data is deleted, but the data itself still exists in the library.
Corresponding SQL statement: update table name set is_delete = 1 where id = 1. Statement indicates that if the information with ID 1 is logically deleted in the table, the client queries the information with ID 1, and the server will not provide information. If you want to continue to provide this information to the client, you can use is_delete is changed to 0.
1. Add is to the data table_ Deleted field
2. Add attribute in entity class
@TableLogic //Delete annotation logically private Integer isDeleted;
@TableLogic Description: table field logical processing annotation (logical deletion)
attribute | type | Must specify | Default value | describe |
---|---|---|---|---|
value | String | no | "" | Logical undeleted value |
delval | String | no | "" | Logical delete value |
3. Configuration
# Configuration log (default console output) mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # Logical deletion global-config: db-config: logic-delete-field: flag # Global logically deleted entity field name logic-delete-value: 1 # Logical deleted value (default is 1) logic-not-delete-value: 0 # Logical undeleted value (default is 0)
4. Test and delete user 1
// Test logical deletion @Test public void testLogicDelete(){ userMapper.deleteById(1L); }
5. View SQL code
6. View database
7. Query user 1 again
5. Conditional constructor Wrapper
We can use it instead of writing some complex sql.
5.1 complex query
Requirement: query users whose name is not empty and whose age is greater than or equal to 18 years old
code
@Test public void testComplexQuery() { // Query users whose name is not empty and whose age is greater than or equal to 18 QueryWrapper<User> wrapper = new QueryWrapper<>(); //Similar to map wrapper.isNotNull("name"); wrapper.ge("age",18); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }
View SQL statements
Preparing: SELECT id,name,age,email,create_time,update_time,version,is_deleted FROM user WHERE is_deleted=0 AND (name IS NOT NULL AND age >= ?) ==> Parameters: 18(Integer) <== Columns: id, name, age, email, create_time, update_time, version, is_deleted <== Row: 2, Jack, 20, test2@baomidou.com, 2021-06-30 13:59:32, 2021-06-30 14:07:41, 1, 0 <== Row: 3, Tom, 28, test3@baomidou.com, 2021-06-30 13:59:32, 2021-06-30 13:59:32, 1, 0 <== Row: 4, Sandy, 21, test4@baomidou.com, 2021-06-30 13:59:32, 2021-06-30 13:59:32, 1, 0 <== Row: 5, Billie, 24, test5@baomidou.com, 2021-06-30 13:59:32, 2021-06-30 13:59:32, 1, 0 <== Row: 1409883511660752897, eighty fen, 18, bamao@qq.com, 2021-06-30 13:59:32, 2021-07-01 00:57:29, 4, 0 <== Row: 1409883511660752899, forty fen, 18, simao@qq.com, 2021-06-30 14:04:31, 2021-06-30 14:04:31, 1, 0 <== Total: 6
SQL statements are automatically spliced again.
Output results
5.2 simple query
Requirement: query the information whose name is equal to 80 cents
code
// Simple query @Test public void testEasyQuery() { // Query users whose name is not empty and whose age is greater than or equal to 18 QueryWrapper<User> wrapper = new QueryWrapper<>(); //Similar to map wrapper.eq("name","eighty fen"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }
SQL statement
Output results
5.3 interval query
Demand: query the age between 18 and 22
code
// Interval query @Test public void testRangeQuery() { // Query the age between 18 and 22 QueryWrapper<User> wrapper = new QueryWrapper<>(); //Similar to map wrapper.between("age",18, 22); //section List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }
SQL statement
Output results
5.4 fuzzy query
Requirement: query users with "Mao" in their names
code
// Fuzzy query @Test public void testLikeQuery() { // Query users with "Mao" in their names QueryWrapper<User> wrapper = new QueryWrapper<>(); //Similar to map wrapper.like("name", "hair"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }
SQL statement
Output results
5.5 sub query
Requirement: use sub query to query users with ID < 4
code
// Subquery @Test public void testSubQuery() { // Query users with ID < 4 QueryWrapper<User> wrapper = new QueryWrapper<>(); //Similar to map // The condition of this SQL statement refers to // Find the user whose id is in the id satisfying id < 4 // That is: ID in (select id from table where id < 4) wrapper.inSql("id", "select id from user where id < 4"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }
SQL statement
JDBC Connection [HikariProxyConnection@2259527 wrapping com.mysql.cj.jdbc.ConnectionImpl@9596ce8] will not be managed by Spring ==> Preparing: SELECT id,name,age,email,create_time,update_time,version,is_deleted FROM user WHERE is_deleted=0 AND (id IN (select id from user where id < 4)) ==> Parameters: <== Columns: id, name, age, email, create_time, update_time, version, is_deleted <== Row: 2, Jack, 20, test2@baomidou.com, 2021-06-30 13:59:32, 2021-06-30 14:07:41, 1, 0 <== Row: 3, Tom, 28, test3@baomidou.com, 2021-06-30 13:59:32, 2021-06-30 13:59:32, 1, 0 <== Total: 2
Output results
5.6 Sorting Query Results
Requirement: query all users and sort their ages from small to large
code
// Sorted by age @Test public void testOrderQuery() { QueryWrapper<User> wrapper = new QueryWrapper<>(); //Similar to map wrapper.orderByAsc("age"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }
SQL statement
Output results
6. Code generator
AutoGenerator is the code generator of mybatis plus. Through AutoGenerator, you can quickly generate the code of Entity, Mapper, Mapper XML, Service, Controller and other modules, which greatly improves the development efficiency.
Demo URL: https://baomidou.com/guide/generator.html
Mad God code
// Automatic code generator public class KuangCode { public static void main(String[] args) { // You need to build an automatic code generator object AutoGenerator mpg = new AutoGenerator(); // Configuration policy // 1. Global configuration GlobalConfig gc = new GlobalConfig(); String projectPath = System.getProperty("user.dir"); //Project path gc.setOutputDir(projectPath+"/src/main/java"); gc.setAuthor("Madness theory"); gc.setOpen(false); // That is, open the folder after generation gc.setFileOverride(false); //Overwrite gc.setServiceName("%sService"); //I prefix to Service gc.setIdType(IdType.ID_WORKER); //Unique ID generation algorithm gc.setDateType(DateType.ONLY_DATE); gc.setSwagger2(true); mpg.setGlobalConfig(gc); //2. Set data source DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://localhost:3306/kuang_community? useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8"); dsc.setDriverName("com.mysql.cj.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("123456"); dsc.setDbType(DbType.MYSQL); mpg.setDataSource(dsc); //3. Package configuration PackageConfig pc = new PackageConfig(); //You only need to change the entity class name, package name and database configuration pc.setModuleName("blog"); pc.setParent("com.kuang"); pc.setEntity("entity"); pc.setMapper("mapper"); pc.setService("service"); pc.setController("controller"); mpg.setPackageInfo(pc); //4. Policy configuration StrategyConfig strategy = new StrategyConfig(); strategy.setInclude("blog_tags"); // Set the table name to be mapped. In the future, you only need to modify this place. You can enter multiple values // strategy.setInclude("blog_tags","course","links","sys_settings","user_record"," user_say"); strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); strategy.setEntityLombokModel(true); // Automatic lombok; strategy.setLogicDeleteFieldName("deleted"); // Logical deletion // Auto fill configuration TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT); TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE); ArrayList<TableFill> tableFills = new ArrayList<>(); tableFills.add(gmtCreate); tableFills.add(gmtModified); strategy.setTableFillList(tableFills); strategy.setVersionFieldName("version"); // Optimistic lock strategy.setRestControllerStyle(true); strategy.setControllerMappingHyphenStyle(true); //The link request becomes underlined and named: localhost: 8080 / Hello_ id_ two mpg.setStrategy(strategy); mpg.execute(); //implement } }