• Mybatis JPA 插件简介


    前段时间了解到Spring JPA,感觉挺好用,但其依赖于Hibernate,本人看到Hibernate就头大(不是说Hibernate不好哈,而是进阶太难),于是做了一个迷你版的Mybatis JPA.

    代码地址(github): https://github.com/svili365/mybatis-jpa

    代码地址(gitee): https://gitee.com/svili/mybatis-jpa

    QQ交流群:246912326

    因为版本更新,可能会导致博客与代码不对应,强烈建议阅读代码仓库的wiki文档

    maven

    <dependency>
                <groupId>com.littlenb</groupId>
                <artifactId>mybatis-jpa</artifactId>
                <version>2.1.1</version>
     </dependency>

    1.1 版本说明

    v2.0.1:纯净版的resultTypePlugin

    v2.1.0:在v2.0.1基础上,增加SQL构建,InsertDefinition|UpdateDifinition

    v2.1.1:增加自定义枚举值,ICodeEnum,@CodeEnum,IntCodeEnumTypeHandler,StringCodeEnumTypeHandler

    1.2 工作模式

    1.)mybatis-jpa 是基于Mybatis的增强插件,没有对依赖包(源代码)造成污染.

    2.)ResultTypePlugin在运行时拦截,每个被拦截的方法会在初次调用时完成解析.

    3.)mybatis-jpa SQL的解析和Statement的注册时机,是在Spring applicationContext初始化完成时,只会解析一次.

    4.)由mybatis-jpa 解析的Mapper接口中定义的方法(method),将被注册到Mybatis Configuration中,即Mapper的代理和注入由依旧由Mybatis和Spring构建和管理,不影响原有的代码模式和工作模式.

    1.3 约定

    1.)Entity实体类需使用@Entity或@Table注解标记,类中字段类型不允许使用基本数据类型(如:使用Integer定义整形而不是int);

    2.)ResultTypePlugin支持结果集的嵌套,SQL的构建(InsertDefinition|UpdateDifinition)会忽略实体类的嵌套.

    3.)按照Mybatis约定,Enum枚举类型默认以 enum.name() 解析,若要解析为enum.ordinal(),需使用注解@Enumrated(value = EnumType.ORDINAL)标识.

    4.)使用自定义枚举值,枚举类型需实现ICodeEnum接口,并使用注解@CodeEnum标记Field.@CodeEnum优先级高于@Enumrated.

    插件清单

    • ResultTypePlugin 

    • DefinitionStatementScanner 

    2.1 ResultTypePlugin

    对于常规的结果映射,不需要再构建ResultMap,ResultTypePlugin增加了Mybatis对结果映射(JavaBean/POJO)中JPA注解的处理。

    映射规则:

    • 名称匹配默认为驼峰(Java Field)与下划线(SQL Column)

    • 使用@Column注解中name属性指定SQL Column

    • 使用@Transient注解标记非持久化字段(不需要结果集映射的字段)

    类型处理:

    • Boolean-->BooleanTypeHandler

    • Enum默认为EnumTypeHandler

      使用@Enumerated(EnumType.ORDINAL) 指定为 EnumOrdinalTypeHandler

    • Enum实现ICodeEnum接口实现自定义枚举值

      使用@CodeEnum(CodeType.INT) 指定为 IntCodeEnumTypeHandler

      或@CodeEnum(CodeType.STRING) 指定为 StringCodeEnumTypeHandler

      @CodeEnum 优先级 高于 @Enumerated

    结果集嵌套:

    • 支持OneToOne
    • 支持OneToMany

    e.g.

    mybatis.xml

    <configuration>
        <plugins>
            <plugin interceptor="com.mybatis.jpa.plugin.ResultTypePlugin">
            </plugin>
        </plugins>
    </configuration>

    JavaBean

    @Entity
    public class UserArchive {// <resultMap id="xxx" type="userArchive">
    
        @Id
        private Long userId;// <id property="id" column="user_id" />
                               
        /** 默认驼峰与下划线转换 */
        private String userName;// <result property="username" column="user_name"/>
    
        /** 枚举类型 */
        @Enumerated(EnumType.ORDINAL)
        private SexEnum sex;// <result property="sex" column="sex" typeHandler=EnumOrdinalTypeHandler/>
        
        /** 枚举类型,自定义值 */
        @CodeEnum(CodeType.INT)
        private PoliticalEnum political;// <result property="political" column="political" typeHandler=IntCodeEnumTypeHandler/>
        
        /** 属性名与列名不一致 */
        @Column(name = "gmt_create")
        private Date createTime;// <result property="createTime" column="gmt_create"/>
    }// </resultMap>

    mapper.xml

    <!-- in xml,declare the resultType -->
    <select id="selectById" resultType="userArchive">
        SELECT * FROM t_sys_user_archive WHERE user_id = #{userId}
    </select>

    DefinitionStatementScanner

    注册MappedStatement,基于注解,仅支持Insert和Update。

    @InsertDefinition:

    • selective: 默认值false(处理null属性)

    @UpdateDefinition:

    • selective: 默认值false(处理null属性)

    • where: SQL condition

    e.g.

    Spring 容器初始化完成后执行

    @Service
    public class DefinitionStatementInit {
    
        @Autowired
        private SqlSessionFactory sqlSessionFactory;
    
        @PostConstruct
        public void init() {
            Configuration configuration = sqlSessionFactory.getConfiguration();
            StatementBuildable statementBuildable = new DefinitionStatementBuilder(configuration);
            DefinitionStatementScanner.Builder builder = new DefinitionStatementScanner.Builder();
            DefinitionStatementScanner definitionStatementScanner = builder.configuration(configuration).basePackages(new String[]{"com.mybatis.jpa.mapper"})
                    .statementBuilder(statementBuildable).build();
            definitionStatementScanner.scan();
        }
    }

    Mapper

    @Mapper
    @Repository
    public interface UserUpdateMapper {
    
        @InsertDefinition(selective = true)
        int insert(User user);
    
        @UpdateDefinition(selective = true, where = " user_id = #{userId}")
        int updateById(User user);
    }

    更多示例请查看test目录代码。

    如果你想深入了解,项目代码目录还算清晰,源码中有大量必要的注释,你会发现有部分英文注释,不要慌,是我写的,现在感觉有些代码用英文描述反而会简单一些,用中文反而不能够被很好的理解.

    代码的构建思路及代码解析,见博文:http://www.cnblogs.com/svili/p/7232323.html

    因个人能力有限,如有不足之处,请多包涵,欢迎交流/指正.

  • 相关阅读:
    AJAX请求MVC控制器跨域头问题
    HTTP 错误500.19 -Internal Server Error 错误代码 0x80070021
    C# 同一时间批量生成订单号不重复
    Unity书籍下载地址
    几种常见的设计模式
    C# web api 对象与JSON互转
    自动按参数首字母排序参数
    C# 3DES加密 解密
    C#大量数据导出Excel
    判断对象是数组
  • 原文地址:https://www.cnblogs.com/svili/p/6828077.html
Copyright © 2020-2023  润新知