整合mybatis很少使用的一些功能和学习

mybatis注解

@TypeDiscriminator 这个确实很少用到

通过case实现根据具体的列值,设置当前返回的类型

public interface UserMapper {
    @Select("SELECT id, name, type FROM users ORDER BY id")
    @TypeDiscriminator(
      column = "type",
      javaType = String.class,
      cases = {
        @Case(value = "1", type = PremiumUser.class, results = ({
            @Result(property = "id", column = "id", id = true),
      		@Result(property = "name", column = "name"),
      		@Result(property = "email" column = "id", one = @One(select = "selectUserEmailById", fetchType = FetchType.LAZY)),
        })),
        @Case(value = "2", type = GeneralUser.class),
        @Case(value = "3", type = TemporaryUser.class)
      }
    )
    List<User> selectAll();
  }

@xxxProvider(insert/delete/update/select)

指定提供用于删除记录的 SQL 的方法的注释。
如何使用:
  public interface UserMapper {
 
    @DeleteProvider(type = SqlProvider.class, method = "deleteById")
    boolean deleteById(int id);
 
    public static class SqlProvider {
      public static String deleteById() {
        return "DELETE FROM users WHERE id = #{id}";
      }
    }
 
  }

通过方法里提供的sql语句执行。

@Flush 一下内容是其源码部分

@Override
  public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
    try {
      List<BatchResult> results = new ArrayList<>();
      if (isRollback) {
        return Collections.emptyList();
      }
      //遍历statement
      for (int i = 0, n = statementList.size(); i < n; i++) {
        //设置查询的参数
        Statement stmt = statementList.get(i);
        applyTransactionTimeout(stmt);
        
        BatchResult batchResult = batchResultList.get(i);
        try {
          // 这里会调用statement的executeBatch来把之前的准备好的sql批量执行。
          // 那么,问题来了,statement是在哪里添加的?batchResult是在哪里添加的?
          batchResult.setUpdateCounts(stmt.executeBatch());
          MappedStatement ms = batchResult.getMappedStatement();
          //得到更新的操作
          List<Object> parameterObjects = batchResult.getParameterObjects();
          
          // 如果使用了KeyGenerator。
          KeyGenerator keyGenerator = ms.getKeyGenerator();
          if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
            Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;
            jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
          } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { //issue #141
            for (Object parameter : parameterObjects) {
              keyGenerator.processAfter(this, ms, stmt, parameter);
            }
          }
          //关闭Statement
          closeStatement(stmt);
        } catch (BatchUpdateException e) {
          StringBuilder message = new StringBuilder();
          message.append(batchResult.getMappedStatement().getId())
              .append(" (batch index #")
              .append(i + 1)
              .append(")")
              .append(" failed.");
          if (i > 0) {
            message.append(" ")
                .append(i)
                .append(" prior sub executor(s) completed successfully, but will be rolled back.");
          }
          throw new BatchExecutorException(message.toString(), e, results, batchResult);
        }
        // 将结果添加在result里面返回。
        results.add(batchResult);
      }
      return results;
    } finally {
      for (Statement stmt : statementList) {
        closeStatement(stmt);
      }
      currentSql = null;
      statementList.clear();
      batchResultList.clear();
    }
  }

@Lang 优雅的Dynamic SQL 动态SQL

优雅的Dynamic SQL

增强MyBatis注解
Lang的使用

自定义select in注解

@Lang(SimpleSelectInExtendedLanguageDriver.class)
@Select("SELECT * FROM users WHERE id IN (#{userIds})")
List<User> selectUsers(@Param("userIds") List<String> userIds);
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import org.apache.ibatis.session.Configuration;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
// 一次编写,受益终生

public class SimpleSelectInExtendedLanguageDriver 
    extends XMLLanguageDriver implements LanguageDriver {

        private final Pattern inPattern = Pattern.compile("\\(#\\{(\\w+)\\}\\)");

        @Override
        public SqlSource createSqlSource(Configuration configuration, 
                                         String script, Class<?> parameterType) {

            Matcher matcher = inPattern.matcher(script);
            if (matcher.find()) {
                script = matcher.replaceAll("(<foreach collection=\"$1\" item=\"__item\" separator=\",\" >#{__item}</foreach>)");
            }

            script = "<script>" + script + "</script>";
            return super.createSqlSource(configuration, script, parameterType);
        }
    }

我们通过实现自己的LanguageDriver,在MyBatis编译语句前,将我们自定义的标签替换为了动态SQL语句,其等同于:

@Select({"<script>",
         "SELECT *", 
         "FROM user",
         "WHERE id IN", 
         "<foreach item='item' index='index' collection='list'",
         "open='(' separator=',' close=')'>",
         "#{item}",
         "</foreach>",
         "</script>"}) 
    List<User> selectUsers(@Param("userIds") List<Intger> userIds);

自定义Update Bean注解

类似的,通过重写LanguageDriver,我们还能扩展出远比其它方案(e.g. XML SQL Mapper配置、在注解语句中写动态SQL)简洁的自定义操作。
一个常用的操作是更新数据库中的一条记录。通常而言,每张表(采用下划线命名法)会有一个对应的Domain对象(采用驼峰式命名法),当我们更新一条记录时,需要为对象中的每个字段配置映射关系,会写出如下的代码:

	@Update("UPDATE user (#{user}) WHERE id =#{userId}")
    @Lang(SimpleUpdateExtendedLanguageDriver.class)
    int updateUser(Store store);
import com.google.common.base.CaseFormat;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import org.apache.ibatis.session.Configuration;

import java.lang.reflect.Field;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by benxue on 3/1/16.
*/
public class SimpleUpdateExtendedLanguageDriver extends XMLLanguageDriver
    implements LanguageDriver {
        private final Pattern inPattern = Pattern.compile("\\(#\\{(\\w+)\\}\\)");


        @Override
        public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {
            Matcher matcher = inPattern.matcher(script);
            if (matcher.find()) {
                StringBuffer ss = new StringBuffer();
                ss.append("<set>");

                for (Field field : parameterType.getDeclaredFields()) {
                    String temp = "<if test=\"__field != null\">__column=#{__field},</if>";
                    ss.append(temp.replaceAll("__field", field.getName())
                              .replaceAll("__column", CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName())));
                }

                ss.deleteCharAt(ss.lastIndexOf(","));
                ss.append("</set>");

                script = matcher.replaceAll(ss.toString());

                script = "<script>" + script + "</script>";
            }
            return super.createSqlSource(configuration, script, parameterType);
        }
    }

一个常见的情况是,Domain中的部分属性在数据库表中并不存在对应的列,我们增加一个自定义的注释并对LanguageDriver的实现稍作修改:

public class User{
    ...

    @Invisible
    private UserSearchDO userSearchDO;
    
    ...
}
/**
 * Created by benxue on 3/10/16.
 * The field marked as Invisible will not be scanned by customized simple extended language drivers
 * of myBatis
 */
(ElementType.FIELD)
(RetentionPolicy.RUNTIME)
public  Invisible {
}

总结

通过实现LanguageDriver,我们可以实现方便的自定义注解。在遵循一些约定的情况下(e.g. Domain使用驼峰命名法,数据库表使用下划线命名法),就可以和麻烦的XML配置和动态SQL编写say 88了:)

// 清爽的数据库操作

	@Select("SELECT * FROM user WHERE user_id IN (#{userIds})")
    @Lang(SimpleSelectInExtendedLanguageDriver.class)
    List<User> getUsers(@Param("userIds") List<Long> userIds);

	@Update("UPDATE user (#{user}) WHERE user_id =#{userId}")
    @Lang(SimpleUpdateExtendedLanguageDriver.class)
    int updateUser(User user);

	@Insert("INSERT INTO user (#{user})")
    @Lang(SimpleInsertExtendedLanguageDriver.class)
    void insertUser(User user);

@二憨(erhan-o0jde):tips: 可以去除最后的逗号,prefix可以自定义被包裹的语句的开头语句。

@One/@Many

@Result(property = "details", many = @Many(resultMap = "1001detailMap", columnPrefix = "s_"))
resultmap 结果集对应的ID
columnPrefix 回参列前缀,会为 resultmap 中的所有列名都加上一个 s_ 前缀,这样一来就能匹配上联合查询 SQL 语句中实际返回的列名(例如 s_id)了。

@MapKey

使返回值为Map-string,object模式

为键值 指定 java.util.Map属性名称(或列名称)的批注。
如何使用:
  public interface UserMapper {
    @MapKey("id")
    @Select("SELECT id, name FROM users WHERE name LIKE #{name} || '%")
    Map<Integer, User> selectByStartingWithName(String name);
  }

@Options

参数含义默认值
useCache是否使用第二个缓存功能true
flushCache第二个缓存刷新策略FlushCachePolicy.DEFAULT
resultSetType结果集类型ResultSetType.DEFAULT
statementType语句类型StatementType.PREPARED
fetchSize提取大小-1
timeout语句超时-1
useGeneratedKeys是否使用 JDBC 3.0 支持的生成密钥功能false
keyProperty保存键值的属性名称
keyColumn检索键值的列名
resultSets结果集名称

@二憨(erhan-o0jde)tips:md |:---- 用于区分表头和表数据


@SelectKey

在Oracle中使用SelectKey生成主键,通常是“先查询得到主键,再进行插入”
所以这里before=true
如果是MySQL,可以用select last_insert_id()语句获取新插入数据的主键

Mybatis中的@SelectKey注解_dejing6575的博客-CSDN博客

指定用于检索键值的 SQL 的注释。
如何使用:
  public interface UserMapper {
    @SelectKey(statement = "SELECT identity('users')", keyProperty = "id", before = true, resultType = int.class)
    @Insert("INSERT INTO users (id, name) VALUES(#{id}, #{name})")
    boolean insert(User user);
  }

自定义MyBatis Generator Plugin

在自定义插件中,你可以重写多个方法来处理不同类型的生成文件。以下是一些常用的方法:
clientGenerated: 生成Java Client接口(Mapper接口)文件时调用。
modelGenerated: 生成Java模型(实体类)文件时调用。
sqlMapGenerated: 生成XML映射文件时调用。
contextGenerateAdditionalJavaFiles: 在生成Java文件时调用,可以自定义生成额外的Java文件。
contextGenerateAdditionalXmlFiles: 在生成XML文件时调用,可以自定义生成额外的XML文件。
你可以根据自己的需求选择适当的方法重写,并在其中处理相应的生成文件。例如,如果你想在生成Java Client接口时进行额外的处理,可以重写clientGenerated方法;如果想在生成Java模型文件时进行特定操作,可以重写modelGenerated方法。

image.png
使用方法:以插件一为例:
1.全java代码:

package com.jhj.plugin.test;

import org.junit.Before;
import org.junit.Test;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * 类描述:TODO
 *
 * @author dxsc_jhj
 * @date 2023-05-23 20:26
 **/
@SpringBootTest()
// @RunWith()
public class TestGenerator {
    private File configFile;

    @Before
    public void before() {
    	String path = "generatorConfig.xml";// 你的配置文件 - 建议绝对位置
        //读取mybatis参数 
        configFile = new File(path);
    }

    @Test
    public void test() throws Exception{
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        myBatisGenerator.generate(null);
    }
}

顺带发一波生成器的配置文件介绍带本次的配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!-- 配置生成器 -->
<generatorConfiguration>

    <!--  数据库驱动位置-->
    <classPathEntry location="D:\environment\apache-maven-3.6.3\maven-repository\mysql\mysql-connector-java\8.0.11\mysql-connector-java-8.0.11.jar"/>

    <!-- 可以用于加载配置项或者配置文件,在整个配置文件中就可以使用${propertyKey}的方式来引用配置项
        resource:配置资源加载地址,使用resource,MBG从classpath开始找,比如com/myproject/generatorConfig.properties
        url:配置资源加载地质,使用URL的方式,比如file:///C:/myfolder/generatorConfig.properties.
        注意,两个属性只能选址一个;

        另外,如果使用了mybatis-generator-maven-plugin,那么在pom.xml中定义的properties都可以直接在generatorConfig.xml中使用
    <properties resource="" url="" />
     -->

    <!-- 在MBG工作的时候,需要额外加载的依赖包
       location属性指明加载jar/zip包的全路径
   <classPathEntry location="/Program Files/IBM/SQLLIB/java/db2java.zip" />
     -->

    <!--
        context:生成一组对象的环境
        id:必选,上下文id,用于在生成错误时提示
        defaultModelType:指定生成对象的样式
            1,conditional:类似hierarchical;
            2,flat:所有内容(主键,blob)等全部生成在一个对象中;
            3,hierarchical:主键生成一个XXKey对象(key class),Blob等单独生成一个对象,其他简单属性在一个对象中(record class)
        targetRuntime:
            1,MyBatis3:默认的值,生成基于MyBatis3.x以上版本的内容,包括XXXBySample;
            2,MyBatis3Simple:类似MyBatis3,只是不生成XXXBySample;
        introspectedColumnImpl:类全限定名,用于扩展MBG
    -->
    <context id="mysql" defaultModelType="flat" targetRuntime="MyBatis3" >

        <!-- 自动识别数据库关键字,默认false,如果设置为true,根据SqlReservedWords中定义的关键字列表;
            一般保留默认值,遇到数据库关键字(Java关键字),使用columnOverride覆盖
         -->
        <property name="autoDelimitKeywords" value="false"/>
        <!-- 生成的Java文件的编码 -->
        <property name="javaFileEncoding" value="UTF-8"/>
        <!-- 格式化java代码 -->
        <property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter"/>
        <!-- 格式化XML代码 -->
        <property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter"/>

        <!-- beginningDelimiter和endingDelimiter:指明数据库的用于标记数据库对象名的符号,比如ORACLE就是双引号,MYSQL默认是`反引号; -->
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>

      	<!-- 此处引入了所需的插件部分-->
        <plugin type="com.jhj.plugin.generator.MyPlugin">
        </plugin>
        <!--<plugin type="com.jhj.plugin.generator.MyControllerPlugin" >-->
        <!--    <property name="targetProject" value="D:\Projects\mybatis-generator"/>-->
        <!--    <property name="servicePackage" value="service"/>-->
        <!--    <property name="serviceImplPackage" value="service.impl"/>-->
        <!--    <property name="controllerPackage" value="controller"/>-->
        <!--    &lt;!&ndash;UserService,该值则为Service&ndash;&gt;-->
        <!--    <property name="serviceSuffix" value="Service"/>-->
        <!--    &lt;!&ndash;Service接口的父接口&ndash;&gt;-->
        <!--    <property name="superServiceInterface" value="org.aurochsframework.boot.commons.service.GeneralService"/>-->
        <!--    &lt;!&ndash;ServiceImpl的父类&ndash;&gt;-->
        <!--    <property name="superServiceImpl" value="org.aurochsframework.boot.commons.service.AbstractGeneralService"/>-->
        <!--    &lt;!&ndash;controller的父类接口&ndash;&gt;-->
        <!--    <property name="superController" value="org.aurochsframework.boot.commons.controller.GeneralCrudController"/>-->
        <!--</plugin>-->

        <!--用于定义属性的注释生成器。 注释生成器生成注释用于生成的各种元素 MyBatis发生器(MBG) (Java字段,Java方法,XML元素,等等)。
                    默认的注释生成器将JavaDoc注释添加到所有生成的Java元素使 Java合并功能在Eclipse插件。
                    同时,注解被添加到每个生成的XML元素。 注解的目的是通知用户 元素生成并受再生(例如,他们不应该 改变)。-->
        <commentGenerator>
            <!--当属性为 false 或未指定时,所有生成的 elelment 都将包含指示元素是生成元素的注释。当该属性为 true 时,不会向任何生成的元素添加任何注释。-->
            <property name="suppressAllComments" value="true" />
            <!--当属性为 false 或未指定时,所有生成的注释都将包含生成元素时的时间戳。 当该属性为 true 时,不会向生成的注释添加时间戳-->
            <!--<property name="suppressDate" value="true" />-->
            <!--当属性为 false 或未指定时,所有生成的评论 将 不 包括来自数据库表的表和列的言论 当生成的元素。 当该属性为 true 时,表和列的言论从数据库表 将被添加到生成的评论。-->
            <!--<property name="addRemarkComments" value="true" />-->
            <!--日期格式的字符串时使用写作日期到生成的评论。 这个字符串 将被用来构造一个吗 java.text.SimpleDateFormat 对象。 任何 有效的格式字符串的对象可以在这里指定。
                默认情况下,字符串的日期 将从 toString () 方法 java.util.Date .-->
            <!--<property name="dateFormat" value="true" />-->
        </commentGenerator>

        <!-- 必须要有的,使用这个配置链接数据库
            @TODO:是否可以扩展
         -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="jdbc:mysql://192.168.30.131:3306/camera_sdk?serverTimezone=Asia/Shanghai&amp;useSSL=false" userId="root" password="123456">
            <!-- 这里面可以设置property属性,每一个property属性都设置到配置的Driver上 -->
        </jdbcConnection>

        <!-- java类型处理器
            用于处理DB中的类型到Java中的类型,默认使用JavaTypeResolverDefaultImpl;
            注意一点,默认会先尝试使用Integer,Long,Short等来对应DECIMAL和 NUMERIC数据类型;
        -->
        <javaTypeResolver type="org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl">
            <!--
                true:使用BigDecimal对应DECIMAL和 NUMERIC数据类型
                false:默认,
                    scale>0;length>18:使用BigDecimal;
                    scale=0;length[10,18]:使用Long;
                    scale=0;length[5,9]:使用Integer;
                    scale=0;length<5:使用Short;
             -->
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>


        <!-- java模型创建器,是必须要的元素
            负责:1,key类(见context的defaultModelType);2,java类;3,查询类
            targetPackage:生成的类要放的包,真实的包受enableSubPackages属性控制;
            targetProject:目标项目,指定一个存在的目录下,生成的内容会放到指定目录中,如果目录不存在,MBG不会自动建目录
         -->
        <javaModelGenerator targetPackage="xxx" targetProject="D:\Projects\mybatis-generator">
            <!--  for MyBatis3/MyBatis3Simple
                自动为每一个生成的类创建一个构造方法,构造方法包含了所有的field;而不是使用setter;
             -->
            <property name="constructorBased" value="false"/>

            <!-- 在targetPackage的基础上,根据数据库的schema再生成一层package,最终生成的类放在这个package下,默认为false -->
            <property name="enableSubPackages" value="true"/>

            <!-- for MyBatis3 / MyBatis3Simple
                是否创建一个不可变的类,如果为true,
                那么MBG会创建一个没有setter方法的类,取而代之的是类似constructorBased的类
             -->
            <property name="immutable" value="false"/>

            <!-- 设置一个根对象,
                如果设置了这个根对象,那么生成的keyClass或者recordClass会继承这个类;在Table的rootClass属性中可以覆盖该选项
                注意:如果在key class或者record class中有root class相同的属性,MBG就不会重新生成这些属性了,包括:
                    1,属性名相同,类型相同,有相同的getter/setter方法;
             -->
            <!--<property name="rootClass" value="domain.BaseDomain"/>-->

            <!-- 设置是否在getter方法中,对String类型字段调用trim()方法 -->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <!-- 生成SQL map的XML文件生成器,
            注意,在Mybatis3之后,我们可以使用mapper.xml文件+Mapper接口(或者不用mapper接口),
                或者只使用Mapper接口+Annotation,所以,如果 javaClientGenerator配置中配置了需要生成XML的话,这个元素就必须配置
            targetPackage/targetProject:同javaModelGenerator
         -->
        <sqlMapGenerator targetPackage="xxx" targetProject="D:\Projects\mybatis-generator">
            <!-- 在targetPackage的基础上,根据数据库的schema再生成一层package,最终生成的类放在这个package下,默认为false -->
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>

        <!-- !!!对于mybatis来说,即生成Mapper接口,注意,如果没有配置该元素,那么默认不会生成Mapper.xml
            targetPackage/targetProject:同javaModelGenerator
            type:选择怎么生成mapper接口(在MyBatis3/MyBatis3Simple下):
                1,ANNOTATEDMAPPER:会生成使用Mapper接口+Annotation的方式创建(SQL生成在annotation中),不会生成对应的XML;
                2,MIXEDMAPPER:使用混合配置,会生成Mapper接口,并适当添加合适的Annotation,但是XML会生成在XML中;
                3,XMLMAPPER:会生成Mapper接口,接口完全依赖XML;
            注意,如果context是MyBatis3Simple:只支持ANNOTATEDMAPPER和XMLMAPPER
        -->
        <javaClientGenerator targetPackage="mapper" type="ANNOTATEDMAPPER" targetProject="D:\Projects\mybatis-generator">
            <!-- 在targetPackage的基础上,根据数据库的schema再生成一层package,最终生成的类放在这个package下,默认为false -->
            <property name="enableSubPackages" value="false"/>

            <!-- 可以为所有生成的接口添加一个父接口,但是MBG只负责生成,不负责检查
            <property name="rootInterface" value=""/>
             -->
        </javaClientGenerator>

        <!-- 选择一个table来生成相关文件,可以有一个或多个table,必须要有table元素
            选择的table会生成一下文件:
            1,SQL map文件
            2,生成一个主键类;
            3,除了BLOB和主键的其他字段的类;
            4,包含BLOB的类;
            5,一个用户生成动态查询的条件类(selectByExample, deleteByExample),可选;
            6,Mapper接口(可选)

            tableName(必要):要生成对象的表名;
            注意:大小写敏感问题。正常情况下,MBG会自动的去识别数据库标识符的大小写敏感度,在一般情况下,MBG会
                根据设置的schema,catalog或tablename去查询数据表,按照下面的流程:
                1,如果schema,catalog或tablename中有空格,那么设置的是什么格式,就精确的使用指定的大小写格式去查询;
                2,否则,如果数据库的标识符使用大写的,那么MBG自动把表名变成大写再查找;
                3,否则,如果数据库的标识符使用小写的,那么MBG自动把表名变成小写再查找;
                4,否则,使用指定的大小写格式查询;
            另外的,如果在创建表的时候,使用的""把数据库对象规定大小写,就算数据库标识符是使用的大写,在这种情况下也会使用给定的大小写来创建表名;
            这个时候,请设置delimitIdentifiers="true"即可保留大小写格式;

            可选:
            1,schema:数据库的schema;
            2,catalog:数据库的catalog;
            3,alias:为数据表设置的别名,如果设置了alias,那么生成的所有的SELECT SQL语句中,列名会变成:alias_actualColumnName
            4,domainObjectName:生成的domain类的名字,如果不设置,直接使用表名作为domain类的名字;可以设置为somepck.domainName,那么会自动把domainName类再放到somepck包里面;
            5,enableInsert(默认true):指定是否生成insert语句;
            6,enableSelectByPrimaryKey(默认true):指定是否生成按照主键查询对象的语句(就是getById或get);
            7,enableSelectByExample(默认true):MyBatis3Simple为false,指定是否生成动态查询语句;
            8,enableUpdateByPrimaryKey(默认true):指定是否生成按照主键修改对象的语句(即update);
            9,enableDeleteByPrimaryKey(默认true):指定是否生成按照主键删除对象的语句(即delete);
            10,enableDeleteByExample(默认true):MyBatis3Simple为false,指定是否生成动态删除语句;
            11,enableCountByExample(默认true):MyBatis3Simple为false,指定是否生成动态查询总条数语句(用于分页的总条数查询);
            12,enableUpdateByExample(默认true):MyBatis3Simple为false,指定是否生成动态修改语句(只修改对象中不为空的属性);
            13,modelType:参考context元素的defaultModelType,相当于覆盖;
            14,delimitIdentifiers:参考tableName的解释,注意,默认的delimitIdentifiers是双引号,如果类似MYSQL这样的数据库,使用的是`(反引号,那么还需要设置context的beginningDelimiter和endingDelimiter属性)
            15,delimitAllColumns:设置是否所有生成的SQL中的列名都使用标识符引起来。默认为false,delimitIdentifiers参考context的属性

            注意,table里面很多参数都是对javaModelGenerator,context等元素的默认属性的一个复写;
         -->
        <table tableName="xxx" domainObjectName="xxx" delimitIdentifiers="true" enableCountByExample="true" enableDeleteByExample="true" enableSelectByExample="true" enableUpdateByExample="true" selectByExampleQueryId="true">

            <columnOverride column="xxx" property="xxx"/>

            <!-- 参考 javaModelGenerator 的 constructorBased属性-->
            <!--<property name="constructorBased" value="false"/>-->

            <!-- 默认为false,如果设置为true,在生成的SQL中,table名字不会加上catalog或schema; -->
            <!--<property name="ignoreQualifiersAtRuntime" value="false"/>-->

            <!-- 参考 javaModelGenerator 的 immutable 属性 -->
            <!--<property name="immutable" value="false"/>-->

            <!-- 指定是否只生成domain类,如果设置为true,只生成domain类,如果还配置了sqlMapGenerator,那么在mapper XML文件中,只生成resultMap元素 -->
            <!--<property name="modelOnly" value="false"/>-->

            <!-- 参考 javaModelGenerator 的 rootClass 属性
            <property name="rootClass" value=""/>
             -->

            <!-- 参考javaClientGenerator 的  rootInterface 属性
            <property name="rootInterface" value=""/>
            -->

            <!-- 如果设置了runtimeCatalog,那么在生成的SQL中,使用该指定的catalog,而不是table元素上的catalog
            <property name="runtimeCatalog" value=""/>
            -->

            <!-- 如果设置了runtimeSchema,那么在生成的SQL中,使用该指定的schema,而不是table元素上的schema
            <property name="runtimeSchema" value=""/>
            -->

            <!-- 如果设置了runtimeTableName,那么在生成的SQL中,使用该指定的tablename,而不是table元素上的tablename
            <property name="runtimeTableName" value=""/>
            -->

            <!-- 注意,该属性只针对MyBatis3Simple有用;
                如果选择的runtime是MyBatis3Simple,那么会生成一个SelectAll方法,如果指定了selectAllOrderByClause,那么会在该SQL中添加指定的这个order条件;
             -->
            <!--<property name="selectAllOrderByClause" value="age desc,username asc"/>-->

            <!-- 如果设置为true,生成的model类会直接使用column本身的名字,而不会再使用驼峰命名方法,比如BORN_DATE,生成的属性名字就是BORN_DATE,而不会是bornDate -->
            <!--<property name="useActualColumnNames" value="true"/>-->

            <!-- generatedKey用于生成生成主键的方法,
                如果设置了该元素,MBG会在生成的<insert>元素中生成一条正确的<selectKey>元素,该元素可选
                column:主键的列名;
                sqlStatement:要生成的selectKey语句,有以下可选项:
                    Cloudscape:相当于selectKey的SQL为: VALUES IDENTITY_VAL_LOCAL()
                    DB2       :相当于selectKey的SQL为: VALUES IDENTITY_VAL_LOCAL()
                    DB2_MF    :相当于selectKey的SQL为:SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1
                    Derby     :相当于selectKey的SQL为:VALUES IDENTITY_VAL_LOCAL()
                    HSQLDB    :相当于selectKey的SQL为:CALL IDENTITY()
                    Informix  :相当于selectKey的SQL为:select dbinfo('sqlca.sqlerrd1') from systables where tabid=1
                    MySql     :相当于selectKey的SQL为:SELECT LAST_INSERT_ID()
                    SqlServer :相当于selectKey的SQL为:SELECT SCOPE_IDENTITY()
                    SYBASE    :相当于selectKey的SQL为:SELECT @@IDENTITY
                    JDBC      :相当于在生成的insert元素上添加useGeneratedKeys="true"和keyProperty属性
            <generatedKey column="" sqlStatement=""/>
             -->

            <!--
                该元素会在根据表中列名计算对象属性名之前先重命名列名,非常适合用于表中的列都有公用的前缀字符串的时候,
                比如列名为:CUST_ID,CUST_NAME,CUST_EMAIL,CUST_ADDRESS等;
                那么就可以设置searchString为"^CUST_",并使用空白替换,那么生成的Customer对象中的属性名称就不是
                custId,custName等,而是先被替换为ID,NAME,EMAIL,然后变成属性:id,name,email;

                注意,MBG是使用java.util.regex.Matcher.replaceAll来替换searchString和replaceString的,
                如果使用了columnOverride元素,该属性无效;

            <columnRenamingRule searchString="" replaceString=""/>
             -->

            <!-- 用来修改表中某个列的属性,MBG会使用修改后的列来生成domain的属性;
               column:要重新设置的列名;
               注意,一个table元素中可以有多个columnOverride元素哈~
             -->
            <!--<columnOverride column="startTime">-->
            <!--    &lt;!&ndash; 使用property属性来指定列要生成的属性名称 &ndash;&gt;-->
            <!--    <property name="property" value="startTime"/>-->

            <!--    &lt;!&ndash; javaType用于指定生成的domain的属性类型,使用类型的全限定名-->
            <!--    <property name="javaType" value=""/>-->
            <!--     &ndash;&gt;-->

            <!--    &lt;!&ndash; jdbcType用于指定该列的JDBC类型-->
            <!--    <property name="jdbcType" value=""/>-->
            <!--     &ndash;&gt;-->

            <!--    &lt;!&ndash; typeHandler 用于指定该列使用到的TypeHandler,如果要指定,配置类型处理器的全限定名-->
            <!--        注意,mybatis中,不会生成到mybatis-config.xml中的typeHandler-->
            <!--        只会生成类似:where id = #{id,jdbcType=BIGINT,typeHandler=com._520it.mybatis.MyTypeHandler}的参数描述-->
            <!--    <property name="jdbcType" value=""/>-->
            <!--    &ndash;&gt;-->

            <!--    &lt;!&ndash; 参考table元素的delimitAllColumns配置,默认为false-->
            <!--    <property name="delimitedColumnName" value=""/>-->
            <!--     &ndash;&gt;-->
            <!--</columnOverride>-->

            <!-- ignoreColumn设置一个MGB忽略的列,如果设置了改列,那么在生成的domain中,生成的SQL中,都不会有该列出现
               column:指定要忽略的列的名字;
               delimitedColumnName:参考table元素的delimitAllColumns配置,默认为false

               注意,一个table元素中可以有多个ignoreColumn元素
            <ignoreColumn column="deptId" delimitedColumnName=""/>
            -->
        </table>

    </context>

</generatorConfiguration>

2.pom引入插件 真心不推荐doge

插件1:自定义生成insert/select/update方法,有点小问题就是需要手动改一下参数类型

package com.jhj.plugin.generator;

import org.mybatis.generator.api.*;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.internal.util.StringUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.sql.JDBCType;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class MyPlugin extends PluginAdapter {
    private static final Logger logger = LoggerFactory.getLogger(MyPlugin.class);

    public MyPlugin() {
    }

    private static final String USEGENERATEDKEYS = "useGeneratedKeys";
    private static final String KEYCOLUMN = "keyColumn";
    private static final String KEYPROPERTY = "keyProperty";
    private static final String IS_GEN_USEGENERATEDKEYS = "my.isgen.usekeys";

    @Override
    public boolean validate(List<String> warnings) {
        logger.info("--- MyPlugin validate invoke");
        return true;
    }

    @Override
    public boolean clientInsertSelectiveMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        // 获取表的列信息
        logger.info("调用-clientInsertSelectiveMethodGenerated");
        List<IntrospectedColumn> columns = introspectedTable.getAllColumns();

        // 构造SQL语句的VALUES子句
        StringBuilder valuesClause = new StringBuilder();
        valuesClause.append("\t\t\"<trim prefix=\'VALUES (\' suffixOverrides=\',\' suffix=\')\'> \",\n");
        StringBuilder columnsClause = new StringBuilder();
        columnsClause.append("\t\t\"<trim prefix=\'(\' suffixOverrides=\',\' > suffix=\')\' \",\n");
        for (IntrospectedColumn column : columns) {
            String propertyName = column.getJavaProperty();
            String columnName = column.getActualColumnName();

            // 添加列的判断和赋值
            columnsClause.append("\t\t\"<if test=\'").append(propertyName).append(" != null\'>\",\n");
            columnsClause.append("\t\t\"").append(columnName).append(",\",\n");
            columnsClause.append("\t\t\"</if>\",\n");

            // 添加列值的判断和赋值
            valuesClause.append("\t\t\"<if test=\'").append(propertyName).append(" != null\'>\",\n");
            valuesClause.append("\t\t\"#{").append(propertyName).append(", jdbcType=").append(column.getJdbcTypeName()).append("},\",\n");
            valuesClause.append("\t\t\"</if>\",\n");
        }
        valuesClause.append("\t\t\"</trim>\",\n");
        columnsClause.append("\t\t\"</trim>\",\n");
        StringBuilder sql = columnsClause.append(valuesClause);

        // 修改@Insert注解中的value属性
        List<String> annotations = method.getAnnotations();
        for (int i = 0; i < annotations.size(); i++) {
            String annotation = annotations.get(i);
            if (annotation.startsWith("@Insert")) {
                StringBuilder annotationSb = new StringBuilder();
                annotationSb.append("@Insert(value = {\"<script>\",\n\t\t\"INSERT INTO *** values \t\"</script>\"})");
                String annotationSt = annotationSb.toString();
                // 替换INSERT INTO后面的部分,并在VALUES子句中插入列的判断和赋值
                String modifiedAnnotation = annotationSt.replaceFirst("(?i)INSERT INTO \\S+", "INSERT INTO " + introspectedTable.getFullyQualifiedTableNameAtRuntime()+"\",\n");
                modifiedAnnotation = modifiedAnnotation.replaceFirst("(?i)VALUES[ \\(]",  sql.toString() + " ");
                annotations.set(i, modifiedAnnotation);
                break;
            }
        }

        return true;
    }

    @Override
    public boolean clientUpdateByPrimaryKeySelectiveMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        // 获取表的列信息
        logger.info("调用-clientUpdateByPrimaryKeySelectiveMethodGenerated");
        List<IntrospectedColumn> columns = introspectedTable.getAllColumns();

        // 构造SQL语句的VALUES子句
        StringBuilder sql = new StringBuilder();
        sql.append("\t\t\"<set>\",\n");
        for (IntrospectedColumn column : columns) {
            String propertyName = column.getJavaProperty();
            String columnName = column.getActualColumnName();

            // 添加列的判断和赋值
            sql.append("\t\t\"<if test=\'").append(propertyName).append(" != null\'>\",\n");
            sql.append("\t\t\"").append(columnName).append(" = ").append("#{").append(propertyName).append(", jdbcType=").append(column.getJdbcTypeName()).append("}, \",\n");
            sql.append("\t\t\"</if>\",\n");
        }
        sql.append("\t\t\"</set>\",\n");
        List<IntrospectedColumn> primaryKeyColumns = introspectedTable.getPrimaryKeyColumns();
        applyWhere(primaryKeyColumns, sql);

        // 修改@Insert注解中的value属性
        List<String> annotations = method.getAnnotations();
        for (int i = 0; i < annotations.size(); i++) {
            String annotation = annotations.get(i);
            if (annotation.startsWith("@Update")) {
                StringBuilder annotationSb = new StringBuilder();
                annotationSb.append("@Update(value = {\"<script>\",\n\t\t\"UPDATE_SQL *** SET \t\"</script>\"})");
                String annotationSt = annotationSb.toString();
                // 替换INSERT INTO后面的部分,并在VALUES子句中插入列的判断和赋值
                String modifiedAnnotation = annotationSt.replaceFirst("(?i)UPDATE_SQL \\S+", "UPDATE " + introspectedTable.getFullyQualifiedTableNameAtRuntime()+"\",\n");
                modifiedAnnotation = modifiedAnnotation.replaceFirst("(?i)SET[ \\(]",  sql.toString() + " ");
                annotations.set(i, modifiedAnnotation);
                break;
            }
        }

        return true;
    }

    @Override
    public boolean clientSelectByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        // 获取表的列信息
        logger.info("调用-clientSelectByExampleWithoutBLOBsMethodGenerated");
        List<IntrospectedColumn> columns = introspectedTable.getAllColumns();

        // 构造SQL语句的WHERE子句
        StringBuilder sql = new StringBuilder();
        applyWhere(columns, sql);

        // 修改@Insert注解中的value属性
        List<String> annotations = method.getAnnotations();
        for (int i = 0; i < annotations.size(); i++) {
            String annotation = annotations.get(i);
            if (annotation.startsWith("@Select")) {
                StringBuilder annotationSb = new StringBuilder();
                annotationSb.append("@Select(value = {\"<script>\",\n\t\t\"SELECT_SQL *** WHERE \t\"</script>\"})");
                String annotationSt = annotationSb.toString();
                // 替换INSERT INTO后面的部分,并在VALUES子句中插入列的判断和赋值
                String modifiedAnnotation = annotationSt.replaceFirst("(?i)SELECT_SQL \\S+", "SELECT * FROM " + introspectedTable.getFullyQualifiedTableNameAtRuntime()+"\",\n");
                modifiedAnnotation = modifiedAnnotation.replaceFirst("(?i)WHERE[ \\(]",  sql.toString() + " ");
                annotations.set(i, modifiedAnnotation);
                break;
            }
        }

        return true;
    }

    @Override
    public boolean clientCountByExampleMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        // 获取表的列信息
        logger.info("调用-clientCountByExampleMethodGenerated");
        List<IntrospectedColumn> columns = introspectedTable.getAllColumns();

        // 构造SQL语句的WHERE子句
        StringBuilder sql = new StringBuilder();
        applyWhere(columns, sql);

        // 修改@Insert注解中的value属性
        List<String> annotations = method.getAnnotations();
        for (int i = 0; i < annotations.size(); i++) {
            String annotation = annotations.get(i);
            if (annotation.startsWith("@Select")) {
                StringBuilder annotationSb = new StringBuilder();
                annotationSb.append("@Select(value = {\"<script>\",\n\t\t\"SELECT_SQL *** WHERE \t\"</script>\"})");
                String annotationSt = annotationSb.toString();
                // 替换INSERT INTO后面的部分,并在VALUES子句中插入列的判断和赋值
                String modifiedAnnotation = annotationSt.replaceFirst("(?i)SELECT_SQL \\S+", "SELECT COUNT(1) FROM " + introspectedTable.getFullyQualifiedTableNameAtRuntime()+"\",\n");
                modifiedAnnotation = modifiedAnnotation.replaceFirst("(?i)WHERE[ \\(]",  sql.toString() + " ");
                annotations.set(i, modifiedAnnotation);
                break;
            }
        }

        return true;
    }

    @Override
    public boolean clientDeleteByExampleMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        // 获取表的列信息
        logger.info("调用-clientDeleteByExampleMethodGenerated");
        List<IntrospectedColumn> columns = introspectedTable.getAllColumns();

        // 构造SQL语句的WHERE子句
        StringBuilder sql = new StringBuilder();
        applyWhere(columns, sql);

        // 修改@Insert注解中的value属性
        List<String> annotations = method.getAnnotations();
        for (int i = 0; i < annotations.size(); i++) {
            String annotation = annotations.get(i);
            if (annotation.startsWith("@Delete")) {
                StringBuilder annotationSb = new StringBuilder();
                annotationSb.append("@Delete(value = {\"<script>\",\n\t\t\"DELETE_SQL *** WHERE \t\"</script>\"})");
                String annotationSt = annotationSb.toString();
                // 替换INSERT INTO后面的部分,并在VALUES子句中插入列的判断和赋值
                String modifiedAnnotation = annotationSt.replaceFirst("(?i)DELETE_SQL \\S+", "DELETE FROM " + introspectedTable.getFullyQualifiedTableNameAtRuntime()+"\",\n");
                modifiedAnnotation = modifiedAnnotation.replaceFirst("(?i)WHERE[ \\(]",  sql.toString() + " ");
                annotations.set(i, modifiedAnnotation);
                break;
            }
        }

        return true;
    }

    @Override
    public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        // 获取所有方法
        Iterator<Method> methods = interfaze.getMethods().iterator();

        // 需要删除的方法名列表
        List<String> methodNamesToDelete = new ArrayList<>();
        methodNamesToDelete.add("insert");
        methodNamesToDelete.add("updateByPrimaryKey");
        methodNamesToDelete.add("updateByExample");
        methodNamesToDelete.add("updateByExampleSelective");

        // 删除指定方法
        while (methods.hasNext()){
            Method method = methods.next();
            if (methodNamesToDelete.contains(method.getName())) {
                methods.remove();
            }
        }
        return true;
    }

    /**
     * 该方法在每一个mapper.xml文件的insert节点生成是调用,我们要做的就是判断是否要插入三个属性,
     * 如果需要插入,就往XmlElement添加三个元素即可;
     */
    public boolean sqlMapInsertSelectiveElementGenerated(XmlElement element,
                                                         IntrospectedTable introspectedTable) {

        logger.info("调用sqlMapInsertSelectiveElementGenerated");

        //定义是否需要生成三个属性
        boolean isGen = true;
        //调用getTableConfigurationProperty方法,得到在当前这个table中定义的property元素
        //直接去尝试获取my.isgen.usekeys property;
        String isGenStr = introspectedTable
                .getTableConfigurationProperty(IS_GEN_USEGENERATEDKEYS);
        //如果得到了值,就尝试转化成boolean
        if (StringUtility.stringHasValue(isGenStr)) {
            isGen = Boolean.valueOf(isGenStr);
        }
        //如果需要生成参数
        if (isGen) {
            // 要使用usegeneratedkeys只能有一个主键,并且主键的类型必须是数字类型;
            //通过introspectedTable的getPrimaryKeyColumns方法得到解析出来数据库中的主键列;
            //因为主键列可能是多个,所以返回的是List<IntrospectedColumn>
            List<IntrospectedColumn> keyColumns = introspectedTable
                    .getPrimaryKeyColumns();
            IntrospectedColumn keyColumn = null;
            //对于usegeneratedkeys来说,只能有一个主键列;
            if (keyColumns.size() == 1) {
                //得到这个唯一的主键列
                keyColumn = keyColumns.get(0);
                //得到这个列映射成Java模型之后的属性对应的Java类型;
                FullyQualifiedJavaType javaType = keyColumn
                        .getFullyQualifiedJavaType();
                //usegeneratedkeys要求主键只能是递增的,所以我们把这个主键属性的类型分别和Integer,Long,Short做对比;
                if (javaType.equals(PrimitiveTypeWrapper.getIntegerInstance())
                        || javaType.equals(PrimitiveTypeWrapper
                        .getLongInstance())
                        || javaType.equals(PrimitiveTypeWrapper
                        .getShortInstance())) {
                    //如果是Integer,Long,Short三个类型中的而一个;则添加属性;
                    //因为我们要添加的属性就是insert元素上的,而insert元素就是根节点,所以element就是insert元素;
                    element.addAttribute(new Attribute(USEGENERATEDKEYS, "true"));
                    //通过IntrospectedColumn的getActualColumnName得到列中的名称,用于生成keyColumn属性;
                    element.addAttribute(new Attribute(KEYCOLUMN, keyColumn
                            .getActualColumnName()));
                    //通过IntrospectedColumn的getJavaProperty方法得到key在Java对象中的属性名,用于生成keyProperty属性
                    element.addAttribute(new Attribute(KEYPROPERTY, keyColumn
                            .getJavaProperty()));
                }
            }
        }
        //打完收工
        return true;
    }

    @Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {
        // 删除生成的 SqlProvider 类文件
        logger.info("删除生成的 SqlProvider 类文件");
        String targetDir = context.getJavaClientGeneratorConfiguration().getTargetProject();
        String targetPackage = context.getJavaClientGeneratorConfiguration().getTargetPackage();
        String packages = introspectedTable.getMyBatis3SqlProviderType();
        // String className = packages[packages.length - 1];
        String fileName = targetDir + "\\" + packages.replace(".", "\\")  + ".java";

        File file = new File(fileName);
        if (file.exists()) {
            file.delete();
        }

        return null;
    }

    protected void applyWhere(List<IntrospectedColumn> clumns, StringBuilder sql) {
        sql.append("\t\t\"<where>\",\n");
        for (IntrospectedColumn column : clumns) {
            String propertyName = column.getJavaProperty();
            String columnName = column.getActualColumnName();

            // 添加列的判断和赋值
            if(column.getJdbcTypeName() == JDBCType.VARCHAR.getName())
                sql.append("\t\t\"<if test=\\\\\"").append(propertyName).append(" != null and ").append(propertyName).append(" != '' ").append("\\\\\">\\\",\n");
            else
                sql.append("\t\t\"<if test=\\\\\"").append(propertyName).append(" != null\\\\\">\",\n");
            sql.append("\t\t\"and ").append(columnName).append(" = ").append("#{").append(propertyName).append(", jdbcType=").append(column.getJdbcTypeName()).append("}\",\n");
            sql.append("\t\t\"</if>\",\n");
        }
        sql.append("\t\t\"</where>\",\n");
    }
}

插件2:听听你们需求

Mybatis-Plus

LambdaWrapper获取其字段属性名称的源代码部分,列如:USER::GETRUERNAME 通过get/set/is为开头来读取

	// AbstractLambdaWrapper.java
	/**
     * 获取 SerializedLambda 对应的列信息,从 lambda 表达式中推测实体类
     * <p>
     * 如果获取不到列信息,那么本次条件组装将会失败
     *
     * @return 列
     * @throws com.baomidou.mybatisplus.core.exceptions.MybatisPlusException 获取不到列信息时抛出异常
     */
    protected ColumnCache getColumnCache(SFunction<T, ?> column) {
        LambdaMeta meta = LambdaUtils.extract(column);
        String fieldName = PropertyNamer.methodToProperty(meta.getImplMethodName());
        Class<?> instantiatedClass = meta.getInstantiatedClass();
        tryInitCache(instantiatedClass);
        return getColumnCache(fieldName, instantiatedClass);
    }
	// ------------------------------------------------------------
	/**
     * 该缓存可能会在任意不定的时间被清除
     *
     * @param func 需要解析的 lambda 对象
     * @param <T>  类型,被调用的 Function 对象的目标类型
     * @return 返回解析后的结果
     */
    public static <T> LambdaMeta extract(SFunction<T, ?> func) {
        // 1. IDEA 调试模式下 lambda 表达式是一个代理
        if (func instanceof Proxy) {
            return new IdeaProxyLambdaMeta((Proxy) func);
        }
        // 2. 反射读取
        try {
            Method method = func.getClass().getDeclaredMethod("writeReplace");
            return new ReflectLambdaMeta((SerializedLambda) ReflectionKit.setAccessible(method).invoke(func));
        } catch (Throwable e) {
            // 3. 反射失败使用序列化的方式读取
            return new ShadowLambdaMeta(com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda.extract(func));
        }
    }

	 //---------------------------------------------------------------
	 public static String methodToProperty(String name) {
	   if (name.startsWith("is")) {
	     name = name.substring(2);
	   } else if (name.startsWith("get") || name.startsWith("set")) {
	     name = name.substring(3);
	   } else {
	     throw new ReflectionException("Error parsing property name '" + name + "'.  Didn't start with 'is', 'get' or 'set'.");
	   }
	
	   if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) {
	     name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
	   }
	
	   return name;
	 }

自定义的mybatis-plus的空值判断 - 推荐一手源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
手把手教你整合最优雅SSM框架:SpringMVC + Spring + MyBatis 博客地址:http://blog.csdn.net/qq598535550/article/details/51703190 我们看招聘信息的时候,经常会看到这一点,需要具备SSH框架的技能;而且在大部分教学课堂中,也会把SSH作为最核心的教学内容。 但是,我们在实际应用中发现,SpringMVC可以完全替代Struts,配合注解的方式,编程非常快捷,而且通过restful风格定义url,让地址看起来非常优雅。 另外,MyBatis也可以替换Hibernate,正因为MyBatis的半自动特点,我们程序猿可以完全掌控SQL,这会让有数据库经验的程序猿能开发出高效率的SQL语句,而且XML配置管理起来也非常方便。 好了,如果你也认同我的看法,那么下面我们一起来做整合吧! 在写代码之前我们先了解一下这三个框架分别是干什么的? 相信大以前也看过不少这些概念,我这就用大白话来讲,如果之前有了解过可以跳过这一大段,直接看代码! SpringMVC:它用于web层,相当于controller(等价于传统的servlet和struts的action),用来处理用户请求。举个例子,用户在地址栏输入http://网站域名/login ,那么springmvc就会拦截到这个请求,并且调用controller层中相应的方法,(中间可能包含验证用户名和密码的业务逻辑,以及查询数据库操作,但这些都不是springmvc的职责),最终把结果返回给用户,并且返回相应的页面(当然也可以只返回json/xml等格式数据)。springmvc就是做前面和后面过程的活,与用户打交道!! Spring:太强大了,以至于我无法用一个词或一句话来概括它。但与我们平时开发接触最多的估计就是IOC容器,它可以装载bean(也就是我们java中的类,当然也包括service dao里面的),有了这个机制,我们就不用在每次使用这个类的时候为它初始化,很少看到关键字new。另外spring的aop,事务管理等等都是我们经常用到的。 MyBatis:如果你问我它跟鼎鼎大名的Hibernate有什么区别?我只想说,他更符合我的需求。第一,它能自由控制sql,这会让有数据库经验的人(当然不是说我啦捂脸)编写的代码能搞提升数据库访问的效率。第二,它可以使用xml的方式来组织管理我们的sql,因为一般程序出错很多情况下是sql出错,别人接手代码后能快速找到出错地方,甚至可以优化原来写的sql。
MyBatis 目录(?)[-] mybatis实战教程mybatis in action之一开发环境搭建 mybatis实战教程mybatis in action之二以接口的方式编程 mybatis实战教程mybatis in action之三实现数据的增删改查 mybatis实战教程mybatis in action之四实现关联数据的查询 mybatis实战教程mybatis in action之五与spring3集成附源码 mybatis实战教程mybatis in action之六与Spring MVC 的集成 mybatis实战教程mybatis in action之七实现mybatis分页源码下载 mybatis实战教程mybatis in action之八mybatis 动态sql语句 mybatis实战教程mybatis in action之九mybatis 代码生成工具的使用 mybatis SqlSessionDaoSupport的使用附代码下载 转自:http://www.yihaomen.com/article/java/302.htm (读者注:其实这个应该叫做很基础的入门一下下,如果你看过Hibernate了那这个就非常的简单) (再加一条,其实大家可以看官方的教程更好些:http://mybatis.github.io/mybatis-3/,而且如果英文不是很好的那就看中文的:http://mybatis.github.io/mybatis-3/zh/sqlmap-xml.html) 写在这个系列前面的话: 以前曾经用过ibatis,这是mybatis的前身,当时在做项目时,感觉很不错,比hibernate灵活。性能也比hibernate好。而且也比较轻量级,因为当时在项目中,没来的及做很很多笔记。后来项目结束了,我也没写总结文档。已经过去好久了。但最近突然又对这个ORM 工具感兴趣。因为接下来自己的项目中很有可能采用这个ORM工具。所以在此重新温习了一下 mybatis, 因此就有了这个系列的 mybatis 教程. 什么是mybatis MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan Old Java Objects,普通的Java对象)映射成数据库中的记录. orm工具的基本思想 无论是用过的hibernate,mybatis,你都可以法相他们有一个共同点: 1. 从配置文件(通常是XML配置文件中)得到 sessionfactory. 2. 由sessionfactory 产生 session 3. 在session 中完成对数据的增删改查和事务提交等. 4. 在用完之后关闭session 。 5. 在java 对象和 数据库之间有做mapping 的配置文件,也通常是xml 文件。 mybatis实战教程(mybatis in action)之一:开发环境搭建 mybatis 的开发环境搭建,选择: eclipse j2ee 版本,mysql 5.1 ,jdk 1.7,mybatis3.2.0.jar包。这些软件工具均可以到各自的官方网站上下载。 首先建立一个名字为 MyBaits 的 dynamic web project 1. 现阶段,你可以直接建立java 工程,但一般都是开发web项目,这个系列教程最后也是web的,所以一开始就建立web工程。 2. 将 mybatis-3.2.0-SNAPSHOT.jar,mysql-connector-java-5.1.22-bin.jar 拷贝到 web工程的lib目录. 3. 创建mysql 测试数据库和用户表,注意,这里采用的是 utf-8 编码 创建用户表,并插入一条测试数据 程序代码 程序代码 Create TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `userName` varchar(50) DEFAULT NULL, `userAge` int(11) DEFAULT NULL, `userAddress` varchar(200) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; Insert INTO `user` VALUES ('1', 'summer', '100', 'shanghai,pudong'
Spring Boot是一个基于Spring框架的快速开发脚手架,可以帮助开发者快速搭建一个Spring应用。MyBatis和JPA是两个流行的ORM框架,可以帮助开发者将Java对象映射到数据库表。 Spring Boot整合MyBatis使用: 1. 添加MyBatis和MySQL的依赖: ```xml <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> ``` 2. 配置数据源和MyBatis: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=true username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver # MyBatis Mapper文件的位置 mybatis: mapper-locations: classpath:mapper/*.xml # 实体类的包名 type-aliases-package: com.example.demo.model ``` 3. 编写MyBatis Mapper: ```xml <!-- UserMapper.xml --> <mapper namespace="com.example.demo.mapper.UserMapper"> <select id="getUserById" resultType="com.example.demo.model.User"> select * from user where id = #{id} </select> </mapper> ``` 4. 编写UserMapper接口: ```java @Mapper public interface UserMapper { User getUserById(int id); } ``` 5. 在需要使用的地方注入UserMapper: ```java @Service public class UserService { @Autowired private UserMapper userMapper; public User getUserById(int id) { return userMapper.getUserById(id); } } ``` Spring Boot整合JPA的使用: 1. 添加JPA和MySQL的依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>2.5.5</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> ``` 2. 配置数据源和JPA: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=true username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver jpa: hibernate: ddl-auto: update properties: # 打印JPA的SQL语句 hibernate: show_sql: true format_sql: true ``` 3. 编写实体类: ```java @Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; private int age; // 省略getter和setter } ``` 4. 编写JpaRepository: ```java @Repository public interface UserRepository extends JpaRepository<User, Integer> { } ``` 5. 在需要使用的地方注入UserRepository: ```java @Service public class UserService { @Autowired private UserRepository userRepository; public User getUserById(int id) { return userRepository.findById(id).orElse(null); } } ``` 总结: Spring Boot整合MyBatis和JPA的使用方法基本相似,只是依赖和配置略有不同。MyBatis需要编写Mapper和XML文件,JPA需要编写实体类和JpaRepository接口。使用时只需要在需要使用的地方注入Mapper或Repository即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大欺诈师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值