SpringBoot整合mybatis通用Mapper+自定義通用Mapper方法解析
最近公司在用的通用mapper,自己感興趣,然后就來搭建了一個springboot項目試驗通用mapper
這個項目是國內(nèi)的大神寫的一個mybatis插件,里面有很多的增刪改查方法
官方解釋的是通用mapper支持3.2.4以及以上的版本
首先引入pom
<!--Mybatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator</artifactId> <version>1.3.5</version> <type>pom</type> </dependency> <!--分頁插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.2.1</version> </dependency> <!--tkmybatis --> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>1.1.4</version> </dependency>
通用Mapper是tk.mybais中的
配置文件application.yml:
server:
port: 8081
# 下面是配置undertow作為服務(wù)器的參數(shù)
undertow:
# 設(shè)置IO線程數(shù), 它主要執(zhí)行非阻塞的任務(wù),它們會負責多個連接, 默認設(shè)置每個CPU核心一個線程
io-threads: 4
# 阻塞任務(wù)線程池, 當執(zhí)行類似servlet請求阻塞操作, undertow會從這個線程池中取得線程,它的值設(shè)置取決于系統(tǒng)的負載
worker-threads: 20
# 以下的配置會影響buffer,這些buffer會用于服務(wù)器連接的IO操作,有點類似netty的池化內(nèi)存管理
# 每塊buffer的空間大小,越小的空間被利用越充分
buffer-size: 1024
# 是否分配的直接內(nèi)存
direct-buffers: true
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
driver-class-name: com.mysql.jdbc.Driver
platform: mysql
url: jdbc:mysql://xxx.xxx.xxx.xxx:5306/miniprogram?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
username: xxxxx
password: xxxxx
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT1FROMDUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
filters: stat,wall
logSlowSql: true
redis:
database: 1
host: xxxxx
port: xxxx
password: xxxx
timeout: 10000
activemq:
queueName: mvp.queue
topicName: mvp.topic
#賬號密碼
user: user
password: user
#URL of the ActiveMQ broker.
broker-url: tcp://localhost:61616
in-memory: false
#必須使用連接池
pool:
#啟用連接池
enabled: true
#連接池最大連接數(shù)
max-connections: 5
#空閑的連接過期時間,默認為30秒
idle-timeout: 30s
# jedis: 有默認值,源碼:RedisProperties
# pool:
# max-active:
# max-idle:
# max-wait:
# min-idle:
mybatis:
typeAliasesPackage: com.pinyu.miniprogram.mysql.entity
mapper-locations: classpath:mapper/**/*Mapper.xml
mapper:
mappers: com.pinyu.miniprogram.mysql.mappers.BaseMapper
identity: mysql
#logging.config:
# classpath: test/log4j2_test.xmlxxxx請配置自己的數(shù)據(jù)庫相關(guān)信息
mapper: ? mappers: com.pinyu.miniprogram.mysql.mappers.BaseMapper ? identity: mysql
ctrl+鼠標點擊com.pinyu.miniprogram.mysql.mappers.BaseMapper 進入源碼可以看到 MapperProperties類

是一個集合,意思這里可以mappers配置多個通用Mapper,可以是直接繼承它已有的通用Mapper,也可以是定義自己需要的通用Mapper,自定義通用Mapper(代替它的Mapper)繼承實現(xiàn)的方式不一樣,下面會講到
也可以用代碼進行配置
/**
* 通用mapper與分頁插件的一些配置
*/
@Configuration
public class MyBatisMapperScannerConfig {
/**
* 使用通用Mapper之前需要初始化的一些信息
* 使用通用Mapper插件時請勿使用熱加載,否則報錯,插件作者后續(xù)應(yīng)該會修復(fù)
*/
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
mapperScannerConfigurer.setBasePackage("com.xx.xx.xx.mapper");//普通mapper的位置
Properties properties = new Properties();
properties.setProperty("mappers", BaseMapper.class.getName());//通用mapper的全名
properties.setProperty("notEmpty", "false");
properties.setProperty("IDENTITY", "MYSQL");//配置數(shù)據(jù)庫方言
mapperScannerConfigurer.setProperties(properties);
return mapperScannerConfigurer;
}
/**
* 配置mybatis的分頁插件pageHelper
*/
@Bean
public PageHelper pageHelper(){
PageHelper pageHelper = new PageHelper();
Properties properties = new Properties();
//設(shè)置為true時,會將RowBounds第一個參數(shù)offset當成pageNum頁碼使用
properties.setProperty("offsetAsPageNum","true");
//置為true時,使用RowBounds分頁會進行count查詢
properties.setProperty("rowBoundsWithCount","true");
//合理化查詢,啟用合理化時,
//如果pageNum<1會查詢第一頁,如果pageNum>pages會查詢最后一頁
//未開啟時如果pageNum<1或pageNum>pages會返回空數(shù)據(jù)
properties.setProperty("reasonable","true");
//配置mysql數(shù)據(jù)庫的方言
properties.setProperty("dialect","mysql");
pageHelper.setProperties(properties);
return pageHelper;
}
}mappers對應(yīng)的通用mapper類,不要和自己其他業(yè)務(wù)的mapper放在一起,不要被@MapperScan掃描到,不然會報錯,因為繼承了通用mapper,會有很多相應(yīng)的方法,被掃描到以后,mybatis發(fā)現(xiàn)沒有一個xml配置文件或者相應(yīng)方法沒有進行實現(xiàn),這時候就會報錯。但是繼承自己的BaseMapper相關(guān)mapper肯定是要被掃描到的
數(shù)據(jù)庫創(chuàng)建一張表member以及相關(guān)字段
/*
Navicat MySQL Data Transfer
Source Server : 120.79.81.103-5306-master
Source Server Version : 50719
Source Host : 120.79.81.103:5306
Source Database : miniprogram
Target Server Type : MYSQL
Target Server Version : 50719
File Encoding : 65001
Date: 2019-04-03 23:09:51
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for member
-- ----------------------------
DROP TABLE IF EXISTS `member`;
CREATE TABLE `member` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`member_name` varchar(255) NOT NULL COMMENT '會員用戶名',
`tel` varchar(255) DEFAULT NULL COMMENT '電話',
`nick_name` varchar(255) NOT NULL COMMENT '昵稱',
`head_img` varchar(255) DEFAULT NULL COMMENT '頭像地址',
`status` int(1) NOT NULL COMMENT '狀態(tài) 1啟用 2禁用',
`create_date` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間',
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間',
`pwd` varchar(255) NOT NULL COMMENT '密碼',
`signature` varchar(255) DEFAULT NULL COMMENT '個性簽名',
`creat_id` bigint(20) DEFAULT NULL,
`delete_state` int(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of member
-- ----------------------------
INSERT INTO `member` VALUES ('1', 'dsada', '15928878433', 'dasdas', null, '1', '2019-03-11 18:47:53', '2019-03-11 18:47:53', '123456', null, null, '1');
INSERT INTO `member` VALUES ('2', 'ypp', '15928878888', '6666', null, '1', '2019-03-11 19:35:39', null, 'EDGM@MAMABDACFDLLG', null, null, '1');創(chuàng)建實體MemberEntity,一般創(chuàng)建實體我都會抽一些相同的字段出來
MemberEntity:
package com.pinyu.miniprogram.mysql.entity.member;
import javax.persistence.Table;
import com.pinyu.miniprogram.mysql.entity.BaseEntity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data // getter、setter
@AllArgsConstructor // 全參構(gòu)造方法
@NoArgsConstructor // 無參構(gòu)造方法
@Accessors(chain = true) // 鏈式編程寫法
@Table(name="member")
public class MemberEntity extends BaseEntity {
/**
*
*/
private static final long serialVersionUID = -2601234073734313278L;
private String memberName;// 會員登錄用戶名
private String nickName;// 昵稱
private String tel;// 電話
private String pwd;// 密碼
private String headImg;// 頭像圖片
private String signature;// 個性簽名
private Integer status;//狀態(tài) 1禁用 2啟用
}BaseEntity:
package com.pinyu.miniprogram.mysql.entity;
import java.util.Date;
import javax.persistence.Column;
import com.pinyu.miniprogram.mysql.entity.member.MemberEntity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* @author ypp
* @Description: TODO(用一句話描述該文件做什么)
*/
@Data // getter、setter
@AllArgsConstructor // 全參構(gòu)造方法
@NoArgsConstructor // 無參構(gòu)造方法
@Accessors(chain = true) // 鏈式編程寫法
public class BaseEntity extends IdEntity {
/**
*
*/
private static final long serialVersionUID = 8575696766261326260L;
@Column(name="creat_id")
private Integer creatId;
@Column(name="create_date")
private Date createDate;
@Column(name="delete_state")
private Integer deleteState;// 刪除狀態(tài) 1正常 2已刪除
}IdEntity:
package com.pinyu.miniprogram.mysql.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import com.pinyu.miniprogram.mysql.entity.member.MemberEntity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* @author ypp
* @Description: TODO(用一句話描述該文件做什么)
*/
@Data // getter、setter
@AllArgsConstructor // 全參構(gòu)造方法
@NoArgsConstructor // 無參構(gòu)造方法
@Accessors(chain = true) // 鏈式編程寫法
public class IdEntity implements Serializable {
/**
*
*/
private static final long serialVersionUID = -9089706482760436909L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}@Table:對應(yīng)數(shù)據(jù)庫的表,如果不寫默認是類名首字母小寫作為表名,比Member,不寫數(shù)據(jù)庫表默認指向member@Column:的屬性name對應(yīng)數(shù)據(jù)庫表的字段,如果不寫默認是駝峰下劃線匹配,比如private Long myId,如果不寫得話,就是對應(yīng)數(shù)據(jù)庫表字段my_id@Id:把當前字段作為數(shù)據(jù)庫主鍵使用,匹配數(shù)據(jù)庫主鍵。如果不貼此注解,在某些查詢語句的時候會把表字段一起作為聯(lián)合主鍵查詢@GeneratedValue:讓通用mapper在執(zhí)行insert操作之后將自動生成的主鍵值回寫到當前實體對象對應(yīng)的屬性當中
新建一個通用Mapper繼承Mapper、MySqlMapper
點擊進去看
package com.pinyu.miniprogram.mysql.mappers;
import com.pinyu.miniprogram.mysql.entity.BaseEntity;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;
/**
* @author ypp
* 創(chuàng)建時間:2018年12月27日 下午1:29:03
* @Description: TODO(用一句話描述該文件做什么)
*/
public interface BaseMapper<T extends BaseEntity> extends Mapper<T>,MySqlMapper<T>{
}BaseMapper是我自己定義的通用Mapper,注意在被繼承Mapper上面也有BaseMapper,注意區(qū)分,我這里名字取一樣了而已。
被Mapper繼承的BaseMapper里面有還有很多增刪改查的方法

這是源碼
看了下,里面有大概20個左右方法,都是比較基礎(chǔ)的增刪改查

測試:



MemberMapper并沒有selectAll方法,沿用的繼承的selectAll方法
比較詳細的一個入門示例
希望能幫助到用到的小伙伴

自定義通用Mapper,也有可能在實際工作中通用Mapper并不能滿足工作,需要額外的一些通用方法,但是這種的情況很少,通用Mapper提供的方法基本都能滿足單表操作需求了
舉例我要寫一個通用的單表分頁
1、自己定義的通用Mapper必須包含泛型,例如MysqlMapper<T>。這一點在這里可以忽略,這里并沒有自定義自己的通用Mapper,而是使用了它自帶的通用Mapper,我們繼承的它
2、自定義的通用Mapper接口中的方法需要有合適的注解。具體可以參考Mapper
3、需要繼承MapperTemplate來實現(xiàn)具體的操作方法。必須要新建一個類繼承MapperTemplate,必須繼承MapperTemplate,必須繼承MapperTemplate
4、通用Mapper中的Provider一類的注解只能使用相同的type類型(這個類型就是第三個要實現(xiàn)的類。)。實際上method也都寫的一樣。
在自己的BaseMapper寫一個方法
改造后的BaseMapper
package com.pinyu.miniprogram.mysql.mappers;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.SelectProvider;
import com.pinyu.miniprogram.mysql.entity.BaseEntity;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;
/**
* @author ypp 創(chuàng)建時間:2018年12月27日 下午1:29:03
* @Description: TODO(用一句話描述該文件做什么)
*/
public interface BaseMapper<T extends BaseEntity> extends Mapper<T>, MySqlMapper<T> {
/**
* * 單表分頁查詢 * * @param object * @param offset * @param limit * @return
*/
@SelectProvider(type = BaseMapperProvider.class, method = "dynamicSQL")
List selectPage(@Param("entity") T object, @Param("offset") int offset, @Param("limit") int limit);
}返回結(jié)果為List,入?yún)⒎謩e為查詢條件和分頁參數(shù)。在Mapper的接口方法中,當有多個入?yún)⒌臅r候建議增加@Param注解,否則就得用param1,param2...來引用參數(shù)。
同時必須在方法上添加注解。查詢使用SelectProvider,插入使用@InsertProvider,更新使用UpdateProvider,刪除使用DeleteProvider。不同的Provider就相當于xml中不同的節(jié)點,如<select>,<insert>,<update>,<delete>。
因為這里是查詢,所以要設(shè)置為SelectProvider,這4個Provider中的參數(shù)都一樣,只有type和method。
type必須設(shè)置為實際執(zhí)行方法的BaseMapperProvider.class(此類在下面),method必須設(shè)置為"dynamicSQL"。
通用Mapper處理的時候會根據(jù)type反射BaseMapperProvider查找方法,而Mybatis的處理機制要求method必須是type類中只有一個入?yún)?,且返回值為String的方法。"dynamicSQL"方法定義在MapperTemplate中,該方法如下:
public String dynamicSQL(Object record) {
? ? return "dynamicSQL";
}新建的BaseMapperProvider
上面第三點說到了需要一個類繼承MapperTemplate,這是必須的。繼承了它然后再進行相應(yīng)的實現(xiàn),方法名請和Mapper接口中的方法名一致
package com.pinyu.miniprogram.mysql.mappers;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.scripting.xmltags.IfSqlNode;
import org.apache.ibatis.scripting.xmltags.MixedSqlNode;
import org.apache.ibatis.scripting.xmltags.SqlNode;
import org.apache.ibatis.scripting.xmltags.StaticTextSqlNode;
import org.apache.ibatis.scripting.xmltags.WhereSqlNode;
import tk.mybatis.mapper.entity.EntityColumn;
import tk.mybatis.mapper.mapperhelper.EntityHelper;
import tk.mybatis.mapper.mapperhelper.MapperHelper;
import tk.mybatis.mapper.mapperhelper.MapperTemplate;
public class BaseMapperProvider extends MapperTemplate {
public BaseMapperProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
super(mapperClass, mapperHelper);
}
public SqlNode selectPage(MappedStatement ms) {
Class<?> entityClass = getEntityClass(ms);
// 修改返回值類型為實體類型
setResultType(ms, entityClass);
List<SqlNode> sqlNodes = new ArrayList<SqlNode>();
// 靜態(tài)的sql部分:select column ... from table
sqlNodes.add(new StaticTextSqlNode(
"SELECT " + EntityHelper.getSelectColumns(entityClass) + " FROM " + tableName(entityClass)));
// 獲取全部列
Set<EntityColumn> columns = EntityHelper.getColumns(entityClass);
List<SqlNode> ifNodes = new ArrayList<SqlNode>();
boolean first = true;
// 對所有列循環(huán),生成<if test="property!=null">[AND] column = #{property}</if>
for (EntityColumn column : columns) {
StaticTextSqlNode columnNode = new StaticTextSqlNode(
(first ? "" : " AND ") + column.getColumn() + " = #{entity." + column.getProperty() + "} ");
if (column.getJavaType().equals(String.class)) {
ifNodes.add(new IfSqlNode(columnNode, "entity." + column.getProperty() + " != null and " + "entity."
+ column.getProperty() + " != '' "));
} else {
ifNodes.add(new IfSqlNode(columnNode, "entity." + column.getProperty() + " != null "));
}
first = false;
}
// 將if添加到<where>
sqlNodes.add(new WhereSqlNode(ms.getConfiguration(), new MixedSqlNode(ifNodes)));
// 處理分頁
sqlNodes.add(new IfSqlNode(new StaticTextSqlNode(" LIMIT #{limit}"), "offset==0"));
sqlNodes.add(new IfSqlNode(new StaticTextSqlNode(" LIMIT #{limit} OFFSET #{offset} "), "offset>0"));
return new MixedSqlNode(sqlNodes);
}
}在這里有一點要求,那就是BaseMapperProvider處理BaseMapper<T>中的方法時,方法名必須一樣,因為這里需要通過反射來獲取對應(yīng)的方法,方法名一致一方面是為了減少開發(fā)人員的配置,另一方面和接口對應(yīng)看起來更清晰。
除了方法名必須一樣外,入?yún)⒈仨毷荕appedStatement ms,除此之外返回值可以是void或者SqlNode之一。
這里先講一下通用Mapper的實現(xiàn)原理。通用Mapper目前是通過攔截器在通用方法第一次執(zhí)行的時候去修改MappedStatement對象的SqlSource屬性。而且只會執(zhí)行一次,以后就和正常的方法沒有任何區(qū)別。
使用Provider注解的這個Mapper方法,Mybatis本身會處理成ProviderSqlSource(一個SqlSource的實現(xiàn)類),由于之前的配置,這個ProviderSqlSource種的SQL是上面代碼中返回的"dynamicSQL"。這個SQL沒有任何作用,如果不做任何修改,執(zhí)行這個代碼肯定會出錯。所以在攔截器中攔截符合要求的接口方法,遇到ProviderSqlSource就通過反射調(diào)用如BaseMapperProvider中的具體代碼去修改原有的SqlSource。
最簡單的處理Mybatis SQL的方法是什么?就是創(chuàng)建SqlNode,使用DynamicSqlSource,這種情況下我們不需要處理入?yún)?,不需要處理代碼中的各種類型的參數(shù)映射。比執(zhí)行SQL的方式容易很多。
有關(guān)這部分的內(nèi)容建議查看通用Mapper的源碼和Mybatis源碼了解,如果不了解在這兒說多了反而會亂。
對上訴實現(xiàn)代碼的描述
首先獲取了實體類型,然后通過setResultType將返回值類型改為entityClass,就相當于resultType=entityClass。
這里為什么要修改呢?因為默認返回值是T,Java并不會自動處理成我們的實體類,默認情況下是Object,對于所有的查詢來說,我們都需要手動設(shè)置返回值類型。
對于insert,update,delete來說,這些操作的返回值都是int,所以不需要修改返回結(jié)果類型。
之后從List<SqlNode> sqlNodes = new ArrayList<SqlNode>();代碼開始拼寫SQL,首先是SELECT查詢頭,在EntityHelper.getSelectColumns(entityClass)中還處理了別名的情況。
然后獲取所有的列,對列循環(huán)創(chuàng)建<if entity.property!=null>column = #{entity.property}</if>節(jié)點。最后把這些if節(jié)點組成的List放到一個<where>節(jié)點中。
這一段使用屬性時用的是 entity. + 屬性名,entity來自哪兒?來自我們前面接口定義處的Param("entity")注解,后面的兩個分頁參數(shù)也是。如果你用過Mybatis,相信你能明白。
之后在<where>節(jié)點后添加分頁參數(shù),當offset==0時和offset>0時的分頁代碼不同。
最后封裝成一個MixedSqlNode返回。
返回后通用Mapper是怎么處理的
這里貼下源碼:
SqlNode sqlNode = (SqlNode) method.invoke(this, ms); DynamicSqlSource dynamicSqlSource = new DynamicSqlSource(ms.getConfiguration(), sqlNode); setSqlSource(ms, dynamicSqlSource);
返回SqlNode后創(chuàng)建了DynamicSqlSource,然后修改了ms原來的SqlSource。
測試:


這里分頁參數(shù)就隨便用了RESTFUL風格隨便寫了下


數(shù)據(jù)庫只有2條數(shù)據(jù)。測試成功
其實有了Mybatis自動生成插件,通用Mapper優(yōu)勢并不是太突出。
非SpringBoot項目的話,原理都是一樣的,只是某些類需要.xml配置文件進行配置和注入
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java INPUTSTREAM如何實現(xiàn)重復(fù)使用
這篇文章主要介紹了Java INPUTSTREAM如何實現(xiàn)重復(fù)使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-10-10
Java Swing組件實現(xiàn)進度監(jiān)視功能示例
這篇文章主要介紹了Java Swing組件實現(xiàn)進度監(jiān)視功能,結(jié)合完整實例形式詳細分析了Java基于Swing組件實現(xiàn)進度條顯示功能的具體操作技巧與相關(guān)注意事項,需要的朋友可以參考下2018-02-02
IKAnalyzer結(jié)合Lucene實現(xiàn)中文分詞(示例講解)
下面小編就為大家?guī)硪黄狪KAnalyzer結(jié)合Lucene實現(xiàn)中文分詞(示例講解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10
Spring Cloud服務(wù)入口Gateway的介紹和使用問題小結(jié)
Spring Cloud Gateway是Spring Cloud的?個全新的API?關(guān)項?, 基于Spring + SpringBoot等技術(shù)開發(fā), ?的是為了替換掉Zuul,這篇文章主要介紹了Spring Cloud服務(wù)入口Gateway的介紹和使用問題小結(jié),需要的朋友可以參考下2025-03-03
Java中對list map根據(jù)map某個key值進行排序的方法
今天小編就為大家分享一篇Java中對list map根據(jù)map某個key值進行排序的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07
使用Spring Data Jpa的CriteriaQuery一個陷阱
使用Spring Data Jpa的CriteriaQuery進行動態(tài)條件查詢時,可能會遇到一個陷阱,當條件為空時,查詢不到任何結(jié)果,并不是期望的返回所有結(jié)果。這是為什么呢?2020-11-11

