Mybatis JPA mini

前段时间了解到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">

1@Id 2private Long userId;// <id property="id" column="user\_id" /> 3 4/\*\* 默认驼峰与下划线转换 \*/ 5private String userName;// <result property="username" column="user\_name"/> 6 7/\*\* 枚举类型 \*/ 8@Enumerated(EnumType.ORDINAL) 9private SexEnum sex;// <result property="sex" column="sex" typeHandler=EnumOrdinalTypeHandler/> 10 11/\*\* 枚举类型,自定义值 \*/ 12@CodeEnum(CodeType.INT) 13private PoliticalEnum political;// <result property="political" column="political" typeHandler=IntCodeEnumTypeHandler/> 14 15/\*\* 属性名与列名不一致 \*/ 16@Column(name = "gmt\_create") 17private 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 {

1@Autowired 2private SqlSessionFactory sqlSessionFactory; 3 4@PostConstruct 5public void init() { 6 Configuration configuration = sqlSessionFactory.getConfiguration(); 7 StatementBuildable statementBuildable = new DefinitionStatementBuilder(configuration); 8 DefinitionStatementScanner.Builder builder = new DefinitionStatementScanner.Builder(); 9 DefinitionStatementScanner definitionStatementScanner = builder.configuration(configuration).basePackages(new String\[\]{"com.mybatis.jpa.mapper"}) 10 .statementBuilder(statementBuildable).build(); 11 definitionStatementScanner.scan(); 12}

}

Mapper

@Mapper @Repository public interface UserUpdateMapper {

1@InsertDefinition(selective = true) 2int insert(User user); 3 4@UpdateDefinition(selective = true, where = " user\_id = #{userId}") 5int updateById(User user);

}

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

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

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

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )