SpringBoot整合mybatis通用Mapper+自定義通用Mapper方法解析
最近公司在用的通用mapper,自己感興趣,然后就來(lái)搭建了一個(gè)springboot項(xiàng)目試驗(yàn)通用mapper
這個(gè)項(xiàng)目是國(guó)內(nèi)的大神寫的一個(gè)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> <!--分頁(yè)插件 --> <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ù),它們會(huì)負(fù)責(zé)多個(gè)連接, 默認(rèn)設(shè)置每個(gè)CPU核心一個(gè)線程
io-threads: 4
# 阻塞任務(wù)線程池, 當(dāng)執(zhí)行類似servlet請(qǐng)求阻塞操作, undertow會(huì)從這個(gè)線程池中取得線程,它的值設(shè)置取決于系統(tǒng)的負(fù)載
worker-threads: 20
# 以下的配置會(huì)影響buffer,這些buffer會(huì)用于服務(wù)器連接的IO操作,有點(diǎn)類似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
#賬號(hào)密碼
user: user
password: user
#URL of the ActiveMQ broker.
broker-url: tcp://localhost:61616
in-memory: false
#必須使用連接池
pool:
#啟用連接池
enabled: true
#連接池最大連接數(shù)
max-connections: 5
#空閑的連接過(guò)期時(shí)間,默認(rèn)為30秒
idle-timeout: 30s
# jedis: 有默認(rèn)值,源碼: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請(qǐng)配置自己的數(shù)據(jù)庫(kù)相關(guān)信息
mapper: ? mappers: com.pinyu.miniprogram.mysql.mappers.BaseMapper ? identity: mysql
ctrl+鼠標(biāo)點(diǎn)擊com.pinyu.miniprogram.mysql.mappers.BaseMapper 進(jìn)入源碼可以看到 MapperProperties類

是一個(gè)集合,意思這里可以mappers配置多個(gè)通用Mapper,可以是直接繼承它已有的通用Mapper,也可以是定義自己需要的通用Mapper,自定義通用Mapper(代替它的Mapper)繼承實(shí)現(xiàn)的方式不一樣,下面會(huì)講到
也可以用代碼進(jìn)行配置
/**
* 通用mapper與分頁(yè)插件的一些配置
*/
@Configuration
public class MyBatisMapperScannerConfig {
/**
* 使用通用Mapper之前需要初始化的一些信息
* 使用通用Mapper插件時(shí)請(qǐng)勿使用熱加載,否則報(bào)錯(cuò),插件作者后續(xù)應(yīng)該會(huì)修復(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ù)庫(kù)方言
mapperScannerConfigurer.setProperties(properties);
return mapperScannerConfigurer;
}
/**
* 配置mybatis的分頁(yè)插件pageHelper
*/
@Bean
public PageHelper pageHelper(){
PageHelper pageHelper = new PageHelper();
Properties properties = new Properties();
//設(shè)置為true時(shí),會(huì)將RowBounds第一個(gè)參數(shù)offset當(dāng)成pageNum頁(yè)碼使用
properties.setProperty("offsetAsPageNum","true");
//置為true時(shí),使用RowBounds分頁(yè)會(huì)進(jìn)行count查詢
properties.setProperty("rowBoundsWithCount","true");
//合理化查詢,啟用合理化時(shí),
//如果pageNum<1會(huì)查詢第一頁(yè),如果pageNum>pages會(huì)查詢最后一頁(yè)
//未開啟時(shí)如果pageNum<1或pageNum>pages會(huì)返回空數(shù)據(jù)
properties.setProperty("reasonable","true");
//配置mysql數(shù)據(jù)庫(kù)的方言
properties.setProperty("dialect","mysql");
pageHelper.setProperties(properties);
return pageHelper;
}
}mappers對(duì)應(yīng)的通用mapper類,不要和自己其他業(yè)務(wù)的mapper放在一起,不要被@MapperScan掃描到,不然會(huì)報(bào)錯(cuò),因?yàn)槔^承了通用mapper,會(huì)有很多相應(yīng)的方法,被掃描到以后,mybatis發(fā)現(xiàn)沒(méi)有一個(gè)xml配置文件或者相應(yīng)方法沒(méi)有進(jìn)行實(shí)現(xiàn),這時(shí)候就會(huì)報(bào)錯(cuò)。但是繼承自己的BaseMapper相關(guān)mapper肯定是要被掃描到的
數(shù)據(jù)庫(kù)創(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 '會(huì)員用戶名',
`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)建時(shí)間',
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時(shí)間',
`pwd` varchar(255) NOT NULL COMMENT '密碼',
`signature` varchar(255) DEFAULT NULL COMMENT '個(gè)性簽名',
`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)建實(shí)體MemberEntity,一般創(chuàng)建實(shí)體我都會(huì)抽一些相同的字段出來(lái)
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 // 無(wú)參構(gòu)造方法
@Accessors(chain = true) // 鏈?zhǔn)骄幊虒懛?
@Table(name="member")
public class MemberEntity extends BaseEntity {
/**
*
*/
private static final long serialVersionUID = -2601234073734313278L;
private String memberName;// 會(huì)員登錄用戶名
private String nickName;// 昵稱
private String tel;// 電話
private String pwd;// 密碼
private String headImg;// 頭像圖片
private String signature;// 個(gè)性簽名
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 // 無(wú)參構(gòu)造方法
@Accessors(chain = true) // 鏈?zhǔn)骄幊虒懛?
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 // 無(wú)參構(gòu)造方法
@Accessors(chain = true) // 鏈?zhǔn)骄幊虒懛?
public class IdEntity implements Serializable {
/**
*
*/
private static final long serialVersionUID = -9089706482760436909L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}@Table:對(duì)應(yīng)數(shù)據(jù)庫(kù)的表,如果不寫默認(rèn)是類名首字母小寫作為表名,比Member,不寫數(shù)據(jù)庫(kù)表默認(rèn)指向member@Column:的屬性name對(duì)應(yīng)數(shù)據(jù)庫(kù)表的字段,如果不寫默認(rèn)是駝峰下劃線匹配,比如private Long myId,如果不寫得話,就是對(duì)應(yīng)數(shù)據(jù)庫(kù)表字段my_id@Id:把當(dāng)前字段作為數(shù)據(jù)庫(kù)主鍵使用,匹配數(shù)據(jù)庫(kù)主鍵。如果不貼此注解,在某些查詢語(yǔ)句的時(shí)候會(huì)把表字段一起作為聯(lián)合主鍵查詢@GeneratedValue:讓通用mapper在執(zhí)行insert操作之后將自動(dòng)生成的主鍵值回寫到當(dāng)前實(shí)體對(duì)象對(duì)應(yīng)的屬性當(dāng)中
新建一個(gè)通用Mapper繼承Mapper、MySqlMapper
點(diǎn)擊進(jìn)去看
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)建時(shí)間: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個(gè)左右方法,都是比較基礎(chǔ)的增刪改查

測(cè)試:



MemberMapper并沒(méi)有selectAll方法,沿用的繼承的selectAll方法
比較詳細(xì)的一個(gè)入門示例
希望能幫助到用到的小伙伴

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


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


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

