另外,喜欢的朋友,帮忙关注 和 star(点点小爱心)!官网文档:http://mybatis-mp.cn !!!
特别申明:禁止在非法项目中使用,否则后果自负!
轻量级封装mybatis。 其他框架都比较深度修改了mybatis源码。
对比其他mybatis框架,性能不差,接近最优。
中高度实现ORM,查询API零学习成本。
可应付90%的SQL需求。
没有过于复杂的设计,但是api却很丰富,足够使用! 其他框架或多或少设计的过于复杂,反而容易出现各种问题。
自动过滤多余的left join count查询 自动去除order by ,无效的left join,以及select部分替换成 select count() 或 select 1 后 在select count() 内置分页功能,超级牛逼!
群号: 121908790 ,邀请各位大神参与补充,绝对开源,大家都可以进行代码提交,审核通过会进行master分支。
https://gitee.com/mybatis-mp/mybatis-mp-spring-boot-demo
<dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.mybatis-mp</groupId>
<artifactId>mybatis-mp-spring-boot-parent</artifactId>
<version>1.5.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.mybatis-mp</groupId>
<artifactId>mybatis-mp-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.mybatis-mp</groupId>
<artifactId>mybatis-mp-spring-boot-parent</artifactId>
<version>1.5.0-spring-boot3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.mybatis-mp</groupId>
<artifactId>mybatis-mp-spring-boot-starter</artifactId>
</dependency>
</dependencies>
配置spring boot配置文件
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
或者 自己实例一个 DataSource 也可以
@Configuration(proxyBeanMethods = false)
public class DatasourceConfig {
@Bean
public DataSource getDataSource() {
return new EmbeddedDatabaseBuilder()
.setName("test_db")
.setType(EmbeddedDatabaseType.H2)
.addScript("schema.sql")
.build();
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
MybatisMpConfig.setTableUnderline(true); //数据库表是否下划线规则 默认 true
MybatisMpConfig.setColumnUnderline(true); ///数据库列是否下划线规则 默认 true
SpringApplication.run(DemoApplication.class, args);
}
}
mybatis:
configuration:
databaseId: MYSQL
更多数据库支持,请查看类:db.sql.api.DbType
启动springboot即可,非常简单
1.添加此依赖,无需再添加mybatis依赖
2.包含 mybatis、mybatis-spring、 mybatis-spring-boot-starter 所有功能(支持原有mybatis的所有功能)
3.更多mybatis 配置参数,参考 https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/zh/index.html
4.参考示例:https://gitee.com/mybatis-mp/mybatis-mp/tree/master/mybatis-mp-spring-boot-demo
5.更多 mybatis 用法,参考: mybatis:https://mybatis.org/mybatis-3/zh/index.html
mybatis spring: https://mybatis.org/spring/zh/index.html
6.更多mybatis-mp 用法,参考作者编写的test case:(包含各种简单,复杂的CRUD操作案例)
mybatis-mp 支持枚举作为参数进行进行CRUD;要求一下:
public enum TestEnum implements EnumSupport<String> {
X1("a1"),X2("a2");
TestEnum(String code){
this.code=code;
}
private final String code;
@Override
public String getCode() {
return this.code;
}
@Table
@Data
public class DefaultValueTest {
@TableId
private Integer id;
@TableField(defaultValue = "{BLANK}")
private String value1;
@TableField(defaultValue = "1", updateDefaultValue = "2")
private Integer value2;
@TableField(defaultValue = "{NOW}")
private LocalDateTime createTime;
private TestEnum value3;
}
DefaultValueTestMapper mapper = session.getMapper(DefaultValueTestMapper.class);
DefaultValueTest defaultValueTest = new DefaultValueTest();
defaultValueTest.setValue3(TestEnum.X1);
mapper.save(defaultValueTest);
QueryChain.of(mapper)
.in(DefaultValueTest::getValue1,Arrays.asList(TestEnum.X1,TestEnum.X2))
.list();
把它看成普通的参数即可,用户和 int string 都是一样的
@Table
public class Student {
}
@Table
public class Student {
@TableId
private Integer id;
}
@TableId 支持不同数据库自增或序列 以及 自定义SQL,默认是数据库自增
属性 | 默认 | 说明 |
---|---|---|
value | IdAutoType.AUTO |
IdAutoType.AUTO: 数据库自增 IdAutoType.NONE: 开发者自己set值 IdAutoType.SQL: 结合@TableId.sql属性使用 IdAutoType.NONE: 开发者自己set值 IdAutoType.GENERATOR: 结合@TableId.generatorName属性,实现自定义自增; |
dbType | DbType.MYSQL | 设置数据库的类型,@TableId 可配置多个,以支持多数据库切换 |
sql | "" | IdAutoType.SQL生效,实现数据库层自增;例如:SELECT LAST_INSERT_ID() 或 序列 |
generatorName | "" |
IdAutoType.GENERATOR生效;可取值: IdentifierGeneratorType.DEFAULT(推荐,可替换成自己的实现):基于雪花算法 IdentifierGeneratorType.UUID: 基于UUID IdentifierGeneratorType.mpNextId:基于雪花算法 自定义:只需要实现 IdentifierGenerator,并注册(项目启动时)ID生成器:IdentifierGeneratorFactory.register("名字",生成器的实例) |
@Table
public class Student {
@TableField
private LocalDateTime createTime;
}
@TableField 可以设置列名、typeHandler、jdbcType、是否查询、是否更新,保存时默认值,修改时默认值 等
默认值 可以是常量,动态值(结合 动态参数配置),例如{BLANK} 空值,支持string,list,map,set,数组,更多查看 动态参数配置 一项
@Data
@Table
public class Achievement {
@TableId
private Integer id;
@ForeignKey(Student.class)
private Integer studentId;
private BigDecimal score;
private Date createTime;
}
非实体类映射,可以select(非实体类.class),除@ResultField注解,其他均可自动帮你select;
QueryChain queryChain = QueryChain.of(sysUserMapper)
.select(SysUserRoleAutoSelectVo.class)
.from(SysUser.class)
.join(SysUser.class, SysRole.class)
.eq(SysUser::getId, 2)
.returnType(SysUserRoleAutoSelectVo.class);
@Data
@ToString(callSuper = true)
@ResultEntity(Student.class)
public class StudentVo {
private Integer id;
private String name;
//private LocalDateTime stCreateTime;
@ResultEntityField(target = Student.class, property = "createTime")
private LocalDateTime st2CreateTime;
}
@Data
@ToString(callSuper = true)
@ResultEntity(Student.class)
public class StudentAchievementVo extends StudentVo {
@ResultEntityField(target = Achievement.class, property = "id")
private Integer achievementId;
@NestedResultEntity(target = Achievement.class)
private Achievement achievement;
@ResultField(value = "xx_score")
private Integer score;
}
用于返回类 和 实体类关联 (只能配置一个,哪个返回列多,配哪个实体类)
用于解决字段名字和实体类名字不一致的问题
用于内嵌类的映射 和 @ResultEntity 类似,可以映射一对一,一对多(List 属性)
@Data
@ResultEntity(SysRole.class)
public class OneToManyVo {
private Integer id;
private String name;
private LocalDateTime createTime;
@NestedResultEntity(target = SysUser.class)
private List<SysUser> sysUserList;
}
用于解决内嵌字段名字和实体类名字不一致的问题
返回列的映射(用于非实体类字段,可以设置列名、typeHandler、jdbcType) 返回可以平级 或者 1级 2级 多层映射
@Data
@ResultEntity(SysUser.class)
public class SysUserVo {
private Integer id;
private String userName;
@ResultField("asNameOther")
private String asName;
@ResultField
private String asName2;
}
2种用法:
SysUserVo sysUser = QueryChain.of(sysUserMapper)
.select(SysUser::getId, SysUser::getUserName)
.selectWithFun(SysUser::getUserName, c -> c.as("asNameOther"))
.selectWithFun(SysUser::getUserName, c -> c.as(SysUserVo::getAsName2))
.from(SysUser.class)
.eq(SysUser::getId, 1)
.returnType(SysUserVo.class)
.get();
asName 字段 也可以 用 selectWithFun(SysUser::getUserName, c -> c.as(SysUserVo::getAsName))映射
乐观锁,只能注解在Integer类型字段上
在save(实体类)、save(Model)、update(实体类)、update(Model);
其他update地方操作 需要自己维护,进行version+1.
多租户是围绕实体进行自动设置租户ID,通常在 from(实体类),join(实体类),delete(实体类),update(实体类),
另外设置租户ID的获取方法,示例是返回租户ID为2:
TenantContext.registerTenantGetter(() -> {
return 2;
});
如果想临时关闭
TenantContext.registerTenantGetter(() -> {
if(临时关闭){
//返回null 即可
return null;
}
return 2;
});
支持字段类型:string,数字,布尔类型,时间类型(Date,LocalDateTime,Long,Integer)
逻辑删除 在deleteById,delete(实体类),delete(Where) 生效
查询时,将自动添加删除过滤条件(通常在 from(实体类),join(实体类),update(实体类)时,自动添加,delete 除上面3个方法, 其他不附加)
@Data
@Table
public class LogicDeleteTest {
@TableId
private Long id;
private String name;
private LocalDateTime deleteTime;
@LogicDelete(beforeValue = "0", afterValue = "1", deleteTimeField = "deleteTime")
private Byte deleted;
}
未删除前的值,只能是固定值;时间类型的逻辑,可不填
删除后的值,可固定值或者动态值 例如 afterValue = "{NOW}",目前支持LocalDateTime,Date,Long,Integer,框架自动给值
逻辑删除的时间字段,可不填,填了系统自动update 时 设置删除时间,deleteTimeField对应的字段类型 支持:LocalDateTime,Date,Long,Integer类型
MybatisMpConfig.setLogicDeleteSwitch(true);
try (LogicDeleteSwitch ignored = LogicDeleteSwitch.with(false)) {
logicDeleteTestMapper.getById(1);
}
上面代码必须try (LogicDeleteSwitch ignored = LogicDeleteSwitch.with(false))
或
下面的更简单:
LogicDeleteTest logicDeleteTest = LogicDeleteUtil.execute(false, () -> {
return logicDeleteTestMapper.getById(1);
});
用于非实体类中,内嵌(非实体)类中 配置代码
@Data
@ResultEntity(SysUser.class)
public class FetchSysUserVo {
private Integer id;
private String userName;
private String password;
@Fetch(source = SysUser.class, property = "role_id", target = SysRole.class, targetProperty = "id")
private SysRoleVo sysRole;
private LocalDateTime create_time;
}
List<FetchSysUserVo> list = QueryChain.of(sysUserMapper)
.select(FetchSysUserVo.class)
.from(SysUser.class)
.eq(SysUser::getId,2)
.returnType(FetchSysUserVo.class)
.list();
[FetchSysUserVo(id=2, userName=test1, password=123456, sysRole=SysRoleVo(id=1, name=测试), create_time=2023-10-11T15:16:17)]
以上为1对1,如果需要实现 1对多,则 private SysRoleVo sysRole 改为 private List sysRoles 即可
SysRoleVo 也可以是 实体类 SysRole
@Fetch 属性说明
属性 | 默认值 | 说明 |
---|---|---|
column | "" |
指定结果列,用于获取查询子表的值 column 和 property 二选一,column优先 |
source | Void.class |
指定列的对应的实体 选择property属性时填写 |
property | "" |
指定列的对应的实体的属性 column 和 property 二选一,column优先 |
storey | 1 |
指定列的存储层级,默认为1 选择property属性时填写 |
target |
指定加载实体类(也就是表的意思) |
|
targetProperty |
指定加载实体类的属性 指定属性对象列进行匹配查询 |
|
targetSelectProperty |
指定返回实体类的属性 指定返回属性对象列 |
|
multiValueErrorIgnore | false |
1对1 多条时,发现多条是否忽略错误 |
orderBy |
排序,格式为 属性 desc/asc,多个逗号分割 例如:id asc,userName desc |
Model类字段实体类注解 用于解决字段命名不一样问题
Model是类似实体类子集类,用于新增、修改中,可以减少类型转换的损失;save(model)/update(model) 再也不用转换了
@Data
@Table
public class IdTest {
@TableId
@TableId(dbType = DbType.SQL_SERVER, value = IdAutoType.AUTO)
@TableId(dbType = DbType.PGSQL, value = IdAutoType.SQL, sql = "select nextval('seq1')")
private Long id;
private LocalDateTime createTime;
}
@Data
public class IdTestModel implements Model<IdTest> {
@ModelEntityField("id")
private Long xxid;
private LocalDateTime createTime;
}
Model类会继承实体类的相关信息,例如上面 IdTestModel 自动匹配 IdTest的相关信息;
丰富Vo类 ,实现类似脱敏的功能;注意:实体类里不会生效
package com.mybatis.mp.core.test.typeHandler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.*;
public class PhoneTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
throw new RuntimeException("not support");
}
private String format(String value) throws SQLException {
if (value != null) {
//此处实现 手机号码脱敏
return value.substring(0,3)+"****"+value.substring(7);
}
return "";
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return format(rs.getString(columnName));
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return format(rs.getString(columnIndex));
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return format(cs.getString(columnIndex));
}
}
@Data
@ResultEntity(SysRole.class)
public class OneToManyTypeHandlerVo {
private Integer id;
@TypeHandler(PhoneTypeHandler.class)
private String name;
private LocalDateTime createTime;
@TypeHandler(PhoneTypeHandler.class)
@ResultField("kk2")
private String kkName;
@NestedResultEntity(target = SysUser.class)
private List<SysUserTypeHandlerVo> sysUserList;
}
内嵌的类 也是可以的
@Data
public class SysUserTypeHandlerVo {
private Integer id;
@TypeHandler(PhoneTypeHandler.class)
private String userName;
@TypeHandler(PhoneTypeHandler.class)
@NestedResultEntityField("password")
private String pwd;
@TypeHandler(PhoneTypeHandler.class)
@ResultField("kk")
private String kkName;
}
查询代码:关键在 returnType(OneToManyTypeHandlerVo.class) ;其他都是普通的查询代码
List<OneToManyTypeHandlerVo> list = QueryChain.of(sysRoleMapper)
.select(SysUser.class)
.selectWithFun(SysUser::getUserName, c -> c.as("kk"))
.selectWithFun(SysUser::getUserName, c -> c.as("kk2"))
.select(SysRole.class)
.from(SysRole.class)
.join(SysRole.class, SysUser.class, on -> on.eq(SysUser::getRole_id, SysRole::getId))
.returnType(OneToManyTypeHandlerVo.class)
.list();
- 方法返回是 Pager T不能省略
- 方法第一个参数 是 Pager 类型
- 方法上加上注解 @Paging
@Paging
Pager<SysRole> xmlPaging(Pager<SysRole> pager, @Param("id") Integer id, @Param("id2") Integer id2);
@Paging
Pager<SysRole> xmlPaging2(Pager<SysRole> pager);
@Paging
Pager<SysRole> xmlDynamicPaging(Pager<SysRole> pager, @Param("id") Integer id, @Param("id2") Integer id2, @Param("id3") Integer id3);
@Paging
@Select("select * from sys_role where id >=#{id} and id <=#{id2}")
Pager<SysRole> annotationPaging(Pager<SysRole> pager, @Param("id") Integer id, @Param("id2") Integer id2);
<resultMap id="sysRole" type="com.mybatis.mp.core.test.DO.SysRole">
<id column="id" property="id"/>
</resultMap>
<select id="xmlPaging" resultType="com.mybatis.mp.core.test.DO.SysRole">
select *
from sys_role
where id >= #{id}
and id <= #{id2}
</select>
<select id="xmlPaging2" resultMap="sysRole">
select *
from sys_role
</select>
<select id="xmlDynamicPaging" resultType="com.mybatis.mp.core.test.DO.SysRole">
select * from sys_role where id >=#{id} and id <=#{id2}
<if test="id3 != null">
and id <=#{id3}
</if>
</select>
Pager<SysRole> pager = sysRoleMapper.xmlPaging(Pager.of(1), 1, 1);
Pager<SysRole> pager = sysRoleMapper.xmlPaging2(Pager.of(2));
Pager<SysRole> pager = sysRoleMapper.xmlDynamicPaging(Pager.of(2),1,2,1);
Pager<SysRole> pager = sysRoleMapper.annotationPaging(Pager.of(2), 1, 2);
mybatis-mp 只设计到1层持久层,不过 mybatis-mp的理念,把持久层分2层,mapper层,dao层
区别在于 dao层是对mapper的扩展和限制
扩展:增加CRUD链式操作 增加 queryChain()、updateChain()、deleteChain()、insertChain()等方法,无需操作mapper接口;
限制:dao 只暴露 save(实体类|Model类)、update(实体类|Model类)、getById(ID)、deleteById(ID)、delete(实体类)等
mapper层一般不增加代码,如果有无法的实现的数据库操作,则需要在 mapper类上添加方法
如果不需要dao 可以直接使用mapper接口,进行CRUD;代码生成器有对应的关闭dao生成 和 service 注入mapper的开关
service 不应该支持操作mapper,因为mapper包含丰富的api,这样不利于代码的维护性
service 不应该使用Query等作为参数,dao层也不应该;让service更专注于业务
为了增加CRUD一体式操作,增加了链路式类,分别为是:
QueryChain 包含 get(),list(),count(),exists(),map(),paging()等查询方法;
UpdateChain 包含 execute();
InsertChain 包含 execute();
DeleteChain 包含 execute();
Chain类都包含一个of(MybatisMapper mapper)静态方法,直接调用即可
例如:
List<SysUser> list=QueryChain.of(sysUserMapper).select(...).list();
int updateCnt=UpdateChain.of(sysUserMapper)
.update(SysUser.class)
.set(SysUser::getName,"hi")
.eq(SysUser::getName,"haha")
.execute();
dao 里自带 queryChain()、updateChain()等方法,可以直接获取链路式CRUD类
继承 cn.mybatis.mp.core.mvc.Dao 接口 和 cn.mybatis.mp.core.mvc.impl.DaoImpl
queryChain()
updateChain()
insertChain()
deleteChain() 使用方式
queryChain()
.select(SysUser.class)
.select(SysRole.class)
.selectWithFun(SysUser::getName,c->c.concat("").as("copy_name"))
.from(SysUser.class)
.join(SysUser.class,SysRole.class)
.eq(SysUser::getId,id)
.returnType(SysUserVo.class)
.get();
updateChain()
.update(SysRole.class)
.set(SysRole::getName,"test")
.eq(SysRole::getId,1)
.execute();
使用代码生成器时,可在 ServiceImplConfig injectMapper 一项设置为true,即可生成 queryChain()等方法 和 Dao 层 链路式 CRUD 一样
建议在dao里操作,如果还是想操作,参考 其他层 链路式 CRUD
QueryChain.of(sysUserMapper)
.select(SysUser.class)
.select(SysRole.class)
.selectWithFun(SysUser::getName,c->c.concat("").as("copy_name"))
.from(SysUser.class)
.join(SysUser.class,SysRole.class)
.eq(SysUser::getId,id)
.returnType(SysUserVo.class)
.get();
UpdateChain.of(sysUserMapper)
.update(SysRole.class)
.set(SysRole::getName,"test")
.eq(SysRole::getId,1)
.execute();
其他框架一般都是默认忽略null值参数的
但是这样可能比较容易导致bug出现,例如 删除 修改时,因为null 导致数据紊乱了
因此mybatis-mp,默认会检测 null值,并设有开关,让有需要忽略null,或者 空字符串等需要操作;如下使用:
Query重 select 可以select 实体类,vo类,属性等,推荐select vo类(也就是配置@ResultEntity的vo类)
SysUser sysUser = QueryChain.of(sysUserMapper)
// forSearch包含忽略null 、空字符串、对字符串进行trim去空格
.forSearch()
.select(SysUser::getId)
.from(SysUser.class)
.eq(SysUser::getUserName, null )
.eq(SysUser::getUserName, "" )
.eq(SysUser::getUserName," admin ")
.returnType(SysUser.class)
.get();
或者
SysUser sysUser = QueryChain.of(sysUserMapper)
// 忽略 null 条件参数
.ignoreNullValueInCondition(true)
// 忽略 空字符串 条件参数
.ignoreEmptyInCondition(true)
// 对字符串进行trim 去空格操作
.trimStringInCondition(true)
.select(SysUser::getId)
.from(SysUser.class)
.eq(SysUser::getUserName, null )
.eq(SysUser::getUserName, "" )
.eq(SysUser::getUserName," admin ")
.returnType(SysUser.class)
.get();
目前 CRUD类、Where类都支持以上方法
Mapper 需要继承 MybatisMapper
public interface StudentMapper extends MybatisMapper<Student> {
}
getById(Serializable id) 根据ID查询实体
R get(Query query) 单个动态查询(可自定返回类型)
T get(Where where) 单个动态查询(只返回实体类)
List list(Query query) 列表动态查询(可自定返回类型)
List list(Where where) 列表动态查询(只返回实体类)
count(Query query) 动态count查询
count(Where where) 动态count查询
exists(Query query) 动态检测是否存在
exists(Where where) 动态检测是否存在
deleteById(Serializable id) 根据ID删除
delete(T entity) 根据实体类删除
delete(Where where) 动态删除
delete(Delete delete) 动态删除
deleteByIds(Serializable... ids) 根据多个ID删除
deleteByIds(List ids) 根据多个ID删除
save(T entity) 实体类保存
save(Model entity) 实体类部分保存
save(Insert insert) 动态插入(无法返回ID)
save(List list) 插入多个
saveBatch(List list, Getter... saveFields) 原生sql批量插入,需要指定列
* 使用数据库原生方式批量插入 * 一次最好在100条内 * * 会自动加入 主键 租户ID 逻辑删除列 乐观锁 * 自动设置 默认值,不会忽略NULL值字段
List<DefaultValueTest> list= Arrays.asList(new DefaultValueTest(),new DefaultValueTest());
mapper.saveBatch(list, DefaultValueTest::getValue1, DefaultValueTest::getValue2, DefaultValueTest::getCreateTime);
update(T entity) 实体类更新
update(T entity,F... fields) 实体类更新 + 强制字段更新
update(Model entity) 实体类部分更新
update(Model entity,F... fields) 实体类部分更新 + 强制字段更新
update(T entity,Where where) 实体类批量更新
update(Update update) 动态更新
Map<K, V> mapWithKey(Getter mapKey, Serializable... ids) key为mapKey,value当前实体类
Map<K, V> mapWithKey(Getter mapKey, BaseQuery query) key为mapKey,value为query指定的类型
Map<K, V> mapWithKey(Getter mapKey, List ids) key为mapKey,value当前实体类
Map<K, T> mapWithKey(Getter mapKey, Consumer consumer) key为mapKey,value当前实体类
Map<K, T> mapWithKey ... 还有其他的方法
Pager paging(Query query, Pager pager) 分页查询(可自定返回类型)
Pager paging(Where where, Pager pager) 分页查询(只返回实体类类型)
去除无用left join
去除无用left join (自动判断是否有效)
去除无用的order by (自动判断是否有效)
优化union 查询 (优化 left join 和 order by,自动判断是否有效)
文档为演示 所以是调用 QueryChain.of(mapper),实际使用 queryChain()方法,在dao层
Student stu=studentMapper.getById(1);
或
Student stu2=QueryChain.of(sysUserMapper)
.eq(Student::getId,1)
.get();
或
Student stu3=studentMapper.get(where->where.eq(Student::getId,1));
能用前者优先前者,后者为单个动态查询
Student stu3=QueryChain.of(sysUserMapper)
.select(Student::getName,Student::getCreateTime)
.from(Student.class)
.eq(Student::getId,1)
.get();
Student stu3=QueryChain.of(sysUserMapper)
.select(Student.class)
.selectIgnore(Student::getCreateTime)
.from(Student.class)
.eq(Student::getId,1)
.get();
注意:需要先select 再 selectIgnore
List<Achievement> achievementList=QueryChain.of(achievementMapper)
.select(Achievement.class)
.select(Student::getName)
.from(Achievement.class)
.join(Achievement.class,Student.class,on->on.eq(Achievement::getStudentId,Student::getId))
.eq(Achievement::getId,1)
.list();
支持各种连接:INNER JOIN ,LEFT JOIN 等等
join 可结合 @ForeignKey使用 这样无需加 ON 条件
List<Achievement> achievementList2=QueryChain.of(achievementMapper)
.select(Achievement.class)
.select(Student::getName)
.from(Achievement.class)
.join(Achievement.class,Student.class)
.eq(Achievement::getId,1)
.list();
注意,假如自己拼接上了 on 条件 ,则 @ForeignKey 不生效,需要自己把条件书写完成!
List<SysUser> list=QueryChain.of(sysUserMapper)
.select(SysUser.class)
.from(SysUser.class)
.join(JoinMode.INNER,SysUser.class,1,SysUser.class,2,on->on.eq(SysUser::getId,1,SysUser::getRole_id,2))
.list();
注意 select(SysUser.class) 只是返回前面那个表的数据,如需返回后面那个表,则需要 结合注解@ResultField(别名)
然后 new Query().select(SysUser::getUserName,2,c->c.as("sub_name")),其中2 表示实体类SysUser对应的表实例的缓存层级
List<SysUserAndRole> list=QueryChain.of(sysUserMapper)
.select(SysUser.class)
.select(SysRole.class)
.from(SysUser.class)
.join(SysUser.class,SysRole.class,on->on.eq(SysUser::getRole_id,SysRole::getId))
.returnType(SysUserAndRole.class)
.list();
SysUserAndRole 如何映射,请查看注解说明。
SubQuery subQuery=SubQuery.create("sub")
.select(SysRole.class)
.from(SysRole.class)
.eq(SysRole::getId,1);
List<SysUser> list=QueryChain.of(sysUserMapper)
.select(SysUser.class)
.from(SysUser.class)
.join(JoinMode.INNER,SysUser.class,subQuery,on->on.eq(SysUser::getRole_id,subQuery.$(subQuery,SysRole::getId)))
.list();
这个方法的意义在于 拿到本身实例,从而更好的链式操作,例如下面的query.$(SysUser::getId):
这样可以使用query里方法,query.$(SysUser::getId) 就是从query里取得SysUser的id列,从而被 exists子查询引用。
List<SysUser> list=QueryChain.of(sysUserMapper)
.select(SysUser::getId,SysUser::getUserName,SysUser::getRole_id)
.from(SysUser.class)
.connect(query->{
query.exists(SubQuery.create()
.select1()
.from(SysUser.class)
.eq(SysUser::getId,query.$(SysUser::getId))
.isNotNull(SysUser::getPassword)
.limit(1)
);
})
.list();
studentMapper.deleteById(1);
或
DeleteChain.of(studentMapper).eq(Student::getId,1).execute();
或
studentMapper.delete(where->where.eq(Student::getId,1))
能用前者优先前者,后者为单个动态删除
Student student=new Student();
//student.setIdMethod(11);
student.setName("哈哈");
student.setExcellent(true);
student.setCreateTime(LocalDateTime.now());
studentMapper.save(student);
或者
@Data
public class StudentDTO implements cn.mybatis.mp.db.Model<Student> {
private Integer id;
private String name;
private LocalDateTime createTime;
}
StudentDTO studentDTO = new StudentDTO();
studentDTO.setName("DTO Insert");
studentDTO.setCreateTime(LocalDateTime.now());
studentMapper.save(studentDTO);
或者
InsertChain.of(studentMapper)
.insert(Student.class)
.field(
Student::getName,
Student::getExcellent,
Student::getCreateTime
)
.values(Arrays.asList("哈哈",true,LocalDateTime.now()))
.execute();
能用前者优先前者,后者为动态插入(可多个)
Student student=new Student();
student.setName("哈哈");
student.setExcellent(true);
student.setCreateTime(LocalDateTime.now());
studentMapper.update(student);
或者
@Data
public class StudentDTO implements cn.mybatis.mp.db.Model<Student> {
private Integer id;
private String name;
private LocalDateTime createTime;
}
StudentDTO studentDTO = new StudentDTO();
studentDTO.setId(1);
studentDTO.setName("DTO Insert");
studentMapper.update(studentDTO);
或者
UpdateChain.of(studentMapper)
.update(Student.class)
.set(Student::getName,"嘿嘿")
.eq(Student::getId,1)
.execute();
或者
SysUser updateSysUser = new SysUser();
updateSysUser.setUserName("adminxx");
sysUserMapper.update(updateSysUser, where->where.eq(SysUser::getId,1));
能用前者优先前者,后者为动态更新
List<Integer> counts=QueryChain.of(sysUserMapper)
.select(SysUser::getId,c->c.count())
.from(SysUser.class)
.groupBy(SysUser::getRole_id)
.returnType(Integer.TYPE)
.list();
SysUser sysUser=QueryChain.of(sysUserMapper)
.select(SysUser::getId,SysUser::getUserName,SysUser::getRole_id)
.from(SysUser.class)
.orderBy(false,SysUser::getRole_id,SysUser::getId)
.limit(1)
.get();
Integer count=QueryChain.of(sysUserMapper)
.selectWithFun(SysUser::getRole_id,FunctionInterface::count)
.from(SysUser.class)
.groupBy(SysUser::getRole_id)
.having(SysUser::getRole_id,c->c.gt(0))
.returnType(Integer.TYPE)
.get();
QueryChain.of(sysUserMapper)
.select(SysUser::getId)
.from(SysUser.class)
.eq(SysUser::getId,2).or().eq(SysUser::getId,1)
.returnType(Integer.TYPE)
.get();
调用 and(),则后续操作默认都and操作
调用 or(),则后续操作默认都or操作
Integer id=QueryChain.of(sysUserMapper)
.select(SysUser::getId)
.from(SysUser.class)
.gt(SysUser::getId,2)
.returnType(Integer.TYPE)
.get();
Integer id=QueryChain.of(sysUserMapper)
.select(SysUser::getId)
.from(SysUser.class)
.gte(SysUser::getId,2)
.limit(1)
.returnType(Integer.TYPE)
.get();
Integer id=QueryChain.of(sysUserMapper)
.select(SysUser::getId)
.from(SysUser.class)
.lt(SysUser::getId,2)
.limit(1)
.returnType(Integer.TYPE)
.get();
Integer id=QueryChain.of(sysUserMapper)
.select(SysUser::getId)
.from(SysUser.class)
.lte(SysUser::getId,1)
.limit(1)
.returnType(Integer.TYPE)
.get();
Integer id=QueryChain.of(sysUserMapper)
.select(SysUser::getId)
.from(SysUser.class)
.eq(SysUser::getId,2)
.returnType(Integer.TYPE)
.get();
Integer id=QueryChain.of(sysUserMapper)
.select(SysUser::getId)
.from(SysUser.class)
.ne(SysUser::getId,2)
.returnType(Integer.TYPE)
.count();
SysUserMapper sysUserMapper=session.getMapper(SysUserMapper.class);
SysUser sysUser=QueryChain.of(sysUserMapper)
.select(SysUser::getId,SysUser::getPassword,SysUser::getRole_id)
.from(SysUser.class)
.isNull(SysUser::getPassword)
.get();
SysUser sysUser=QueryChain.of(sysUserMapper)
.select(SysUser::getId,SysUser::getPassword)
.from(SysUser.class)
.isNotNull(SysUser::getPassword)
.eq(SysUser::getId,3)
.returnType(Integer.TYPE)
.get();
List<Integer> list=QueryChain.of(sysUserMapper)
.select(SysUser::getId)
.from(SysUser.class)
.in(SysUser::getId,1,2)
.returnType(Integer.TYPE)
.list();
SysUser sysUser=QueryChain.of(sysUserMapper)
.select(SysUser::getId,SysUser::getPassword,SysUser::getRole_id)
.from(SysUser.class)
.like(SysUser::getUserName,"test1")
.get();
SysUser sysUser = QueryChain.of(sysUserMapper)
.select(SysUser::getId, SysUser::getPassword, SysUser::getRole_id)
.from(SysUser.class)
.like(SysUser::getUserName, "test1", LikeMode.LEFT)
.get();
Integer count = QueryChain.of(sysUserMapper)
.select(SysUser::getId, c -> c.count())
.from(SysUser.class)
.like(SysUser::getUserName, "test", LikeMode.RIGHT)
.returnType(Integer.TYPE)
.count();
SysUser sysUser = QueryChain.of(sysUserMapper)
.select(SysUser::getId, SysUser::getPassword, SysUser::getRole_id)
.from(SysUser.class)
.notLike(SysUser::getUserName, "test1")
.like(SysUser::getUserName, "test")
.get();
SysUser sysUser = QueryChain.of(sysUserMapper)
.select(SysUser::getId, SysUser::getPassword, SysUser::getRole_id)
.from(SysUser.class)
.notLike(SysUser::getUserName, "est1", LikeMode.LEFT)
.like(SysUser::getUserName, "test")
.get();
SysUser sysUser = QueryChain.of(sysUserMapper)
.select(SysUser::getId, SysUser::getPassword, SysUser::getRole_id)
.from(SysUser.class)
.notLike(SysUser::getUserName, "test2", LikeMode.RIGHT)
.like(SysUser::getUserName, "test")
.get();
List<Integer> list = QueryChain.of(sysUserMapper)
.select(SysUser::getId)
.from(SysUser.class)
.between(SysUser::getId, 1, 2)
.returnType(Integer.TYPE)
.list();
List<Integer> list = QueryChain.of(sysUserMapper)
.select(SysUser::getId)
.from(SysUser.class)
.between(SysUser::getId, 1, 3)
.notBetween(SysUser::getId, 1, 2)
.returnType(Integer.TYPE)
.list();
boolean exists = QueryChain.of(sysUserMapper)
.select(SysUser::getId, SysUser::getUserName, SysUser::getRole_id)
.from(SysUser.class)
.join(SysUser.class, SysRole.class)
.like(SysUser::getUserName, "test")
.exists();
或者
sysUserMapper.exists(where->where.like(SysUser::getUserName, "test"));
List<Integer> roleIds = QueryChain.of(sysUserMapper)
.selectDistinct()
.select(SysUser::getRole_id)
.from(SysUser.class)
.returnType(Integer.TYPE)
.list();
List<SysUser> list = QueryChain.of(sysUserMapper)
.select(SysUser::getRole_id, SysUser::getId)
.from(SysUser.class)
.eq(SysUser::getId, 1)
.union(Query.create()
.select(SysUser::getRole_id, SysUser::getId)
.from(SysUser.class)
.lt(SysUser::getId, 3)
.list();
List<SysUser> list = QueryChain.of(sysUserMapper)
.select(SysUser::getRole_id, SysUser::getId)
.from(SysUser.class)
.eq(SysUser::getId, 1)
.unionAll(Query.create()
.select(SysUser::getRole_id, SysUser::getId)
.from(SysUser.class)
.lt(SysUser::getId, 3)
.list();
Integer id = QueryChain.of(sysUserMapper)
.select(SysUser::getId)
.from(SysUser.class)
.eq(SysUser::getId, 2)
.empty(SysUser::getUserName)
.returnType(Integer.TYPE)
.get();
Integer id = QueryChain.of(sysUserMapper)
.select(SysUser::getId)
.from(SysUser.class)
.eq(SysUser::getId, 2)
.notEmpty(SysUser::getUserName)
.returnType(Integer.TYPE)
.get();
SubQuery subQuery = SubQuery.create("sub")
.select(SysRole.class)
.from(SysRole.class)
.eq(SysRole::getId, 1);
List<SysUser> list = QueryChain.of(sysUserMapper)
.with(subQuery)
.selectWithFun(subQuery, SysRole::getId, c -> c.as("xx"))
.select(subQuery, "id")
.select(SysUser.class)
.from(SysUser.class)
.from(subQuery)
.eq(SysUser::getRole_id, subQuery.$(subQuery, SysRole::getId))
.orderBy(subQuery, SysRole::getId)
.list();
上面是一个利用with 构建的复杂SQL,核心在 .with(subQuery)
.from(subQuery)
把它看成一个子查询
Integer count = QueryChain.of(sysUserMapper)
.select(SysUser::getId, c -> c.count())
.from(SysUser.class)
.like(SysUser::getUserName, "test", LikeMode.RIGHT)
.returnType(Integer.TYPE)
.count();
selectWithFun(SysUser::getId,c->c.min())
selectWithFun(SysUser::getId,c->c.max())
selectWithFun(SysUser::getId,c->c.avg())
selectWithFun(SysUser::getId,c->c.plus(1))
selectWithFun(SysUser::getId,c->c.subtract(1))
selectWithFun(SysUser::getId,c->c.multiply(1))
selectWithFun(SysUser::getId,c->c.divide(1))
abs,
pow,
concat,
concatAs,
round,
if,
case when
比较函数
gte,gt,lt,lte 等等还很多
Integer id = QueryChain.of(sysUserMapper)
.select(SysUser::getId)
.from(SysUser.class)
.and(SysUser::getId, c -> c.concat("x1").eq("2x1"))
.returnType(Integer.TYPE)
.get();
或
SysUser sysUser = sysUserMapper.get(where -> where.and(SysUser::getId, c -> c.concat("x1").eq("2x1")));
boolean exists = QueryChain.of(sysUserMapper)
.select(SysUser::getId, SysUser::getUserName, SysUser::getRole_id)
.from(SysUser.class)
.join(SysUser.class, SysRole.class)
.like(SysUser::getUserName, "test")
.exists();
List<SysUser> list = QueryChain.of(sysUserMapper)
.select(SysUser::getId, SysUser::getUserName, SysUser::getRole_id)
.from(SysUser.class)
.connect(queryChain -> {
queryChain.in(SysUser::getId, new SubQuery()
.select(SysUser::getId)
.from(SysUser.class)
.connect(subQuery -> {
subQuery.eq(SysUser::getId, queryChain.$().field(SysUser::getId));
})
.isNotNull(SysUser::getPassword)
.limit(1)
);
})
.list();
sql 如下:
SELECT
t.id, t.user_name, t.role_id
FROM
t_sys_user t
WHERE
t.id IN (SELECT
st.id
FROM
t_sys_user st
WHERE
st.id = t.id AND st.password IS NOT NULL
LIMIT 1 OFFSET 0)
Integer count = QueryChain.of(sysUserMapper)
.selectWithFun(SysUser::getId, FunctionInterface::count)
.from(SysUser.class)
.join(JoinMode.INNER, SysUser.class, 1, SysUser.class, 2, on -> on.eq(SysUser::getId, 1, SysUser::getRole_id, 2))
.returnType(Integer.TYPE)
.get();
sql 如下:
SELECT
COUNT(t.id)
FROM
t_sys_user t
INNER JOIN
t_sys_user t2 ON t.id = t2.role_id
LIMIT 1 OFFSET 0
SubQuery subQuery = SubQuery.create("sub")
.select(SysRole.class)
.from(SysRole.class)
.eq(SysRole::getId, 1);
List<SysUser> list = QueryChain.of(sysUserMapper)
.selectWithFun(subQuery, SysRole::getId, c -> c.as("xx"))
.select(SysUser.class)
.from(SysUser.class)
.join(JoinMode.INNER, SysUser.class, subQuery, on -> on.eq(SysUser::getRole_id, subQuery.$(subQuery, SysRole::getId)))
.orderBy(subQuery, SysRole::getId)
.list();
selectWithFun(subQuery, SysRole::getId, c -> c.as("xx")) 返回子表的角色ID并设置别名 sql 如下:
SELECT sub.id AS xx , sub.id , t.id , t.user_name , t.password , t.role_id , t.create_time
FROM t_sys_user t
INNER JOIN (
SELECT st.id , st.name , st.create_time FROM sys_role st WHERE st.id = 1
) AS sub ON t.role_id = sub.id
ORDER BY sub.id ASC
new Query().select1();
new Query().selectAll();
new Query().selectCount1();
new Query().selectCountAll();
MybatisBatchUtil 内置了批量保存,批量修改,批量其他操作
/**
* 批量插入(batchSize!=1时,无法获取主键)
*
* @param sqlSessionFactory mybatis SqlSessionFactory 通过spring 注解注入获取
* @param mapperType MybatisMapper 的 class
* @param list 数据列表
* @param batchSize 一次批量处理的条数(如需获取主键,请设置为1)
* @param <M> MybatisMapper
* @param <T> 数据的类型
* @return 影响的条数
*/
public static <M extends MybatisMapper, T> int batchSave(SqlSessionFactory sqlSessionFactory, Class<M> mapperType, List<T> list, int batchSize) {
}
/**
* 批量更新
*
* @param sqlSessionFactory mybatis SqlSessionFactory 通过spring 注解注入获取
* @param mapperType MybatisMapper 的 class
* @param list 数据列表
* @param batchSize 一次批量处理的条数
* @param <M> MybatisMapper
* @param <T> 数据的类型
* @return 影响的条数
*/
public static <M extends MybatisMapper, T> int batchUpdate(SqlSessionFactory sqlSessionFactory, Class<M> mapperType, List<T> list, int batchSize) {
}
/**
* 批量操作
*
* @param sqlSessionFactory mybatis SqlSessionFactory 通过spring 注解注入获取
* @param mapperType MybatisMapper 的 class
* @param list 数据列表
* @param batchSize 一次批量处理的条数
* @param batchFunction 操作方法
* @param <M> MybatisMapper
* @param <T> 数据的类型
* @return 影响的条数
*/
public static <M extends MybatisMapper, T> int batch(SqlSessionFactory sqlSessionFactory, Class<M> mapperType, List<T> list, int batchSize, MybatisBatchBiConsumer<SqlSession, M, T> batchFunction) {
}
List<IdTest> list = new ArrayList<>(10000);
for (int i = 0; i < 10000; i++) {
IdTest idTest = new IdTest();
idTest.setCreateTime(LocalDateTime.now());
list.add(idTest);
}
MybatisBatchUtil.batchSave(sqlSessionFactory, IdTestMapper.class, list);
sqlSessionFactory 是mybatis SqlSessionFactory 可通过spring 依赖注入获得
IdTestMapper 是mybatis Mapper 接口
如需获取主键,可设置batchSize=1,虽然性能可能下降,也比一般的循环save,update快!
项目启动时设置
MybatisMpConfig.setDefaultValue("{NOW}", (type) -> {
if (type == LocalDateTime.class) {
return LocalDateTime.now();
} else if (type == LocalDate.class) {
return LocalDate.now();
} else if (type == Date.class) {
return new Date();
} else if (type == Long.class) {
return System.currentTimeMillis();
} else if (type == Integer.class) {
return (int) (System.currentTimeMillis() / 1000);
}
throw new RuntimeException("Inconsistent types");
});
可应用在 字符串,集合,数组上
可应用在 LocalDateTime,LocalDate,Date,Long,Integer 字段上
Query,QueryChain等中有个方法,专门提供创建sql的工厂类:$()
可创建 条件,列,表,函数等等,例如
new Query().$().table(...) //创建表
new Query().$().field(...) //创建表的列
new Query().$().columnName(...) //获取数据库列名
new Query().$().gt(...) //创建大于的条件
结合实际使用,例如:
new Query(){{
select(SysUser::getRole_id)
.from(SysUser.class)
.eq($().field(SysUser::getId),1)
.gt($().table(SysUser.class).$("role_id"),2);
}};
甚至 Query 也包含了部分创建 列 表的功能
new Query(){{
select($(SysUser::getId))
.from($(SysUser.class))
.eq($("id"),1);
}};
3个模板类:普通模板 CmdTemplate ,函数模板 FunTemplate(后续可继续调用框架的函数),条件模板 ConditionTemplate(用于 where 中)
QueryChain queryChain = QueryChain.of(sysUserMapper);
queryChain.selectWithFun(SysUser::getRole_id, c -> CmdTemplate.create("count({0})+{1}", c, "1"));
queryChain.from(SysUser.class);
queryChain.and(cs -> ConditionTemplate.create("{0}+{1}={2}", cs[0], cs[1], 2), SysUser::getId, SysUser::getId);
queryChain.returnType(String.class);
String str = queryChain.get();
QueryChain queryChain = QueryChain.of(sysUserMapper);
queryChain.selectWithFun(SysUser::getRole_id, c -> FunTemplate.create("count({0})",c).plus(1).concat(1,"2",3).length());
queryChain.from(SysUser.class);
queryChain.and(cs -> ConditionTemplate.create("{0}+{1}={2}", cs[0], cs[1], 2), SysUser::getId, SysUser::getId);
queryChain.returnType(String.class);
String str = queryChain.get();
Integer id = QueryChain.of(sysUserMapper)
//方法 1
.selectWithFun(SysUser::getId, c -> c.sin().as("x_sin"))
.from(SysUser.class)
.eq(SysUser::getId, 2)
//方法 2
.and(queryChain -> {
return queryChain.$(SysUser::getCreate_time, c -> c.date().eq("2023-12-10"));
})
//方法 3
.and(queryChain -> {
return Methods.date(queryChain.$(SysUser::getCreate_time)).eq("2023-12-10");
})
.empty(SysUser::getUserName)
//方法 1
.orderBy(SysUser::getId, c -> c.plus(1))
.returnType(Integer.TYPE)
.get();
支持的函数 | 函数说明 |
---|---|
count | 查询数据总量 |
sum | 返回指定字段值的和 |
avg | 返回指定列的平均值 |
min | 返回指定列的最小值 |
max | 返回指定列的最大值 |
abs | 返回绝对值 |
ceil | 返回大于或等于 x 的最小整数(向上取整) |
floor | 返回小于或等于 x 的最大整数(向下取整) |
rand | 返回 0~1 的随机数 |
sign | 返回 x 的符号,x 是负数、0、正数分别返回 -1、0、1 |
pi | 返回圆周率 |
truncate | 返回数值 x 保留到小数点后 y 位的值 |
round | 返回离 x 最近的整数(四舍五入) |
pow | 返回 x 的 y 次方 |
power | 返回 x 的 y 次方 |
sqrt | 返回 x 的平方根 |
exp | 返回 e 的 x 次方 |
mod | 取模 |
log | 返回自然对数(以 e 为底的对数) |
log2 | 返回以 2 为底的对数 |
log10 | 返回以 10 为底的对数 |
radians | 将角度转换为弧度 |
degrees | 将弧度转换为角度 |
sin | 求正弦值 |
asin | 求反正弦值 |
cos | 求余弦值 |
acos | 求反余弦值 |
tan | 求正切值 |
atan | 求反正切值 |
cot | 求余切值 |
charLength | 返回字符串 s 的字符数 |
length | 返回字符串 s 的长度 |
concat | 字符串拼接 |
concatWs | 字符串拼接,需要指定分割符 |
upper | 转大写 |
lower | 转小写 |
left | 左截取 |
right | 截取 |
lpad | 从左字符串 补全,需要补全的字符和长度 |
rpad | 从右字符串 补全,需要补全的字符和长度 |
trim | 去除两边的空格 |
ltrim | 去除左边的空格 |
rtrim | 去除右边的空格 |
repeat | 将字符串 s 重复 n 次 |
replace | 用字符串 s2 代替字符串 s 中的字符串 s1 |
strcmp | 比较字符串 s1 和 s2 |
substring | 获取从字符串 s 中的第 n 个位置开始长度为 len 的字符串 |
instr | 从字符串 s 中获取 s1 的开始位置 |
reverse | 将字符串 s 的顺序反过来 |
field | 返回第一个与字符串 s 匹配的字符串的位置 |
findInSet | 返回在字符串 s2 中与 s1 匹配的字符串的位置 |
currentDate | 返回当前日期 |
currentTime | 返回当前时间 |
currentDateTime | 返回当前日期和时间 |
unixTimestamp | 以 UNIX 时间戳的形式返回当前时间 |
fromUnixTime | 把 UNIX 时间戳的时间转换为普通格式的时间 |
month | 日期 d 中的月份值,范围是 1~12 |
weekday | 日期星期几,0 表示星期一,1 表示星期二 |
year | 返回年 |
day | 返回日期的天数值 |
hour | 返回时间 t 中的小时值 |
dateDiff | 计算日期 d1 到 d2 之间相隔的天数 |
dateAdd | 日期加操作 |
dateSub | 日期减操作 |
md5 | 字符串md5 加密 |
inetAton | 将 IP 地址转换为数字表示,IP 值需要加上引号 |
inetNtoa | 将数字 n 转换成 IP 的形式 |
目前仅支持spring项目
mybatis:
configuration:
databaseId: MYSQL
已测试通过的有:
H2,MYSQL,MARIA_DB ,PGSQL,ORACLE(12c及以上),SQL SERVER(2012及以上),DM达梦,DB2
其实也支持其他数据库(只要是和以上数据库规范接近的),只是作者没有放开,如有需要,可联系作者放开!
<dependency>
<groupId>cn.mybatis-mp</groupId>
<artifactId>mybatis-mp-generator</artifactId>
<version>1.5.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.32</version>
</dependency>
// 根据数据库链接生成
new FastGenerator(new GeneratorConfig(
"jdbc:mysql://xxx.xx.x:3306/数据库名字",
"用户名",
"密码")
.basePackage("com.test")//根包路径
).create();
or
//根据数据源生成
new FastGenerator(new GeneratorConfig(
DbType.H2,//数据库类型
dataSource)
.basePackage("com.test")//根包路径
).create();
属性 | 默认值 | 说明 |
---|---|---|
containerType | SPRING |
容器类型,默认SPRING 目前支持,SPRING、SOLON |
swaggerVersion | 3 | swagger版本:2 代表2.x,3代表3.x |
author | "" | 作者 |
ignoreView | false | 是否忽略视图 |
ignoreTable | false | 是否忽略表 |
baseFilePath | System.getProperty("user.dir") + "/demo-generate" | 根文件路径 |
basePackage | "" | 根包路径 |
templateRootPath | templates | 模板根目录,默认即可 |
templateEngine | new FreemarkerTemplateEngine() | 模板引擎,默认Freemarker引擎,其他引擎需要自己实现 |
templateBuilders | 包含 实体类,mapper,mapper xml,dao,service,serviceImpl,action等模板生成构建器 | 模板生成构建器,继承AbstractTemplateBuilder,即可实现自己的生成器(生成自己的页面或其他类等) |
new GeneratorConfig(...).tableConfig(tableConfig->{
tableConfig.includeTables("table1","table2");
});
属性 | 默认值 | 说明 |
---|---|---|
tablePrefixs | 空 | 表、视图的前缀,用于生成类名时忽略前缀 |
includeTables | 空 | 默认包含所有表、视图 |
excludeTables | 空 | 排除表,默认不排除 |
new GeneratorConfig(...).columnConfig(columnConfig->{
columnConfig.excludeColumns("create_time","creater_id");
});
属性 | 默认值 | 说明 |
---|---|---|
versionColumn | 空 | 指定乐观锁列名 |
tenantIdColumn | 空 | 指定租户ID列名 |
logicDeleteColumn | 空 | 逻辑删除列名,配置实体类配置:logicDeleteCode 一起使用 |
excludeColumns | 空 | 排除列,默认不排除(在有公共实体类的时候很实用) |
disableUpdateColumns | 空 | 禁止更新的列,这样字段上会生成@TableField(update=false) |
disableSelectColumns | 空 | 禁止Select的列,这样字段上会生成@TableField(select=false) |
defaultValueConvert | 默认实现 | 可动态转换数据库的默认值(由静态值转成动态值) |
new GeneratorConfig(...).entityConfig(entityConfig->{
entityConfig.lombok(true);
});
属性 | 默认值 | 说明 |
---|---|---|
swagger | false | 是否开启swagger |
superClass | NULL | 实体类的父类,例如:com.xx.test.BaseEntity |
lombok | true | 是否开启lombok,这样类上会生成@Data |
schema | false | 注解上是否加上schema信息 |
packageName | DO | 实体类包名 |
nameConvert | NULL | 实体类名转换器,可以自定义规则,默认大驼峰规则 |
fieldNamingStrategy | NamingStrategy.UNDERLINE_TO_CAMEL | 字段名策略,支持 NO_CHANGE ,UNDERLINE_TO_CAMEL |
fieldNameConverter | NULL | 字段名转换器,优先级大于 fieldNamingStrategy |
remarksConverter | NULL | 字段备注转换器,用于实现不一样的备注 |
defaultTableIdCode | NULL | 默认TableId代码,数据库非自增时生效,例如@TableId(...) |
logicDeleteCode | NULL | 默认@LogicDelete代码,数据库非自增时生效,例如@LogicDelete(beforeValue="0",afterValue="1",deleteTimeField="create_time |
typeMapping | 内置包含各种列类型的java映射 | 数据库列类型映射,用于定制 |
new GeneratorConfig(...).mapperConfig(entityConfig->{
mapperConfig.mapperAnnotation(true);
});
属性 | 默认值 | 说明 |
---|---|---|
superClass | 默认继承 MybatisMapper 接口 | Mapper接口的父接口,例如:cn.mybatis.mp.core.mybatis.mapper.MybatisMapper |
mapperAnnotation | true | 是否开启mybatis @Mapper注解,这样类上会生成@Mapper |
packageName | mapper | mapper类的包名 |
suffix | Mapper | mapper类的后缀 |
new GeneratorConfig(...).mapperXmlConfig(mapperXmlConfig->{
mapperXmlConfig.enable(true);
});
属性 | 默认值 | 说明 |
---|---|---|
enable | false | 是否生成mapper xml |
resultMap | true | 是否生成resultMap |
columnList | true | 是否生成列信息,用于select 列 |
packageName | mappers | mapper xml的目录名字 |
suffix | "" | mapper xml文件的后缀 |
new GeneratorConfig(...).daoConfig(daoConfig->{
daoConfig.enable(true);
});
属性 | 默认值 | 说明 |
---|---|---|
enable | false | 是否生成 dao 接口 |
superClass | 默认继承 Dao 接口 | dao接口的父接口,例如:cn.mybatis.mp.core.mvc.Dao |
generic | true | 是否启用泛型,启用后会在superclass后面加泛型>Entity,ID> |
packageName | dao | dao接口的包名 |
suffix | Dao | dao接口的后缀 |
new GeneratorConfig(...).daoImplConfig(daoImplConfig->{
daoImplConfig.enable(true);
});
属性 | 默认值 | 说明 |
---|---|---|
superClass | 默认继承 DaoImpl 实现类 | dao接口的父接口,例如:cn.mybatis.mp.core.mvc.impl.DaoImpl |
generic | true | 是否启用泛型,启用后会在superclass后面加泛型>Entity,ID> |
packageName | dao.impl | dao实现类的包名 |
suffix | DaoImpl | dao实现类的后缀 |
new GeneratorConfig(...).serviceConfig(serviceConfig->{
serviceConfig.enable(true);
});
属性 | 默认值 | 说明 |
---|---|---|
enable | false | 是否生成 Service 接口 |
superClass | 默认继承 Service 接口 | Service接口的父接口,例如:cn.mybatis.mp.core.mvc.Service |
generic | true | 是否启用泛型,启用后会在superclass后面加泛型>Entity,ID> |
packageName | service | Service接口的包名 |
suffix | Service | Service接口的后缀 |
new GeneratorConfig(...).serviceImplConfig(serviceImplConfig->{
serviceImplConfig.injectDao(true);
});
属性 | 默认值 | 说明 |
---|---|---|
injectDao | true | 是否注入dao |
injectMapper | true | 是否注入mapper |
superClass | 默认继承 ServiceImpl 实现类 | dao接口的父接口,例如:cn.mybatis.mp.core.mvc.impl.ServiceImpl |
generic | true | 是否启用泛型,启用后会在superclass后面加泛型>Entity,ID> |
packageName | service.impl | service实现类的包名 |
suffix | ServiceImpl | service实现类的后缀 |
new GeneratorConfig(...).actionConfig(actionConfig->{
actionConfig.enable(true);
});
属性 | 默认值 | 说明 |
---|---|---|
enable | true | 是否生成控制器 |
swagger | true | 是否开启swagger |
injectService | true | 是否注入service |
superClass | NULL | action父类,例如:cn.xxx.BaseAction |
generic | true | 是否启用泛型,启用后会在superclass后面加泛型>Entity,ID> |
packageName | action | action实现类的包名 |
suffix | ServiceImpl | action实现类的后缀 |
returnClass | Object | save update 等返回的类型 |
save | true | 是否生成save方法 |
update | true | 是否生成update方法 |
deleteById | true | 是否生成deleteById方法 |
getById | true | 是否生成getById方法 |
find | true | 是否生成find方法 |
扩展起来,非常方便,不过最好是联系作者,这样可以让更多开发者使用!