基于 MyBatis 手撸一个分表插件

da2a1b91e5207b4efe3486e49967802a.png

背景

事情是酱紫的,上级leader负责记录信息的业务,每日预估数据量是15万左右,所以引入sharding-jdbc做分表。

上级leader完成业务的开发后,走了一波自测,git push后,就忙其他的事情去了。

项目的框架是SpringBoot+Mybaits

出问题了

因为负责的业务也开发完了,熟练的git pull,准备自测,单元测试run一下,上个厕所回来收工,就是这么自信。

0433307bda1e6240926256ae25ff6a83.gif

回来后,看下控制台,人都傻了,一片红,内心不禁感叹“如果这是股票基金该多好”。

出了问题就要解决,随着排查深入,我的眉头一皱发现事情并不简单,怎么以前的一些代码都报错了?

58f3a74d5b3aca59abc41ec4bb7fa9c8.png

随着排查深入,最后跟到了Mybatis源码,发现罪魁祸首是sharding-jdbc引起的,因为数据源是sharding-jdbc的,导致后续执行sql的是ShardingPreparedStatement

这就意味着,sharding-jdbc影响项目的所有业务表,因为最终数据库交互都由ShardingPreparedStatement去做了,历史的一些sql语句因为sql函数或者其他写法,使得ShardingPreparedStatement无法处理而出现异常。

关键代码如下

8e5b534a7fe6fea9cd48df1643cb5404.png

发现问题后,阿星马上就反馈给leader了。

55900a4a4fc918d930ef599e8977f045.png

唉,本来还想摸鱼的,看来摸鱼的时间是没了,还多了一项任务。

分析

竟然交给阿星来做了,就撸起袖子开干吧,先看看分表功能的需求

  • 支持自定义分表策略

  • 能控制影响范围

  • 通用性

分表会提前建立好,所以不需要考虑表不存在的问题,核心逻辑实现,通过分表策略得到分表名,再把分表名动态替换到sql

8371056152f26433e75bf7f5d5e67cc8.png

分表策略

为了支持分表策略,我们需要先定义分表策略抽象接口,定义如下

/*** @Author 程序猿阿星* @Description 分表策略接口* @Date 2021/5/9*/
public interface ITableShardStrategy {/*** @author: 程序猿阿星* @description: 生成分表名* @param tableNamePrefix 表前缀名* @param value 值* @date: 2021/5/9* @return: java.lang.String*/String generateTableName(String tableNamePrefix,Object value);/*** 验证tableNamePrefix*/default void verificationTableNamePrefix(String tableNamePrefix){if (StrUtil.isBlank(tableNamePrefix)) {throw new RuntimeException("tableNamePrefix is null");}}
}

generateTableName函数的任务就是生成分表名,入参有tableNamePrefix、valuetableNamePrefix为分表前缀,value作为生成分表名的逻辑参数。

verificationTableNamePrefix函数验证tableNamePrefix必填,提供给实现类使用。

为了方便理解,下面是id取模策略代码,取模两张表

/*** @Author 程序猿阿星* @Description 分表策略id* @Date 2021/5/9*/
@Component
public class TableShardStrategyId implements ITableShardStrategy {@Overridepublic String generateTableName(String tableNamePrefix, Object value) {verificationTableNamePrefix(tableNamePrefix);if (value == null || StrUtil.isBlank(value.toString())) {throw new RuntimeException("value is null");}long id = Long.parseLong(value.toString());//此处可以缓存优化return tableNamePrefix + "_" + (id % 2);}
}

传入进来的valueid值,用tableNamePrefix拼接id取模后的值,得到分表名返回。

控制影响范围

分表策略已经抽象出来,下面要考虑控制影响范围,我们都知道Mybatis规范中每个Mapper类对应一张业务主体表,Mapper类的函数对应业务主体表的相关sql

阿星想着,可以给Mapper类打上注解,代表该Mpaaer类对应的业务主体表有分表需求,从规范来说Mapper类的每个函数对应的主体表都是正确的,但是有些同学可能不会按规范来写。

假设Mpaaer类对应的是B表,Mpaaer类的某个函数写着A表的sql,甚至是历史遗留问题,所以注解不仅仅可以打在Mapper类上,同时还可以打在Mapper类的任意一个函数上,并且保证小粒度覆盖粗粒度。

阿星这里自定义分表注解,代码如下

/*** @Author 程序猿阿星* @Description 分表注解* @Date 2021/5/9*/
@Target(value = {ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TableShard {// 表前缀名String tableNamePrefix();//值String value() default "";//是否是字段名,如果是需要解析请求参数改字段名的值(默认否)boolean fieldFlag() default false;// 对应的分表策略类Class<? extends ITableShardStrategy> shardStrategy();}

注解的作用范围是类、接口、函数,运行时生效。

tableNamePrefixshardStrategy属性都好理解,表前缀名和分表策略,剩下的valuefieldFlag要怎么理解,分表策略分两类,第一类依赖表中某个字段值,第二类则不依赖。

根据企业id取模,属于第一类,此处的value设置企业id入参字段名,fieldFlagtrue,意味着,会去解析获取企业id字段名对应的值。

根据日期分表,属于第二类,直接在分表策略实现类里面写就行了,不依赖表字段值,valuefieldFlag无需填写,当然你value也可以设置时间格式,具体看分表策略实现类的逻辑。

通用性

抽象分表策略与分表注解都搞定了,最后一步就是根据分表注解信息,去执行分表策略得到分表名,再把分表名动态替换到sql中,同时具有通用性。

Mybatis框架中,有拦截器机制做扩展,我们只需要拦截StatementHandler#prepare函数,即StatementHandle创建Statement之前,先把sql里面的表名动态替换成分表名。

Mybatis分表拦截器流程图如下

0c0c133da3eb7c792ff9abcdf0c20f72.png

Mybatis分表拦截器代码如下,有点长哈,主流程看intercept函数就好了。

/*** @Author 程序员阿星* @Description 分表拦截器* @Date 2021/5/9*/
@Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class, Integer.class})
})
public class TableShardInterceptor implements Interceptor {private static final ReflectorFactory defaultReflectorFactory = new DefaultReflectorFactory();@Overridepublic Object intercept(Invocation invocation) throws Throwable {// MetaObject是mybatis里面提供的一个工具类,类似反射的效果MetaObject metaObject = getMetaObject(invocation);BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");//获取Mapper执行方法Method method = invocation.getMethod();//获取分表注解TableShard tableShard = getTableShard(method,mappedStatement);// 如果method与class都没有TableShard注解或执行方法不存在,执行下一个插件逻辑if (tableShard == null) {return invocation.proceed();}//获取值String value = tableShard.value();//value是否字段名,如果是,需要解析请求参数字段名的值boolean fieldFlag = tableShard.fieldFlag();if (fieldFlag) {//获取请求参数Object parameterObject = boundSql.getParameterObject();if (parameterObject instanceof MapperMethod.ParamMap) { //ParamMap类型逻辑处理MapperMethod.ParamMap parameterMap = (MapperMethod.ParamMap) parameterObject;//根据字段名获取参数值Object valueObject = parameterMap.get(value);if (valueObject == null) {throw new RuntimeException(String.format("入参字段%s无匹配", value));}//替换sqlreplaceSql(tableShard, valueObject, metaObject, boundSql);} else { //单参数逻辑//如果是基础类型抛出异常if (isBaseType(parameterObject)) {throw new RuntimeException("单参数非法,请使用@Param注解");}if (parameterObject instanceof Map){Map<String,Object>  parameterMap =  (Map<String,Object>)parameterObject;Object valueObject = parameterMap.get(value);//替换sqlreplaceSql(tableShard, valueObject, metaObject, boundSql);} else {//非基础类型对象Class<?> parameterObjectClass = parameterObject.getClass();Field declaredField = parameterObjectClass.getDeclaredField(value);declaredField.setAccessible(true);Object valueObject = declaredField.get(parameterObject);//替换sqlreplaceSql(tableShard, valueObject, metaObject, boundSql);}}} else {//无需处理parameterField//替换sqlreplaceSql(tableShard, value, metaObject, boundSql);}//执行下一个插件逻辑return invocation.proceed();}@Overridepublic Object plugin(Object target) {// 当目标类是StatementHandler类型时,才包装目标类,否者直接返回目标本身, 减少目标被代理的次数if (target instanceof StatementHandler) {return Plugin.wrap(target, this);} else {return target;}}/*** @param object* @methodName: isBaseType* @author: 程序员阿星* @description: 基本数据类型验证,true是,false否* @date: 2021/5/9* @return: boolean*/private boolean isBaseType(Object object) {if (object.getClass().isPrimitive()|| object instanceof String|| object instanceof Integer|| object instanceof Double|| object instanceof Float|| object instanceof Long|| object instanceof Boolean|| object instanceof Byte|| object instanceof Short) {return true;} else {return false;}}/*** @param tableShard 分表注解* @param value      值* @param metaObject mybatis反射对象* @param boundSql   sql信息对象* @author: 程序猿阿星* @description: 替换sql* @date: 2021/5/9* @return: void*/private void replaceSql(TableShard tableShard, Object value, MetaObject metaObject, BoundSql boundSql) {String tableNamePrefix = tableShard.tableNamePrefix();//获取策略classClass<? extends ITableShardStrategy> strategyClazz = tableShard.shardStrategy();//从spring ioc容器获取策略类ITableShardStrategy tableShardStrategy = SpringUtil.getBean(strategyClazz);//生成分表名String shardTableName = tableShardStrategy.generateTableName(tableNamePrefix, value);// 获取sqlString sql = boundSql.getSql();// 完成表名替换metaObject.setValue("delegate.boundSql.sql", sql.replaceAll(tableNamePrefix, shardTableName));}/*** @param invocation* @author: 程序猿阿星* @description: 获取MetaObject对象-mybatis里面提供的一个工具类,类似反射的效果* @date: 2021/5/9* @return: org.apache.ibatis.reflection.MetaObject*/private MetaObject getMetaObject(Invocation invocation) {StatementHandler statementHandler = (StatementHandler) invocation.getTarget();// MetaObject是mybatis里面提供的一个工具类,类似反射的效果MetaObject metaObject = MetaObject.forObject(statementHandler,SystemMetaObject.DEFAULT_OBJECT_FACTORY,SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,defaultReflectorFactory);return metaObject;}/*** @author: 程序猿阿星* @description: 获取分表注解* @param method* @param mappedStatement* @date: 2021/5/9* @return: com.xing.shard.interceptor.TableShard*/private TableShard getTableShard(Method method, MappedStatement mappedStatement) throws ClassNotFoundException {String id = mappedStatement.getId();//获取Classfinal String className = id.substring(0, id.lastIndexOf("."));//分表注解TableShard tableShard = null;//获取Mapper执行方法的TableShard注解tableShard = method.getAnnotation(TableShard.class);//如果方法没有设置注解,从Mapper接口上面获取TableShard注解if (tableShard == null) {// 获取TableShard注解tableShard = Class.forName(className).getAnnotation(TableShard.class);}return tableShard;}}

到了这里,其实分表功能就已经完成了,我们只需要把分表策略抽象接口、分表注解、分表拦截器抽成一个通用jar包,需要使用的项目引入这个jar,然后注册分表拦截器,自己根据业务需求实现分表策略,在给对应的Mpaaer加上分表注解就好了。

c5462d0899f528abdbcf7389dabe7da4.png

实践跑起来

这里阿星单独写了一套demo,场景是有两个分表策略,表也提前建立好了

  • 根据id分表

    • tb_log_id_0

    • tb_log_id_1

  • 根据日期分表

    • tb_log_date_202105

    • tb_log_date_202106

预警:后面都是代码实操环节,请各位读者大大耐心看完(非Java开发除外)

TableShardStrategy定义

/*** @Author wx* @Description 分表策略日期* @Date 2021/5/9*/
@Component
public class TableShardStrategyDate implements ITableShardStrategy {private static final String DATE_PATTERN = "yyyyMM";@Overridepublic String generateTableName(String tableNamePrefix, Object value) {verificationTableNamePrefix(tableNamePrefix);if (value == null || StrUtil.isBlank(value.toString())) {return tableNamePrefix + "_" +DateUtil.format(new Date(), DATE_PATTERN);} else {return tableNamePrefix + "_" +DateUtil.format(new Date(), value.toString());}}
}*** @Author 程序猿阿星* @Description 分表策略id* @Date 2021/5/9*/
@Component
public class TableShardStrategyId implements ITableShardStrategy {@Overridepublic String generateTableName(String tableNamePrefix, Object value) {verificationTableNamePrefix(tableNamePrefix);if (value == null || StrUtil.isBlank(value.toString())) {throw new RuntimeException("value is null");}long id = Long.parseLong(value.toString());//可以加入本地缓存优化return tableNamePrefix + "_" + (id % 2);}
}

Mapper定义

Mapper接口

/*** @Author 程序猿阿星* @Description* @Date 2021/5/8*/
@TableShard(tableNamePrefix = "tb_log_date",shardStrategy = TableShardStrategyDate.class)
public interface LogDateMapper {/*** 查询列表-根据日期分表*/List<LogDate> queryList();/*** 单插入-根据日期分表*/void  save(LogDate logDate);}-------------------------------------------------------------------------------------------------/*** @Author 程序猿阿星* @Description* @Date 2021/5/8*/
@TableShard(tableNamePrefix = "tb_log_id",value = "id",fieldFlag = true,shardStrategy = TableShardStrategyId.class)
public interface LogIdMapper {/*** 根据id查询-根据id分片*/LogId queryOne(@Param("id") long id);/*** 单插入-根据id分片*/void save(LogId logId);}

Mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xing.shard.mapper.LogDateMapper">//对应LogDateMapper#queryList函数<select id="queryList" resultType="com.xing.shard.entity.LogDate">selectid as id,comment as comment,create_date as createDatefromtb_log_date</select>//对应LogDateMapper#save函数<insert id="save" >insert into tb_log_date(id, comment,create_date)values (#{id}, #{comment},#{createDate})</insert>
</mapper>-------------------------------------------------------------------------------------------------<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xing.shard.mapper.LogIdMapper">//对应LogIdMapper#queryOne函数<select id="queryOne" resultType="com.xing.shard.entity.LogId">selectid as id,comment as comment,create_date as createDatefromtb_log_idwhereid = #{id}</select>//对应save函数<insert id="save" >insert into tb_log_id(id, comment,create_date)values (#{id}, #{comment},#{createDate})</insert></mapper>

执行下单元测试

日期分表单元测试执行

@Testvoid test() {LogDate logDate = new LogDate();logDate.setId(snowflake.nextId());logDate.setComment("测试内容");logDate.setCreateDate(new Date());//插入logDateMapper.save(logDate);//查询List<LogDate> logDates = logDateMapper.queryList();System.out.println(JSONUtil.toJsonPrettyStr(logDates));}

输出结果

dd632a09e31e4148214c3f394c1d7877.png

id分表单元测试执行

@Testvoid test() {LogId logId = new LogId();long id = snowflake.nextId();logId.setId(id);logId.setComment("测试");logId.setCreateDate(new Date());//插入logIdMapper.save(logId);//查询LogId logIdObject = logIdMapper.queryOne(id);System.out.println(JSONUtil.toJsonPrettyStr(logIdObject));}

输出结果

09ec4af70b8d331038697d8ba1c5b457.png

小结一下

本文可以当做对Mybatis进阶的使用教程,通过Mybatis拦截器实现分表的功能,满足基本的业务需求,虽然比较简陋,但是Mybatis这种扩展机制与设计值得学习思考。

有兴趣的读者也可以自己写一个,或基于阿星的做改造,毕竟是简陋版本,还是有很多场景没有考虑到。

另外分表的demo项目,放到了Gitee和公众号,大家按需自取

- Gitee地址: https://gitee.com/jxncwx/shard

项目结构:

04a4b0041b5cd3927bae34f97562f2b6.png

855bbf93cc97d113b28e82b4c8148e58.gif

往期推荐

81c9e419c7c7bedeb6567f5fdd03171c.png

MyBatis 中为什么不建议使用 where 1=1?


8c3cf029078bcc946ec4548da883bc78.png

SpringBoot 使用注解实现消息广播功能


185bf9ff5cd5ebec2d64782e6ab45bd6.png

聊聊接口性能优化的11个小技巧


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544465.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

密码学哈希函数_哈希函数在密码学中的应用

密码学哈希函数A Hash Function is a mathematical function that converts a numerical value into another compressed numeric value. The input value for the hash functions can be of arbitrary length, but the output text that it will produce will always be of fi…

C语言图形化界面——含图形、按钮、鼠标、进度条等部件制作(带详细代码、讲解及注释)

目录0.引言1.素材准备2.编程2.1.创建你的界面2.2.创建按钮2.3.鼠标操作2.3.1.单击特效2.3.2.光标感应2.3.3.进度条3.完整代码及效果0.引言 \qquad看了CSDN上很多关于C程序图形化界面的介绍&#xff0c;有的代码繁琐难解&#xff0c;不方便调试修改&#xff1b;有的不够详细。本…

C#学习笔记(十三):I/O操作

C#的IO操作主要是针对文件夹和文件的读取和写入操作&#xff0c;下面我们来学习一下相关操作的类。 获取文件信息 Directory和DirectoryInfo 两个类的功能基本相同&#xff0c;区别如下&#xff1a; 前者继承System.Object,后者继承抽象类FileSystemInfo&#xff1b;前者是静态…

工作几年了,原来我只用了数据校验的皮毛

今天介绍一下 Spring Boot 如何优雅的整合JSR-303进行参数校验&#xff0c;说到参数校验可能都用过&#xff0c;但是你真的会用吗&#xff1f;网上的教程很多&#xff0c;大多是简单的介绍。什么是 JSR-303&#xff1f;JSR-303 是 JAVA EE 6 中的一项子规范&#xff0c;叫做 Be…

scala 字符串转换数组_如何在Scala中将十六进制字符串转换为字节数组?

scala 字符串转换数组Hex String in Scala denotes value in hexadecimal number system i.e. base 16 number system. Scala中的十六进制字符串表示以十六进制数表示的值&#xff0c;即以16进制数表示的系统。 Example: 例&#xff1a; hexString "32AF1"Byte Ar…

【MATLAB】无人驾驶车辆的模型预测控制技术(精简讲解和代码)【运动学轨迹规划】

文章目录<font color#19C>0.友情链接<font color#19C>1.引言<font color#19C>2.预测模型<font color#19C>3.滚动优化<font color#08CF>3.1.线性化3.2.UrU_rUr​的求取<font color#08CF>3.3.离散化与序列化<font color#08CF>3.4.实现…

顶级Javaer,常用的 14 个类库

作者&#xff1a;小姐姐味道&#xff08;微信公众号ID&#xff1a;xjjdog&#xff09;昨天下载下来Java16尝尝鲜。一看&#xff0c;好家伙&#xff0c;足足有176MB大。即使把jmc和jvisualvm给搞了出去&#xff0c;依然还是这么大&#xff0c;真的是让人震惊不已。但即使JDK足够…

单层神经网络线性回归_单层神经网络| 使用Python的线性代数

单层神经网络线性回归A neural network is a powerful tool often utilized in Machine Learning because neural networks are fundamentally very mathematical. We will use our basics of Linear Algebra and NumPy to understand the foundation of Machine Learning usin…

用express、mongodb、nodejs开发简单的登陆

原文http://my.oschina.net/chenhao901007/blog/312367 npm i -g express serve-favicon morgan cookie-parser body-parser kerberos mongoose(注意:kerberos不安装&#xff0c;mongoose会卡住)2. 调试下面讲讲如何调试服务器端的代码&#xff1a;我们最好借助一个叫node-insp…

Lua元表(Metatable)简易教程

文章目录0.友情链接1.引言2.创建一个元表2.1.__tostring方法2.2.__add和__mul方法2.3.__index方法2.4.__call方法3.完整代码0.友情链接 GitHUb上下载Lua编译器Lua菜鸟教程中的元表介绍&#xff08;较全&#xff0c;但功能性受限&#xff09;博客园内元表的介绍&#xff08;较详…

面试官:说一下 final 和 final 的 4 种用法?

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;重要说明&#xff1a;本篇为博主《面试题精选-基础篇》系列中的一篇&#xff0c;查看系列面试文章请关注我。Gitee 开源地址…

ruby 将字符串转为数组_Ruby程序将数组打印为字符串

ruby 将字符串转为数组将数组打印为字符串 (Printing an array as string) Given an array and we have to print it as a string in Ruby. 给定一个数组&#xff0c;我们必须在Ruby中将其打印为字符串。 Ruby provides you various alternatives for the single problem. The…

超定方程组的最小二乘解

\qquad看了很多关于最小二乘解的博客&#xff0c;事实上都没有找到自己想要的证明过程&#xff0c;后来学了矩阵函数时才彻底搞明白了这件事情&#xff0c;所以和大家简单分享如下&#xff1a; \qquad已知矩阵Amn(m&#xff1e;n)A_{mn}(m&#xff1e;n)Amn​(m&#xff1e;n)是…

面试官:int和Integer有什么区别?为什么要有包装类?

作者 | 磊哥来源 | Java面试真题解析&#xff08;ID&#xff1a;aimianshi666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;重要说明&#xff1a;本篇为博主《面试题精选-基础篇》系列中的一篇&#xff0c;查看系列面试文章请关注我。Gitee 开…

shell从小做起:将100以内整除3的数列出来

#!/bin/bash for i in $(seq 1 100) do a$[ $i%3 ] #注&#xff1a; 在取余的时候 需要 运算 所以需要加运算符号 $[ ] if [ $a -eq 0 ]; thenecho "$i" fi done转载于:https://blog.51cto.com/286577399/1676501

c# 用空格分割字符串_C#| 左用空格填充字符串

c# 用空格分割字符串PadLeft() method is a library method of the String class. It is used to pad the string from the left side with spaces. PadLeft()方法是String类的库方法。 它用于从左侧用空格填充字符串。 Syntax: 句法&#xff1a; string string.PadLeft(int …

innodb是如何存数据的?yyds

前言如果你使用过mysql数据库&#xff0c;对它的存储引擎&#xff1a;innodb&#xff0c;一定不会感到陌生。众所周知&#xff0c;在mysql5以前&#xff0c;默认的存储引擎是&#xff1a;myslam。但mysql5之后&#xff0c;默认的存储引擎已经变成了&#xff1a;innodb&#xff…

【MATLAB】卡尔曼滤波器的原理及仿真(初学者专用)

文章目录0.引言1.场景预设2.卡尔曼滤波器3.仿真及效果0.引言 \qquad本文参考了Matlab对卡尔曼滤波器的官方教程及帮助文档&#xff08;Kalman Filter&#xff09;。官方教程的B站链接如下&#xff0c;在此对分享资源的Up主表示感谢。(如不能正常播放或需要看中文字幕&#xff0…

Go实现查找目录下(包括子目录)替换文件内容

为什么80%的码农都做不了架构师&#xff1f;>>> 【功能】 按指定的目录查找出文件&#xff0c;如果有子目录&#xff0c;子目录也将进行搜索&#xff0c;将其中的文件内容进行替换。 【缺陷】 1. 没有过滤出文本文件 2. 当文件过大时&#xff0c;效率不高 【代码】…

卡诺模板_无关条件的卡诺地图

卡诺模板Till now, the Boolean expressions which have been discussed by us were completely specified, i.e., for each combination of input variable we have specified a minterm by representing them as 1 in the K-Map. But, there may arise a case when for a giv…