Coder Social home page Coder Social logo

mapper's People

Contributors

abel533 avatar dq-deepleaper avatar guozilan avatar joeybling avatar tinysnow avatar ydq avatar zoooooway avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mapper's Issues

Fn.toEntityColumn问题

当Entity字段为aTag这种情况下,会将aTag识别为ATag.
ATag does not mark database column field annotations, unable to obtain column information

Entity:

@Data
@Entity.Table("a_test")
public class TestEntity {
    @Entity.Column(value = "id", id = true, typeHandler = UUIDHandler.class)
    private UUID id;
    @Entity.Column( "a_tag")
    private String aTag;
    @Entity.Column("create_time")
    private LocalDateTime createTime;
}

使用:

var exam = new Example<TestEntity>();
exam.createCriteria().andEqualTo(TestEntity::getATag, "a");
mapper.selectByExample(exam);

@Entity.Column(updatable = false)不更新,但也不能作为where条件

最近使用mybatis-mapper集成shardingsphere,shardingsphere要求分片字段不能更新,将对应字段设置为updatable = false,虽然没有更新对应字段,但是在where后面也没有了该字段,造成更新执行了所有分表,建议updatable = false不要直接忽略字段,可以只处理set后的更新字段。

有springboot的demo吗

我看官方文档上说会提供spring boot 的demo,现在可以提供一个吗,我始终跑不起来呢,谢谢了

建议把常用能力实现上去

建议把常用能力实现上去

1、乐观锁
2、逻辑删除
3、MP的动态查询很有特色,可以参考
4、审计

注解上面,尽量少用自定义的,用通用的,MP最诟病的,就是注解随便定,感觉不规范,但也无能为力,没法扩展调整

是否考虑添加`bom`依赖版本管理

参考Maven坐标(GAV):

<!-- 依赖管理 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.mybatis</groupId>
            <artifactId>mybatis-bom</artifactId>
            <version>Latest Version</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

字段不能设置统一的驼峰转下划线规则

@Data
@Extend.Table("user")
public class User  {
    @Extend.Column(id = true)
    private Long id;
    @Extend.Column
    private String userName;
    @Extend.Column("sex")
    private String sex;
}
mybatis:
  configuration:
    map-underscore-to-camel-case: true

该参数 map-underscore-to-camel-case 不生效

【已解决】字段名关键词bug

PS:使用autoResultMap = true 解决了


旧项目切mapper时发现了一个问题

曾经某个字段是个关键词 【order】结果生成的sql出现问题。

eg:

@Entity.Column(value = "order")
Integer order;

上述的注解查询时会输出SQL 【SELECT order FROM xxx】 order 关键词 导致sql错误,这个可以理解

@Entity.Column(value = "`order`")
Integer order;

上述的注解查询时会输出SQL 【SELECT `order` AS order FROM xxx 】 order 关键词 导致sql错误,个人觉得这个不应该加 AS 才对

升级2.0.0之后,如何排除实体类 继承的父类的 映射

我有一个实体类User,继承的父类BaseVO,例如,User表结构 有字段 A 、B 实体类User有属性A、B 父类BaseVO 有属性C,D,
升级2.0.0之后,会报错说 数据库User表找不到对应的属性C和D。
请问,如何排除 父类的 映射?
以前1.2.2版本 没有问题。

开发规范

为什么实体对象一定要加注解呢? 而且必须是 @Extend.Column 这种的? 就不能兼容jpa的注解吗?

现在的 ExampleWrapper 提供的一系列 带 useCondition 的方法有个小弊端

RT:现在的 ExampleWrapper 提供的一系列 带 useCondition 的方法有个小弊端,期望可以改进一下

先来一段code:

//有空指针风险的 不推荐用法
someMapper.wrapper()
        .eq( 
            dto != null && StringUtils.isNotEmpty(dto.getField()) ,  //condition 为 true 下面的操作才生效
            Entity::getField , 
            dto.getField()   // 如果 dto 可能为空的话  此处是有空指针风险的
        )
        //....

这是当前的 ExampleWrapper 提供的带 condition 的方法,原本是 如果参数不为空,则执行后面的操作
但是这个地方有个问题,当 dto 为空的时候,因为后面的条件直接是立刻求值计算好了将返回值作为参数
所以可能导致最后的 dto.getField() 出现空指针

现在的临时的解决方案

//当前避免空指针操作的方法
someMapper.wrapper()
        .eq( 
            dto != null && StringUtils.isNotEmpty(dto.getField()) ,  // condition 为 true 下面的操作才生效
            Entity::getField , 
            Optional.ofNullable(dto).map(Dto::getField).orElse(null))  //为了防止空指针,只能再判断一次
        )
        //....

如果改成一个 Supplier,使其取值操作变成一个惰性的,而在exampleWrapper中做了condition的判断,那这样就不会产生空指针的异常了,即安全的操作应该是:

//期望直接支持接收 Supplier 作为条件
someMapper.wrapper()
        .eq( 
            dto != null && StringUtils.isNotEmpty(dto.getField()) ,  // condition 为 true 下面的操作才生效
            Entity::getField , 
            () ->  dto.getField()  //使用 Supplier 延迟获取, condition 为 false 的时候不执行,这样就不会空指针也少一次判断
        )
        //....

@abel533 如果接受建议的话,我可以提个PR

遇到一个奇怪的问题,启动项目之后,第一次查询,返回的是null

启动项目之后,第一次查询,会遇到如下问题,再次查询就不会了。好奇怪
单个查询 mapper.selectOne(T) 返回的实体 里面的部分属性 是null
多个查询 mapper.selectList(null) 返回的 集合 List 的size 是20 但是 List 里面全是null
不知道是什么原因,使用版本是 1.0.3
查看打印的SQL是正常的SQL直接去数据库查也是正常的结果

AbstractService#findById报错 Expected one result (or null) to be returned by selectOne(), but found: 3

问题描述

使用AbstractService#findById报错,第一次查询正常根据ID返回了预期的数据。之后每一次调用都报以下错误

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3

而且诡异的是,每调用一次,报错里的but found: 2的数字会递增!也就是说第一次不报错,第二次报2个重复,第三次报3个,第四次是4个。。。。

观察sql日志如下,可以看到实际的查询SQL是没有问题的

2022-07-29 12:06:35.255 DEBUG 45512 --- [ XNIO-1 task-1] c.p.m.g.d.m.D.selectByPrimaryKey : ==> Preparing: SELECT id,corp_id,dept_id,user_id,user_name,device_sn,device_name,card_no,attendance_time,api_code,api_message,api_request_id,api_upload_time,create_time FROM dingtalk_attendance_log WHERE id = ?
2022-07-29 12:06:35.256 DEBUG 45512 --- [ XNIO-1 task-1] c.p.m.g.d.m.D.selectByPrimaryKey : ==> Parameters: 1(Long)
2022-07-29 12:06:35.268 DEBUG 45512 --- [ XNIO-1 task-1] c.p.m.g.d.m.D.selectByPrimaryKey : <== Total: 1

版本

<dependency>
            <groupId>io.mybatis</groupId>
            <artifactId>mybatis-service</artifactId>
            <version>1.2.2</version>
</dependency>
<dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.3</version>
</dependency>

代码

AbstractService#findById

  /**
   * 根据指定的主键查询
   *
   * @param id 主键
   * @return 实体
   */
  @Override
  public T findById(I id) {
    return baseMapper.selectByPrimaryKey(id).orElse(null);
  }

我的代码如下

实体类

@Getter
@Setter
@Entity.Table(value = "dingtalk_attendance_log", remark = "钉钉考勤-打卡记录", autoResultMap = true)
public class DingtalkAttendanceLog extends BaseId {
  private Long id;

  @Entity.Column(value = "corp_id", remark = "企业ID")
  private String corpId;

  @Entity.Column(value = "dept_id", remark = "机构ID")
  private String deptId;

  @Entity.Column(value = "user_id", remark = "使用人ID")
  private String userId;

  // 省略其它代码

}

实体基类

public class BaseId extends BaseEntity {

	/**
	 * 使用BigInt作主键,在插入时需要自己填充键值
	 */
	@Entity.Column(id = true, remark = "主键,bigint类型", updatable = false, insertable = true)
	private Long id;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	/**
	 * 获取新的主键,用于插入时使用
	 */
	public static Long $nextId() {
		return IdWorker.getId();
	}

}

发生错误的业务类

public class DingtalkAttendanceLogService
		extends AbstractIdService<DingtalkAttendanceLog, DingtalkAttendanceLogMapper> {
	/**
	 * 指定记录上传到钉钉
	 */
	public long upload2Dingtalk(List<Long> ids) {
		return ids.stream()
				.map(this::findById)          //////////////////////这一句报错//////////////////////
				.filter(e -> {
					if (e == null) return false;
					return e.getApiCode() != 0 && StringUtils.isNotBlank(e.getUserId());
				})
				.filter(e -> {
					try {
						//省略业务代码
						this.updateSelective(l);
						return true;
					} catch (Exception ignore) {
					}
					return false;
				}).count();
	}
}

具体的报错信息

2022-07-29 12:06:35.251 DEBUG 45512 --- [  XNIO-1 task-1] o.s.web.servlet.DispatcherServlet        : POST "/dingtalk/model/attendanceLog/upload2Dingtalk", parameters={}
2022-07-29 12:06:35.252 DEBUG 45512 --- [  XNIO-1 task-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.pro_iot.tcp_server.model.controller.DingtalkAttendanceLogController#upload2Dingtalk(List)
2022-07-29 12:06:35.254 DEBUG 45512 --- [  XNIO-1 task-1] m.m.a.RequestResponseBodyMethodProcessor : Read "application/json;charset=UTF-8" to [[1]]
2022-07-29 12:06:35.255 DEBUG 45512 --- [  XNIO-1 task-1] c.p.m.g.d.m.D.selectByPrimaryKey         : ==>  Preparing: SELECT id,corp_id,dept_id,user_id,user_name,device_sn,device_name,card_no,attendance_time,api_code,api_message,api_request_id,api_upload_time,create_time FROM dingtalk_attendance_log WHERE id = ?
2022-07-29 12:06:35.256 DEBUG 45512 --- [  XNIO-1 task-1] c.p.m.g.d.m.D.selectByPrimaryKey         : ==> Parameters: 1(Long)
2022-07-29 12:06:35.268 DEBUG 45512 --- [  XNIO-1 task-1] c.p.m.g.d.m.D.selectByPrimaryKey         : <==      Total: 1
2022-07-29 12:06:35.273 DEBUG 45512 --- [  XNIO-1 task-1] .m.m.a.ExceptionHandlerExceptionResolver : Using @ExceptionHandler com.pro_iot.tcp_server.config.DingtalkWebExpConfig#handleDataAccessException(DataAccessException)
2022-07-29 12:06:35.289 DEBUG 45512 --- [  XNIO-1 task-1] com.pro_iot.common.dto.Message           : 接口异常:

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:96) ~[mybatis-spring-2.0.7.jar:2.0.7]
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) ~[mybatis-spring-2.0.7.jar:2.0.7]
	at com.sun.proxy.$Proxy133.selectOne(Unknown Source) ~[na:na]
	at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:160) ~[mybatis-spring-2.0.7.jar:2.0.7]
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:87) ~[mybatis-3.5.9.jar:3.5.9]
	at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145) ~[mybatis-3.5.9.jar:3.5.9]
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86) ~[mybatis-3.5.9.jar:3.5.9]
	at com.sun.proxy.$Proxy136.selectByPrimaryKey(Unknown Source) ~[na:na]
	at io.mybatis.service.AbstractService.findById(AbstractService.java:146) ~[mybatis-service-1.2.2.jar:na]
	at com.pro_iot.tcp_server.model.service.DingtalkAttendanceLogService.lambda$upload2Dingtalk$0(DingtalkAttendanceLogService.java:37) ~[classes/:na]
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[na:1.8.0_91]
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) ~[na:1.8.0_91]
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[na:1.8.0_91]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_91]
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[na:1.8.0_91]
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_91]
	at java.util.stream.LongPipeline.reduce(LongPipeline.java:438) ~[na:1.8.0_91]
	at java.util.stream.LongPipeline.sum(LongPipeline.java:396) ~[na:1.8.0_91]
	at java.util.stream.ReferencePipeline.count(ReferencePipeline.java:526) ~[na:1.8.0_91]
	at com.pro_iot.tcp_server.model.service.DingtalkAttendanceLogService.upload2Dingtalk(DingtalkAttendanceLogService.java:60) ~[classes/:na]
	at com.pro_iot.tcp_server.model.controller.DingtalkAttendanceLogController.upload2Dingtalk(DingtalkAttendanceLogController.java:44) ~[classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_91]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_91]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_91]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.15.jar:5.3.15]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.15.jar:5.3.15]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.15.jar:5.3.15]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.15.jar:5.3.15]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) ~[spring-webmvc-5.3.15.jar:5.3.15]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.15.jar:5.3.15]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.3.15.jar:5.3.15]
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) [spring-webmvc-5.3.15.jar:5.3.15]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:517) [jakarta.servlet-api-4.0.4.jar:4.0.4]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) [spring-webmvc-5.3.15.jar:5.3.15]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:584) [jakarta.servlet-api-4.0.4.jar:4.0.4]
	at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at org.springframework.web.servlet.resource.ResourceUrlEncodingFilter.doFilter(ResourceUrlEncodingFilter.java:67) [spring-webmvc-5.3.15.jar:5.3.15]
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:124) [druid-1.1.20.jar:1.1.20]
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:150) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.15.jar:5.3.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter.doFilterInternal(DefaultLogoutPageGeneratingFilter.java:58) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.15.jar:5.3.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:237) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:223) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:219) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.15.jar:5.3.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.15.jar:5.3.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) [spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) [spring-web-5.3.15.jar:5.3.15]
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) [spring-web-5.3.15.jar:5.3.15]
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) [spring-web-5.3.15.jar:5.3.15]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.15.jar:5.3.15]
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) [spring-web-5.3.15.jar:5.3.15]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.15.jar:5.3.15]
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96) [spring-boot-actuator-2.6.3.jar:2.6.3]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.15.jar:5.3.15]
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) [spring-web-5.3.15.jar:5.3.15]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.15.jar:5.3.15]
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) [undertow-core-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) [undertow-core-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60) [undertow-core-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43) [undertow-core-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) [undertow-core-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) [undertow-core-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.SessionRestoringHandler.handleRequest(SessionRestoringHandler.java:119) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:275) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:79) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:134) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:131) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:255) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:79) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:100) [undertow-servlet-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.server.Connectors.executeRootHandler(Connectors.java:387) [undertow-core-2.2.14.Final.jar:2.2.14.Final]
	at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:852) [undertow-core-2.2.14.Final.jar:2.2.14.Final]
	at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35) [jboss-threads-3.1.0.Final.jar:3.1.0.Final]
	at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2019) [jboss-threads-3.1.0.Final.jar:3.1.0.Final]
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558) [jboss-threads-3.1.0.Final.jar:3.1.0.Final]
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1449) [jboss-threads-3.1.0.Final.jar:3.1.0.Final]
	at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1280) [xnio-api-3.8.4.Final.jar:3.8.4.Final]
	at java.lang.Thread.run(Thread.java:745) [na:1.8.0_91]
Caused by: org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:80) ~[mybatis-3.5.9.jar:3.5.9]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_91]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_91]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_91]
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) ~[mybatis-spring-2.0.7.jar:2.0.7]
	... 141 common frames omitted

怎么感觉我在使用的过程中总是出现各种莫名其妙的问题,是我的使用姿势不对吗?-_-!

orderBy 方法期望能添加支持传入字符串以满足一些变态的业务需求

rt : orderBy 方法期望能添加支持传入字符串,以满足一些变态的业务需求(example/wrapper)

非现有的 example.setOrderByClause,因为 setOrderByClause 会覆盖整个已有的排序

有的时候我们可能需要满足一些“变态”的业务需求:

-- 场景1:mysql 按照指定的字段指定的入参顺序来排序
SELECT * 
FROM table 
WHERE /** some condition **/   
ORDER BY 
    /** other sort **/   
    field(`weight` , 5 , 3 , 1 , 2 , 4),  -- 根据传入的 weight 字段的指定顺序来排序
    /** other sort **/   

-- 场景2:如  要求把身份证号不为空的排前面,相同状态下 status = 2 提到前面,其他的按照其他规则排序
SELECT * 
FROM table 
WHERE /** some  condition **/  
ORDER BY 
    /** other sort **/   
    id_card_no IS NOT NULL DESC, -- 指定字段不为空的在前面
    status = 2 DESC ,     -- 指定值的排在前面
    /** other sort **/   

如果使用 example 的 setOrderByClause 会将前面使用 orderBy 设置的排序条件给统一覆盖掉,遇到这种情况现在的做法就是必须 orderBy 条件全部手写,所以期望添加 支持传入自定义字符串排序的方法

不知道是否有说服力

springboot @EnableScheduling开启定时任务activerecord模式报错

springboot @EnableScheduling开启定时任务activerecord模式第一次报错,错误内容java.lang.RuntimeException: com.cytech.framework.db.entity.BusConsult Mapper interface not found,BusConsultMapper是存在的,第二次执行就好了。
业务代码如下:

@SpringBootApplication
@EnableDiscoveryClient
@MapperScan({"com.xxxx.framework.db.mapper", "com.xxxx.task.dao"})
@EnableFeignClients("com.xxxx.framework.feign")
@EnableScheduling
public class HealthTaskApplication {
    public static void main(String[] args) {
        SpringApplication.run(HealthTaskApplication.class);
    }
}

@Component
public class SystemDealConsultTask{

    @Scheduled(fixedDelay = 5 * 1000)
    public void run() {
        List<BusConsult> busConsultList = new BusConsult()
        .baseMapper().wrapper()
        .eq(BusConsult::getIsDeleted, false)
        .list();
    }
    
}

io.Mapper 代码
初步判断定时任务执行的时候

public void addMapper(Class<?> type, Object mapper) {
  if (type != null && BaseMapper.class.isAssignableFrom(type)) {
    EntityClassFinder.find(type, null).ifPresent(clazz -> {
      if (mapper != null) {
        modelMapper.put(clazz, (BaseMapper<T, I>) mapper);
      }
    });
  }
}

初始化未执行完 。

修改方案

/**
 * 获取实体类对应的 Mapper 接口
 *
 * @param modelClass 实体类
 * @return Mapper 接口
 */
public M baseMapper(Class<T> modelClass) {
  if (modelMapper.containsKey(modelClass)) {
    return (M) modelMapper.get(modelClass);
  }

  this.sqlSessionTemplate.getConfiguration().getMapperRegistry().getMappers().forEach(mapper -> {
    addMapper(mapper, this.sqlSessionTemplate.getMapper(mapper));
  });

  if (modelMapper.containsKey(modelClass)) {
    return (M) modelMapper.get(modelClass);
  }

  throw new RuntimeException(modelClass.getName() + " Mapper interface not found");
}

一个TK老用户的使用体验

一天内我从tk切换到mp,再从mp切换到mybatis-mapper。再说下我的情况,tk我大概使用了4年左右,从开始使用就自己封装了通用Baseservice和BaseServiceImlp。

为什么放弃tk:tk的api命名设计遵循了官方MBG,这点非常不错,使用起来心智负担很低。但对于一些条件查询,又只能使用Example,Example的使用体验极差,也不够优雅,如果表字段出现变更,那真的是灾难,所以尝试换mp,而且mp在批量处理上面占优势(包括对比mybatis-mapper)。

为什么放弃mp:mp在复杂查询的时候,还是非常不错的。但api设计真是灾难,心智负担极高。比如update、insert,默认就是过滤null,如果我需要不过滤null,需要统一设置,这就是天坑(明明可以通过不同方法名降低心智负担)。并不是所有业务都要过滤或者不过滤。而且所有简单查询都要Wrapper包装,有种脱裤子放屁的感觉,你明明知道我要update,你就不能底层Wrapper一下,重载一个方法,让我直接扔entity对象进去?就感觉mp的作者没体验过tk,所以搞出一堆复杂的逻辑出来。曾经一次和一个多年经验的同事聊,感受和我差不多,至少从我和同事的角度而言,是坚决抵制mp的。心智成本太高了!

为什么选择mybatis-mapper:因为tk几乎不更新了,tk查询局限性确实太强了,虽然可以Example,但lambda相比Example真的强上了太多了,而且api命名设计比mp强,但感觉没有tk好。一些想吐槽的地方,mybatis-mapper说明页需要增加很多注解。选型的时候,就会产生门槛,你对我的代码入侵太多了。属于没上船,就走了,体验的机会都没有,大忌。就像某些人对swagger有偏见,他们觉得swagger需要太多注解了(知识储备问题,其实只使用基本注解也能正常工作),感觉这点可以参照swagger。
一个建议啊,其实service层命名可以和mapper一致,降级一些心智负担。mp的槽点就是mapper方法设计+service方法设计都很糟糕+null处理机制(其实可以通过不同方法名规避)。
通用service的初衷是什么?我自己当时的初衷是:OrderService里面注入了UserService,我自然不想再注入UserMapper,为了优雅+偷懒。但如果userService和userMapper方法名不一致,期望和实际劈叉了。同样,我学了mapper的通用方法,我还得学一遍通用service的方法,而且BaseMapper.a和BaseService.b的作用是一样的,就有点尴尬了。

尝试推导:我们真的有必要findOne和selectOne吗?答:为了区分service和mapper。问:用类名区分不更好吗?

主要是感受,言辞可能有不得当的地方。无论是对mapper还是mp,并不是为了贬低,而是为了更好。

睿Rui代码生成器的代码生成问题

1.生成的实体类,字段希望能加上注释,目前字段上只有注解;
如果把实体类放在通用API包中,就需要额外添加注释
2.生成的Mapper类,没有引入实体类,需要额外编辑引入实体类
3.使用model-lombok.java生成的实体类,生成的代码不正确

使用 jpa 模块 insert 失败

引入 jpa 模块后,执行 insert 操作时获取实体类型出错,导致表名错误、字段也没能获取到,最终导致sql错误而无法执行

debug 追了一下,问题出在 JpaEntityClassFinder#isEntityClass方法判断有误

该方法调用了 SimpleTypeUtil#isSimpleType 判断是否为基础类型时

SimpleTypeUtil 中有定义一个静态方法registerPrimitiveTypes 去注册 int 等这些原始类型,但代码中没有去调用这个方法初始化

而 insert、update、delete 方法的返回值为原始类型 int,所以会误将 int 类型作为了 Entity 类型来处理


因为 spi JpaEntityClassFinder 类 获取实体类型 的时候 没有重写 findEntityClass 方法,所以调用的是父类的方法

  public Optional<Class<?>> findEntityClass(Class<?> mapperType, Method mapperMethod) {
    //先判断返回值
    Optional<Class<?>> optionalClass;
    if (mapperMethod != null) {
      optionalClass = getEntityClassByMapperMethodReturnType(mapperType, mapperMethod);
      if (optionalClass.isPresent()) {
        return optionalClass;
      }
      //再判断参数
      optionalClass = getEntityClassByMapperMethodParamTypes(mapperType, mapperMethod);
      if (optionalClass.isPresent()) {
        return optionalClass;
      }
      //最后从接口泛型中获取
      optionalClass = getEntityClassByMapperMethodAndMapperType(mapperType, mapperMethod);
      if (optionalClass.isPresent()) {
        return optionalClass;
      }
    }
    return getEntityClassByMapperType(mapperType);
  }

该方法优先使用 当前调用的 mapper 方法的返回值作为 Entity 类型

而 insert 相关的方法 返回的是受影响的行数,是个 int,所以导致获取的 EntityClass 成了 int

最后在 JpaEntityClassFinder#isEntityClass 中判断是否为实体类型,检查的时候没有匹配 基础原始类型

虽然有在SimpleTypeUtil 类中定义了 registerPrimitiveTypes 方法,但是没有使用

导致 生成的sql错误

只测试了 insert 相关的方法,没测试其他方法,猜测 update / delete 应该也都有问题

Example使用多个orderBy时, SQL生成错误

使用方式:
var exam = new Example();
exam.orderBy(TestEntity::getCreateTime, Example.Order.DESC);
exam.orderBy(TestEntity::getId, Example.Order.DESC);

当使用两个以上的orderBy时, 生成SQL会变成
select ... from ... ORDER BY create_time DESCid DESC
只能使用exam.setOrderByClause("create_time desc, id desc") 替换.
希望能增加多字段(FN)方式排序功能

insert没有回写自动编号

@GeneratedValue(strategy = GenerationType.IDENTITY)
@column(name = "[ID]", insertable = false, updatable = false)
private Integer ID;

当设置这个就可以了 @options(useGeneratedKeys = true, keyProperty = "ID")
这个属于元数据,能不能从Entity里自动解析,不然可能每个Mapper都得改下这个

selectList报错

使用mapper.selectList(null);时报错:
实休使用@table(name = "tbl_xxx")注解
Error invoking SqlProvider method 'public static java.lang.String io.mybatis.mapper.base.EntityProvider.select(org.apache.ibatis.builder.annotation.ProviderContext)' with specify parameter 'null'. Cause: java.lang.RuntimeException: Can't obtain selectList method corresponding entity class

代码生成器不支持字段comments换行

当表字段的注释存在换行的时候,代码生成器生成的Entity会有语法错误。

比如:

  @Entity.Column(value = "type", remark = "数据类型
uint8/uint16/uint32/int8/int16/int32/float32/float64/utf8json")
  private String type;

由于注释里存在换行,结果导致remark换行。

扩展根据id批量删除,第一次删除成功,执行第二次还是第一次的参数,没有替换掉

扩展根据id批量删除,第一次删除成功,执行第二次还是第一次的参数,没有替换掉,扩展方法如下,帮忙看看是哪里有问题

  /**
     * @return 根据id批量删除
     */
    public static String deleteBatchIds(ProviderContext providerContext, List<?> idList) {
        if (idList == null || idList.size() == 0) {
            throw new NullPointerException( "Parameter cannot be empty" );
        }
        return SqlScript.caching( providerContext, new SqlScript() {
            @Override
            public String getSql(EntityTable entity) {
                return "DELETE FROM " + entity.table()
                        + where( () ->
                        entity.idColumns().stream().map( entityColumn -> entityColumn.column() 
                                + " IN (" + idList.stream().map( String::valueOf ).collect( Collectors.joining( "," ) ) + ")" ).collect( Collectors.joining( " AND " ) ) );
            }
        } );
    }

使用jpa注解报错

使用jpa注解报错(针对支持部分)

@Data
@Table(name = "account")
public class Account {
    @Id
    @Column(name = "id")
    private Long id;
    @Column(name = "name")
    private String name;
}

使用selectByPrimaryKey(Long id),报错信息如下:

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method 'public static java.lang.String io.mybatis.mapper.base.EntityProvider.selectByPrimaryKey(org.apache.ibatis.builder.annotation.ProviderContext)' with specify parameter 'class java.lang.Long'.  Cause: java.lang.RuntimeException: Can't obtain selectById method corresponding entity class

版本信息

java17

<dependency>
    <groupId>io.mybatis</groupId>
    <artifactId>mybatis-mapper</artifactId>
    <version>1.0.1</version>
</dependency>

补充信息

使用@Entity.XXX注解可以
通过查看jar未发现io.mybatis.provider.jpa包的相关实现

Example能否支持类似or(...)的and(...)方法?

@ydq QQ群里提的需求,方便加群看看吗?

群号: 277256950

大佬 请问是否支持
2% 9YQB~4O}4QD`SS(Y2YAG

将图中or改为and的写法

4YB%EDM)636OFTRCCZ~D(MO

想要上图效果 使用or
E)Y$AKL{%OHN$9V67%S KQH

sql是
M}BQ27Z4NW_A0)ZA9 N31

我把这里的or 改为and就满足我的需求了
5BUFXZ2V9L$Q YVPMDL7U

个人感觉and的场景应该是多些的 大佬下个版本or 能否加个这样的需求

求教一个问题,deleteByFieldList(T::getId, ids); NPE

问题描述

我有一个基类,里面有一个deleteByIdList方法,希望提供通用的删除操作。

public class BaseId  {
	/**
	 * 使用BigInt作主键,在插入时需要自己填充键值
	 */
	@Entity.Column(id = true, remark = "主键,bigint类型", updatable = false, insertable = true)
	private Long id;
}

public abstract class AbstractIdService<T extends BaseId, M extends BaseMapper<T>>
		extends AbstractService<T, Long, M> {

	/**
	 * 根据ID列表进行删除
	 */
	public int deleteByIdList(List<Long> ids) {
		return deleteByFieldList(T::getId, ids);
	}
}

调用这个方法的时候发生了NPE如下
io.mybatis.provider.EntityFactory

public static EntityTable create(Class<?> entityClass) {
    //处理EntityTable
    EntityTableFactory.Chain entityTableFactoryChain = Instance.getEntityTableFactoryChain();
    //创建 EntityTable,不处理列(字段),此时返回的 EntityTable 已经经过了所有处理链的加工
    EntityTable entityTable = entityTableFactoryChain.createEntityTable(entityClass);
    if (entityTable == null) {
      throw new NullPointerException("Unable to get " + entityClass.getName() + " entity class information");  //这里抛出了异常
    }
    //省略后面的代码
  }

debug,发现entityClass为BaseId。

但是当这么使用时,就一切正常

public class DingtalkDeviceGatewayService
		extends AbstractIdService<DingtalkDeviceGateway, DingtalkDeviceGatewayMapper> {
}

gatewayService.deleteByFieldList(DingtalkDeviceGateway::getId, ids)

请教

我不确定这是bug还是我使用不当,所以想问一下
deleteByFieldList(T::getId, ids);这种使用方法是否正确。

为更好的支持 [OR] 条件 SQL 的组装,Example.Criteria 能否添加个 clone 方法?

作者您好,我单纯从使用者的角度来提个功能上的需求

当前版本以及之前的所有的通用Mapper,基本上很难支持很自由的 or,只能将 or 作为最顶层的条件来处理,导致 or 的使用频率不会那么的高,相同字段不同值的 or 我们可以直接用 innot in 来代替,不同字段的 or 条件,如果也比较简单,且我们不想写 SQL 脚本的情况下,我们只能通过改写 SQL 来实现

于是乎出现了下面的情况:

-- 伪代码
SELECT * FROM table WHERE col_1 = 1 AND col_2 = 2 AND col_3 = 3 AND (col_4 = 4  OR col_5 = 5)

-- 上面的SQL 用Example 的方式来做的时候 只能变通成为
SELECT * FROM table WHERE (col_1 = 1 AND col_2 = 2 AND col_3 = 3 AND col_4 = 4) 
          OR (col_1 = 1 AND col_2 = 2 AND col_3 = 3 AND col_5 = 5)

当前版本在 Examle 中 只能 先创建一个 Example.Criteria 拼接好第一组条件,然后通过 example.or() 再创建一个 Example.Criteria 再去拼另外一组条件,由于当前的 Example.Criteria 是个内部密封的类,不太方便直接深度 Copy 复用,所以会很多重复性的代码

所以从易用性上考虑的话,提个功能上的需求,能否直接在底层支持 clone 或者 copy 一个带有当前相同条件的 Example.Criteria 出来呢?

//伪代码 现有的实现方案
Example<Foo> example =example();
example.createCriteria()
        .andEqualTo(Foo::getCol1,1)
        .andEqualTo(Foo::getCol2,2)
        .andEqualTo(Foo::getCol3,3)
        .andEqualTo(Foo::getCol4,4);

example.or()
        .andEqualTo(Foo::getCol1,1)
        .andEqualTo(Foo::getCol2,2)
        .andEqualTo(Foo::getCol3,3) //前几步的操作是重复的,如果通用条件很多甚至有动态判断代码就很显冗余
        .andEqualTo(Foo::getCol5,5);

期望变成如下样子

Example<Foo> example =example();
Example.Criteria<Foo> criteria1 = example.createCriteria()
        .andEqualTo(Foo::getCol1,1)
        .andEqualTo(Foo::getCol2,2)
        .andEqualTo(Foo::getCol3,3);

// 下面是伪代码举例① 
Example.Criteria<Foo> criteria2 = criteria1.or();//  或者叫 criteria1.clone();  criteria1.copy();
example.or(criteria2);

//下面是伪代码举例②,和 example.or() 一样,拷贝完了自动添加到 oredCriteria 中
Example.Criteria<Foo> criteria2 = example.cloneCriteria(criteria1);

criteria1.andEqualTo(Foo::getCol4,4);
criteria2.andEqualTo(Foo::getCol5,5);

当然,如果不考虑深层次的嵌套的情况下,能在 Example.Criteria 层面直接支持单层级的 or 条件组合就不用那么复杂了。

多租户

请问有没有考虑多租户的实现

批量插入

未找到批量插入接口activerecord 模式下能否加批量插入接口

springboot 2.6.1 报错循环引用,不知道是不是哪里配置不对?

2021-12-12 16:53:45 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - [report,40] -


APPLICATION FAILED TO START


Description:

The dependencies of some of the beans in the application context form a cycle:

┌──->──┐
| io.mybatis.activerecord.spring.boot.autoconfigure.MapperProviderAutoConfiguration
└──<-──┘

Action:

Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.

字段为泛型时typeHandler报错

字段注解如下 :

@Entity.Column(typeHandler = ListStringToStringTypeHandler.class)
private List<String> deptList;

会报以下错误:

class io.mybatis.provider.defaults.GenericTypeResolver$ParameterizedTypeImpl cannot be cast to class java.lang.Class (io.mybatis.provider.defaults.GenericTypeResolver$ParameterizedTypeImpl is in unnamed module of loader 'app'; java.lang.Class is in module java.base of loader 'bootstrap')

另,必须使用 @Entity.Table(value = "tableName", autoResultMap = true)才执行typeHandler, 能否默认就支持。
即仅使用 @Entity.Table(value = "tableName") 或者 @Table(name = "tableName")

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.