精华内容
下载资源
问答
  • #MyBatis通用Mapper3 ##极其方便的使用MyBatis单表的增删改改查 ##支持单表操作,不支持通用的多表联合查询 ##优点? 通用Mapper都可以极大的方便开发人员。可以随意的按照自己的需要选择通用方法,还可以很方便的...
  • 通用 Mapper 源码分析

    2019-03-16 11:24:03
    通用 Mapper是一个可以实现任意 MyBatis 通用方法的框架,项目提供了常规的增删改查操作以及Example相关的单表操作。 文章地址:https://mp.weixin.qq.com/s?__biz=MzU1OTgyMDc3Mg==&mid=2247483774&...

    通用 Mapper 是一个可以实现任意 MyBatis 通用方法的框架,项目提供了常规的增删改查操作以及Example 相关的单表操作。

    文章地址:https://mp.weixin.qq.com/s?__biz=MzU1OTgyMDc3Mg==&mid=2247483774&idx=1&sn=aebbcef0f3b26ae2441fbe061b485b3e&chksm=fc103bf5cb67b2e309d241d6899337530895e3c6181c17029bb1025496a67eb60c731e4d844e&token=1852415967&lang=zh_CN#rd

    欢迎关注公众号:

    展开全文
  • 通用mapper测试例子,Example 条件查询,常用添加 更新 删除操作,MBG
  • Mybatis通用Mapper组件是最近才开始真正去了解的,其实很早之间就关注了作者的微信公众号和QQ群,但抱着用上再看的原则,所以拖延到了现在。

    这个组件是最近才开始真正去了解的,很早之间就关注了作者的微信公众号和QQ群,但抱着用上再看的原则,所以拖延到了现在。

    1. 配置

    我们先来看看相关配置,可以说是相当简单了

      	<!-- 通用Mapper配置, 单表操作零SQL -->
      	<!-- 与mybatis-spring.jar中同名类, 唯一区别是完整命名, 其首位由org更换为tk  -->
    	<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
    		<!-- 指示满足通用Mapper契约的定义接口所在的package, 可以配置多个 -->
    		<property name="basePackage" value="com.kanq.train.dao" />
    		<!-- 指定所关联的MyBatis SqlSessionFactory, 如果不设置将交由Spring自动注入-->
    		<!-- 所以如果你有多个数据源, 就需要如下配置来显式指定, 否则会报错-->
    		<property name="sqlSessionFactoryBeanName" value="mainSqlSessionFactory" />
    		<!-- 以下配置属性的最终使用者是 通用Mapper的核心类 MapperHelper -->
    		<!-- 感兴趣的读者可以参见其内部定义的 MapperHelper.setProperties() 方法-->
    		<property name="properties">
    			<value>
    				mappers=com.xxx.yyy.core.Mapper
    				notEmpty=false
    				IDENTITY=ORACLE
    			</value>
    		</property>
    	</bean>
    

    2. 解读

    1. 通观以上的配置,毫无疑问入口就是通用Mapper自定义的那个MapperScannerConfigurer了。
    2. 而观察自定义MapperScannerConfigurer的实现我们可以发现,逻辑主要位于其所实现的接口BeanDefinitionRegistryPostProcessor中定义的postProcessBeanDefinitionRegistry()方法内——通过自定义的ClassPathMapperScanner类将用户配置的basePackage属性指示的package中的指定类型扫描进行Spring容器中。
    3. 就像自定义MapperScannerConfigurer的直接借鉴自mybatis-spring中的同名类一样 ,自定义的ClassPathMapperScanner类同样是直接借鉴自mybatis-spring中的同名类;并选择覆写了基类的doScan(String... basePackages)方法。
    4. 对于自定义的ClassPathMapperScanner类覆写的doScan(String... basePackages)方法,核心逻辑就是将扫描到的用户指定的basePackage下的每个接口的Bean定义,将其beanClass属性更换为自定义的MapperFactoryBean<T>类型(注意这个类型的由来和上面的ClassPathMapperScannerMapperScannerConfigurer类似),以及为该MapperFactoryBean<T>实例注入相应的依赖(例如关键性的MapperHelper实例字段等等)。
    5. 关于上一步的扫描逻辑,还有一个细节就是自定义的ClassPathMapperScanner类还覆写了基类的isCandidateComponent(AnnotatedBeanDefinition beanDefinition)方法,声明只有接口才可能满足条件。所以其实这里声明一个空的标志性接口也是可以被扫描进去的。
    6. 接下来的关注点就是MapperFactoryBean<T>,通观其继承链我们可以发现两个关键性接口InitializingBeanFactoryBean<T>
      a. 接口InitializingBean,这个间接实现的Spring接口,相关的逻辑位于覆写的checkDaoConfig()方法,在此覆写方法中,将回调Mybatis中的configuration.addMapper(this.mapperInterface);方法,这将最终导致ProviderSqlSource的构造(关于这个在通用Mapper起到关键作用的类这里就不赘述了,作者的文章做过专门讲解)。
      回调InitializingBean
      b. 接口InitializingBean中完成的另外一个关键逻辑正是通用Mapper实现的关键——通过替换掉上面生成MappedStatement实例中的所有ProviderSqlSource实例,来完成关键性的准备工作(mapperHelper.processConfiguration(getSqlSession().getConfiguration(), this.mapperInterface);)。
      偷天换日
      c. 关于FactoryBean<T>接口,其对Spring容器的意义不用多说了,在这里的目的也是一样的。
    7. 以上替换SqlSource的操作,正是给予通用Mapper大展拳脚空间的关键。通用Mapper正是在此替换操作之前,回调一系列的约定下的实现者来动态获取相应的作为替换者的真正SqlSource(MapperTemplate.setSqlSource(MappedStatement ms)方法)。

    相关时序图如下:

    1. 替换为MapperFactoryBean<T>类型
      替换为MapperFactoryBean类型
    2. 构建出ProviderSqlSource实例,并替换为我们自定义的SqlSource实例。
      在这里插入图片描述

    3. 实例

    上面扯完了这么多源码相关的内容,对于初次接触到的读者难免会觉得晦涩难懂。所以接下来我将以一个实际的例子来说明一些使用者关心的细节。

    下面这个OracleProvider类是笔者从通用Mapper4.1.5版本中随便挑出来的。

    /**
     * @description: Oracle实现类
     * @author: qrqhuangcy
     * @date: 2018-11-15
     **/
     // ====== 直接继承自MapperTemplate, 这也满足MapperTemplate类上的注释说明
    public class OracleProvider extends MapperTemplate {
    	// 构造函数参数的参数声明, 可以参考框架中的 MapperHelper.fromMapperClass()中的逻辑
    	// 正是在 MapperHelper.fromMapperClass() 中实例化了本类, 以填充自身内部的methodMap 字段(该methodMap 字段将在替换sqlSource时候生效) , 例如对于本类将注册insertList方法
        public OracleProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
            super(mapperClass, mapperHelper);
        }
    	
    	// 该方法将被框架使用反射方式进行回调, 参见MapperTemplate.setSqlSource(MappedStatement ms)
    	// 允许的方法参数只有MappedStatement
    	// 允许的返回值有Void, SqlNode, String, 而这些返回值正是真正执行的SQL相关内容
        public String insertList(MappedStatement ms){
    		......
    	}
    }
    

    看完了OracleProvider类的定义,接下来我们再看看其应用,按照通用Mapper的设计思路,我们还需要一个接口承载该类:

    @tk.mybatis.mapper.annotation.RegisterMapper
    public interface InsertListMapper<T> {
    
        /**
         * <p>生成如下批量SQL:
         * <p>INSERT ALL
         * <p>INTO demo_country ( country_id,country_name,country_code ) VALUES ( ?,?,? )
         * <p>INTO demo_country ( country_id,country_name,country_code ) VALUES ( ?,?,? )
         * <p>INTO demo_country ( country_id,country_name,country_code ) VALUES ( ?,?,? )
         * <p>SELECT 1 FROM DUAL
         *
         * @param recordList
         * @return
         */
        // 该注解也就是导致ProviderSqlSource实例生成的关键
        @InsertProvider(type = OracleProvider.class, method = "dynamicSQL")
        int insertList(List<? extends T> recordList);
    }
    

    以上,所有的扩展准备工作就算是完成了,接下来要做的就是按照自己的需求继承上面的InsertListMapper<T>接口,然后你就自动拥有了InsertList的能力。

    本小节最后,总结下自定义扩展时候的注意事项吧:

    1. 自定义的扩展接口(例如上面的InsertListMapper<T>),方法签名的定义没有注意事项,只需要注意方法上注解的method参数值必须为dynamicSQL
    2. 上述注解中,其另外一个type 参数所指示的自定义类型,该类型必须有这样一个方法:
      a. 与该接口方法同名的,
      b. 方法参数为MappedStatement类型,
      c. 返回值为voidString, SqlNode中的一种。
    3. 更多的细节还是参见作者本人的扩展通用接口 文档吧。

    4. 总结

    1. MapperScannerConfigurerClassPathMapperScanner配合将可能满足条件的全部接口全部扫描入容器,这些接口在Spring容器内部将以自定义MapperFactoryBean<T>的形式存在。
    2. 自定义MapperFactoryBean<T>因为间接实现的Spring中的InitializingBean接口,使得有机会在系统初始化过程中完成底层MappedStatement实例中的SqlSource字段值的替换。
    3. MapperScannerConfigurer构建的MapperHelper实例是全局唯一的。这也符合重量级的服务域应该是全局唯一的最佳实践。
    4. 上面提到的MapperHelper实例在通用Mapper的关键类MapperFactoryBean<T>MapperTemplate类中都相应的实例字段,这和Mybatis内部的Configuration实例地位相当类似,类似《程序员修炼之道–从小工到专家》中"黑板"的概念。

    5. 结尾

    其实最让笔者感慨的是,任何一件事,哪怕再小,只要肯钻研,其中必然有着无数可以完善的细节,而正是这些细节的追求,让人变得优秀。通用Mapper的作者从2014年的最初版本坚持演化到现在,这份坚持的精神,以及精益求精的态度真的很让人动容。

    6. 相关链接

    1. MyBatis 为什么需要通用 Mapper ?
    2. 通用Mapper - WIKI
    展开全文
  • 1.配置JavaBean与数据库表字段映射关系 /** * 字段转换方式 */ public enum Style { normal, //原值 camelhump, //驼峰转下划线 uppercase, //转换为大写 lowercase, ...

    1.配置JavaBean与数据库表字段映射关系

    /**
     * 字段转换方式
     */
    public enum Style {
        normal,                     //原值
        camelhump,                  //驼峰转下划线
        uppercase,                  //转换为大写
        lowercase,                  //转换为小写
        camelhumpAndUppercase,      //驼峰转下划线大写形式
        camelhumpAndLowercase,      //驼峰转下划线小写形式
    }
    

      根据实体类名称转换表名称

      /**
         * 根据指定的样式进行转换
         *
         * @param str
         * @param style
         * @return
         */
        public static String convertByStyle(String str, Style style) {
            switch (style) {
                case camelhump:
                    return camelhumpToUnderline(str);
                case uppercase:
                    return str.toUpperCase();
                case lowercase:
                    return str.toLowerCase();
                case camelhumpAndLowercase:
                    return camelhumpToUnderline(str).toLowerCase();
                case camelhumpAndUppercase:
                    return camelhumpToUnderline(str).toUpperCase();
                case normal:
                default:
                    return str;
            }

    具体的转换方式

      /**
         * 将驼峰风格替换为下划线风格
         */
        public static String camelhumpToUnderline(String str) {
            final int size;
            final char[] chars;
            final StringBuilder sb = new StringBuilder(
                    (size = (chars = str.toCharArray()).length) * 3 / 2 + 1);
            char c;
            for (int i = 0; i < size; i++) {
                c = chars[i];
                if (isUppercaseAlpha(c)) {
                    sb.append('_').append(toLowerAscii(c));
                } else {
                    sb.append(c);
                }
            }
            return sb.charAt(0) == '_' ? sb.substring(1) : sb.toString();
        }

    2.通过反射JavaBean拿到所有的field

         /**
             * 获取全部的Field,仅仅通过Field获取
             *
             * @param entityClass
             * @param fieldList
             * @param level
             * @return
             */
            private List<EntityField> _getFields(Class<?> entityClass, List<EntityField> fieldList, Integer level) {
                if (fieldList == null) {
                    fieldList = new ArrayList<EntityField>();
                }
                if (level == null) {
                    level = 0;
                }
                if (entityClass.equals(Object.class)) {
                    return fieldList;
                }
                Field[] fields = entityClass.getDeclaredFields();
                int index = 0;
                for (int i = 0; i < fields.length; i++) {
                    Field field = fields[i];
                    //排除静态字段,解决bug#2
                    if (!Modifier.isStatic(field.getModifiers()) && !Modifier.isTransient(field.getModifiers())) {
                        if (level.intValue() != 0) {
                            //将父类的字段放在前面
                            fieldList.add(index, new EntityField(field, null));
                            index++;
                        } else {
                            fieldList.add(new EntityField(field, null));
                        }
                    }
                }
                Class<?> superClass = entityClass.getSuperclass();
                if (superClass != null
                        && !superClass.equals(Object.class)
                        && (superClass.isAnnotationPresent(Entity.class)
                        || (!Map.class.isAssignableFrom(superClass)
                        && !Collection.class.isAssignableFrom(superClass)))) {
                    return _getFields(entityClass.getSuperclass(), fieldList, ++level);
                }
                return fieldList;
            }

     

     

    展开全文
  • 1.javabean的属性值生成sql /** * 获取所有查询列,如id,name,code... * * @param entityClass * @return */ public static String getAllColumns(Class&lt;?&gt; entityClass) { ...E...

    1.javabean的属性值生成sql

      /**
         * 获取所有查询列,如id,name,code...
         *
         * @param entityClass
         * @return
         */
        public static String getAllColumns(Class<?> entityClass) {
            Set<EntityColumn> columnSet = EntityHelper.getColumns(entityClass);
            StringBuilder sql = new StringBuilder();
            for (EntityColumn entityColumn : columnSet) {
                sql.append(entityColumn.getColumn()).append(",");
            }
            return sql.substring(0, sql.length() - 1);
        }
      /**
         * 判断自动==null的条件结构
         *
         * @param entityName
         * @param column
         * @param contents
         * @param empty
         * @return
         */
        public static String getIfIsNull(String entityName, EntityColumn column, String contents, boolean empty) {
            StringBuilder sql = new StringBuilder();
            sql.append("<if test=\"");
            if (StringUtil.isNotEmpty(entityName)) {
                sql.append(entityName).append(".");
            }
            sql.append(column.getProperty()).append(" == null");
            if (empty && column.getJavaType().equals(String.class)) {
                sql.append(" or ");
                if (StringUtil.isNotEmpty(entityName)) {
                    sql.append(entityName).append(".");
                }
                sql.append(column.getProperty()).append(" == '' ");
            }
            sql.append("\">");
            sql.append(contents);
            sql.append("</if>");
            return sql.toString();
        }

     

    展开全文
  • 通用Mapper都可以极大的方便开发人员。可以随意的按照自己的需要选择通用方法,还可以很方便的开发自己的通用方法。 极其方便的使用MyBatis单表的增删改查。 支持单表操作,不支持通用的多表联合查询。 通用 Mapper ...
  • boot-mybatis-tk Spring Boot整合Mybatis 通用mapper
  • mybatis通用Mapper 本项目主要实现通用mapper,解决的crud包含以下: void add(S s); void update(S s); void delete(S s); void deleteById(@Param(value = “id”) Object id, Class clazz); void deleteAll...
  • 本篇主要是简单讲解,通用Mapper的实现原理,不是整合教程。每次学习一个新的框架/插件的时候,我们一开始都是按照官方示例写代码,达到了会用的目的。等用一段时候之后,就应该学习源码,学习它是如何设计的,为啥...
  • 通用Mapper Example类使用以及源码分析

    千次阅读 2019-06-11 17:41:17
    通用Mapper Example类源码分析 代码细节理解 1. criteria criteria 英 [kraɪ’tɪərɪə] 美 [kraɪ’tɪrɪə] n. 标准,条件(criterion的复数) 作者这里用 单词criteria 应该表达的是条件的意思,指sql ...
  • SpringBoot整合MyBatis/通用mapper/PageHelper,学习MyBatis注解/注解形式的动态sql等 mapper主页 mapper所有方法 MybatisGeneator插件学习 记录 在github逛到一个支付宝支付的无需申请支付宝api的项目...文档大略看...
  • mybatis是一个很好用的工具,但是编写mapper是一件很麻烦的事,自mybatis 3.0开始可以使用注解的方式,极大的简化了xml的编写量,本地想看看mybatis源码,自己扩展写一个工具,在阅读源码过程中发现一个通用mapper的...
  • Mybatis通用Mapper   极其方便的使用Mybatis单表的增删改查 项目地址:http://git.oschina.net/free/Mapper   优点?   不客气的说,使用这个通用Mapper甚至能改变你对Mybatis单表基础操作不方便的想法,使用...
  • 最近使用通用mapper开发项目,公司用的oracle数据库,持久层用的是通用mapper,公司要求用数据库的序列,按照官方的配置,可能是自己的原因,总是配置不对,自己看了一下源码,发现用key注解就可以实现,具体配置如下: ...
  • 经过 abel533(liuzh) 的修改,使得本项目变成一个基于通用Mapper 和 分页插件 PageHelper 的示例项目。 更多 MyBatis 相关内容可以访问: 基本改动 MyBatis 升级为 3.4.4 MyBatis-Spring 升级为 1.3.2 增加通用 ...
  • 项目基于jdk1.8整合了springboot+mvc+mybatis(通用mapper)+druid+jsp+bootstrap等技术,springboot+Listener(监听器),Filter(过滤器),Interceptor(拦截器),Servlet,springmvc静态资源,文件上传下载,多数据源切换,缓存...
  • 主要版本:springboot采用2.x版本、mybatis3.4X版本、通用mapper使用4.X版本 看完记得点赞噢~~~ 文档说明 1、集成MyBatis、通用Mapper插件、PageHelper分页插件,实现单表业务零SQL,可以说学会使用这套架构将节约你...
  • 一、在maven 的pom.xm中添加组件依赖, mybatis通用Mapper,及分页插件 1、mybatis通用Mapper <!-- mybatis通用Mapper--> <dependency> <groupId>tk.mybatis</groupId> <artif....
  • 以maven的形式生成通用mapper的逆向工程 2.添加maven的坐标 <properties> <!-- ${basedir}引用工程根目录 --> <!-- targetJavaProject:声明存放源码的目录位置 --> <targetJavaProject&...

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 207
精华内容 82
关键字:

通用mapper源码