Environment set up
- Creating a database
- Create the corresponding entity class User
- Import dependence
<dependencies>
<! -- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.5. RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.5. RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Copy the code
- Configuration properties
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://localhost:3306/mybatis_plus? useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
Copy the code
- Implementing an interface
//BaseMapper provides a series of basic operations by default
@Repository
public interface UserMapper extends BaseMapper<User> {}Copy the code
- Modifying the startup class
@SpringBootApplication
@MapperScan("com.mapper") // point to the package where the mapper is located
public class plus_01Application {
public static void main(String[] args) { SpringApplication.run(plus_01Application.class,args); }}Copy the code
- To configure the log
Add the following code to the existing configuration file
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
Copy the code
test
class DemoApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads(a) {
//List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
//queryWrapper entity object encapsulates the operation class (can be null)
//selectList queries based on the criteria passed in
List<User> users = userMapper.selectList(null);
for(User user:users) System.out.println(user); }}Copy the code
The results of
CRUD and expand
The insert
@Test
public void testInsert(a){
User u=new User();
u.setId(7);
u.setEmail("baomidou.com");
u.setName("jony");
userMapper.insert(u);
}
Copy the code
Primary key generation policy
Distributed system is a unique id generated: www.cnblogs.com/haoxinyue/p…
Snowflake algorithm:
Snowflake is Twitter’s open source distributed ID generation algorithm that results in a long ID. The idea is to use 41bits as the number of milliseconds, 10bits as the machine ID (5 bits for the data center, 5 bits for the machine ID), 12bits as the serial number within milliseconds (meaning each node can generate 4096 ids per millisecond), and finally a symbolic bit, always 0. The code can be found at github.com/twitter/sno…
public enum IdType {
/** * Database ID increment * For this type, please ensure that the database ID increment is set otherwise it will not work
*/
AUTO(0),
/** * This type is an unset primary key */
NONE(1),
/** * The user enters ID * this type can be filled by registering your own autofill plug-in
*/
INPUT(2),
/* Only if the ID of the inserted object is empty, it will be automatically filled. * /
/** * Assign ID (primary key type number or string), * default implementation class {@linkCom. Baomidou. Mybatisplus. Core. The incrementer. DefaultIdentifierGenerator} (snow algorithm) * *@since3.3.0 * /
ASSIGN_ID(3),
/** * Assign UUID (primary key type string) * default implementation class {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
*/
ASSIGN_UUID(4),
/ * * *@deprecated3.3.0 both please use {@link #ASSIGN_ID}
*/
@Deprecated
ID_WORKER(3),
/ * * *@deprecated3.3.0 both please use {@link #ASSIGN_ID}
*/
@Deprecated
ID_WORKER_STR(3),
/ * * *@deprecated3.3.0 both please use {@link #ASSIGN_UUID}
*/
@Deprecated
UUID(4);
private final int key;
IdType(int key) {
this.key = key; }}Copy the code
/*
* 主键类型
* {@link IdType}
IdType type() default IdType.NONE;*/
// We specify the primary key generation method with @tableID. Setting the primary key increment needs to be set to increment in the database
@TableId(type = IdType.AUTO)
private int id;
Copy the code
The update operation
Update does not perform dynamic SQL, which is addressed at the end of this article
MybatisPlus will do the SQL concatenation for us automatically
@Test
public void testUpdate(a){
User u=new User();
u.setId(7);
u.setEmail("@baomidou.com");
// The argument is of object type
//int updateById(@Param(Constants.ENTITY) T entity);
userMapper.updateById(u);
}
Copy the code
@Test
public void testUpdate(a){
User u=new User();
u.setId(7);
u.setName("hony");
u.setEmail("@baomidou.com");
userMapper.updateById(u);
}
Copy the code
Automatic filling
Database level
Add two columns to the database
Modify the corresponding entity class
public class User {
@TableId(type = IdType.AUTO)
private int id;
private Integer age;
private String name;
private String email;
// Add the corresponding field
private Date createTime;
private Date updateTime;
}
Copy the code
Code level
- Add an annotation @tableField
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
@TableId(type = IdType.AUTO)
private int id;
private Integer age;
private String name;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE )
private Date updateTime;
@Version
private Integer version;
}
Copy the code
/** * field auto-fill strategy * * will ignore insertStrategy or updateStrategy configuration in the corresponding mode, equal to asserting that the field must have a value */
FieldFill fill(a) default FieldFill.DEFAULT;
Copy the code
public enum FieldFill {
/** ** does not process */ by default
DEFAULT,
/** * Fill in the field */ when inserting
INSERT,
/** * Fill in the field */ when updating
UPDATE,
/** * Fill the fields */ when inserting and updating
INSERT_UPDATE
}
Copy the code
- Handling strategy
@Component // You need to register with the IOC container
public class MymetObejectHandler implements MetaObjectHandler {
// Insert policy
@Override
public void insertFill(MetaObject metaObject) {
log.info("inserte fill start ---------");
// Database field, the populated value
setFieldValByName("createTime".new Date(),metaObject) ;
setFieldValByName("updateTime".new Date(),metaObject) ;
}
// Update policy
@Override
public void updateFill(MetaObject metaObject) {
log.info("update fill start ---------");
setFieldValByName("updateTime".newDate(),metaObject) ; }}Copy the code
Optimistic locking
When a record is updated, it is hoped that the record has not been updated by others
Optimistic lock implementation:
- When the record is fetched, the current version is retrieved
- When you update, take this version with you
- When performing an update, set version = newVersion where version = oldVersion
- If the version is incorrect, the update fails
- Add the field version to the database
2. Update the entity class and add the corresponding attributes
@Version
private Integer version;
Copy the code
- Register with the IOC container
@Configuration
@MapperScan("com.mapper")
@EnableTransactionManagement // Enable transaction support
public class MyConfig {
@Bean
public MybatisPlusInterceptor optimisticLockerInterceptor(a){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
returninterceptor; }}Copy the code
- test
@Test
public void testop2(a){
User u=userMapper.selectById(1);
u.setEmail("t");
User u2=userMapper.selectById(1);
u2.setId(7);
u2.setEmail("T2");
userMapper.updateById(u2);
userMapper.updateById(u);
}
// Email is changed to T2 instead of t
Copy the code
Query operation
/** * query ** by ID@paramId Primary key ID */
T selectById(Serializable id);
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /
/** * query (by ID) **@paramIdList List of primary key ids (cannot be null or empty) */
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /
/** * Query (based on columnMap condition) **@paramColumnMap Table field map object */
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
Copy the code
The Map query is dynamically SQL based on the parameters we pass in
@Test
public void testSelect(a){
// Query by id
userMapper.selectById(1);
// Batch query based on the array passed in
userMapper.selectBatchIds(Arrays.asList(2.3.4));
Map<String, Object> Map = new HashMap<>();
Map.put("name"."jony");
Map.put("age"."18");
userMapper.selectByMap(Map);
}
Copy the code
Paging query
Use the built-in paging plug-in of MybatisPlus for paging
- To register the plugin
public class MyConfig {
@Bean
public MybatisPlusInterceptor optimisticLockerInterceptor(a){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}}
Copy the code
- use
/** * the paging constructor **@paramCurrent Current page *@paramSize Number of items displayed on a page */
public Page(long current, long size) {
this(current, size, 0);
}
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /
/** * Query all records according to entity condition **@paramPage paging query criteria (can be rowbound.default) *@paramThe queryWrapper entity object encapsulates the action class (which can be null) */
<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
Copy the code
@Test
public void testSelect(a){
// 5 records to a page, display the second page
Page<User> page = new Page<>(2.5);
userMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println );
}
Copy the code
Delete operation
Similar to the above query operation
/** * delete ** based on ID@paramId Primary key ID */
int deleteById(Serializable id);
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /
/** * Drop the record ** according to the columnMap condition@paramColumnMap Table field map object */
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /
/** * delete (batch delete by ID) **@paramIdList List of primary key ids (cannot be null or empty) */
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
Copy the code
@Test
public void testDelete(a){
userMapper.deleteById(8);
userMapper.deleteBatchIds(Arrays.asList(2.3.4));
Map<String, Object> Map = new HashMap<>();
Map.put("name"."jony");
Map.put("age"."18");
userMapper.deleteByMap(Map);
}
Copy the code
Logical deletion (only for automatically injected SQL)
- Add a field deleted (with a fixed name) in the database and set its default value to 0
2. Modify the entity class and add corresponding annotations
Note: Lower versions require components to be registered
@Bean// Remove the component logically
public ISqlInjector sqlInjector(a){
return new LogicSqlInjector();
}
Copy the code
- Modifying a Configuration File
Because our database sets deleted to 0 by default, we set logic-not-delete-value: 0 as the condition for not deleting. Logic-delete-value: 1 indicates the deleted flag.4. Test
When we delete user id 8, we are actually doing an update
Query user 8 again
Performance analysis plug-in
Mybatis-Plus removed PerformanceInterceptor in version 3.2 and above
- Import dependence
This plug-in has performance loss and is not recommended for production environments.
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>The latest version</version>
</dependency>
Copy the code
- Modify the original database properties
spring:
datasource:
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
username: root
password: 123456
url: jdbc:p6spy:mysql://localhost:3306/mybatis_plus? useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
Copy the code
- Add the configuration file spy.properties
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
# Custom log printing
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
Log output to console
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
Use logging system to record SQL
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
P6spy Driver agent
deregisterdrivers=true
# remove the JDBC URL prefix
useprefix=true
# configuration record Log exceptions, can get rid of the result set of the error, the info of batch, debug, statement, commit, rollback, the result, the resultset.
excludecategories=info,debug,result,commit,resultset
# date format
dateformat=yyyy-MM-dd HH:mm:ss
# The actual driver can be multiple
#driverlist=org.h2.Driver
Whether to enable slow SQL recording
outagedetection=true
Slow SQL record standard 2 seconds
outagedetectioninterval=2
Copy the code
The conditional constructor Wrapper
Test 1 NotNull, lt
@Test
public void TestWrapper(a){
QueryWrapper<User> wrapper = new QueryWrapper<>();
// The mailbox is not empty 18 years old
wrapper.isNotNull("name")
.isNotNull("email")
.lt("age".18);
userMapper.selectList(wrapper);
}
Copy the code
Test 2 eq
@Test
public void TestWrapper(a){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name"."jony");
userMapper.selectOne(wrapper);
}
Copy the code
Test 3 between
@Test
public void TestWrapper(a){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age".18.20);
userMapper.selectCount(wrapper);
}
Copy the code
Test 4 Like fuzzy query
@Test
public void TestWrapper(a){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.notLike("name"."j")//%j%
.likeLeft("email"."t");// %t
userMapper.selectList(wrapper).forEach(System.out::println);
}
Copy the code
Test 5 subqueries
@Test
public void TestWrapper(a){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.inSql("id"."select id from user where age>18");
userMapper.selectList(wrapper).forEach(System.out::println);
}
Copy the code
Test 6 Sorting
@Test
public void TestWrapper(a){
QueryWrapper<User> wrapper = new QueryWrapper<>();
/ / Desc descending order
wrapper.orderByDesc("id");
userMapper.selectList(wrapper).forEach(System.out::println);
}
Copy the code
Code generator
- Import dependence
MyBatis-Plus removed the default dependencies between code generators and template engines after 3.0.3, requiring manual addition of dependencies:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.2</version>
</dependency>// Template engine dependency, which can be changed, after which you need to set the template engine in AutoGenerator<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
Copy the code
- Write the code
@Test
public void auto(a){
AutoGenerator mpg=new AutoGenerator();
// Global configuration
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java");// Set the output address
globalConfig.setAuthor("lin");// Set the author
globalConfig.setOpen(false);// Set whether to open the folder after the build
globalConfig.setFileOverride(false);// Whether to override
globalConfig.setServiceName("%sService");// Remove the I prefix of service
globalConfig.setIdType(IdType.ASSIGN_ID);// Specify the ID type of the generated primary key
globalConfig.setDateType(DateType.ONLY_DATE);// Use only java.util. Date instead
globalConfig.setSwagger2(true);/ / use swagger
mpg.setGlobalConfig(globalConfig);
// Configure the database
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/mybatis_plus? useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC");
dataSourceConfig.setDriverName("com.mysql.jdbc.Driver");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("123456");
dataSourceConfig.setDbType(DbType.MYSQL);
mpg.setDataSource(dataSourceConfig);
/ / package Settings
PackageConfig packageConfig = new PackageConfig();
packageConfig.setModuleName("blog");
packageConfig.setParent("com");
packageConfig.setEntity("entity");
packageConfig.setService("service");
packageConfig.setMapper("mapper");
packageConfig.setController("controller");
mpg.setPackageInfo(packageConfig);
// Policy configuration
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setInclude("user");// Set the table name for the mapping
strategyConfig.setNaming(NamingStrategy.underline_to_camel);// Underline the hump name
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);// Underline the hump name
strategyConfig.setSuperEntityClass("Specify the parent entity");// Specify the inherited parent class
strategyConfig.setEntityLombokModel(true);/ / Lombok automatically
strategyConfig.setRestControllerStyle(true);/ / a restful style
strategyConfig.setLogicDeleteFieldName("deleted");// Set the logical delete field
// Auto-fill
TableFill gmtCreat=new TableFill("gmt_creat", FieldFill.INSERT);// Field, condition
TableFill gmtModified=new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
ArrayList<TableFill> arrayList= new ArrayList<>();
arrayList.add(gmtCreat);
arrayList.add(gmtModified);
strategyConfig.setTableFillList(arrayList);
/ / optimistic locking
strategyConfig.setVersionFieldName("version");// Specify a field
/ / hump hyphen/managerUserActionHistory - > / manager - user - action - history
strategyConfig.setControllerMappingHyphenStyle(true);
strategyConfig.setRestControllerStyle(true);/ / open Restful
mpg.setStrategy(strategyConfig);
mpg.execute();
}
Copy the code
Test results:
debug
1. Update does not perform dynamic SQL
The reason:
-
Int is the base data type and Integer is the reference data type.
-
Ingeter is a wrapper for int, whose initial value is 0 and whose initial value is null.
The number in the object is defined as an int and defaults to 0 if no value is assigned, and then MyBatisPlus assumes that you assigned a value of 0 to update it instead of dynamically concatenating SQL.