simple-orm-mybatis在github开源,直接跳转查看,欢迎大家fork和star。有什么建议也可以提出,我会尽快修复或实现。

前言

最早接触Java的web开发框架就是SSH,其中的H就是Hibernate。Hibernate作为最出名的Java的ORM框架,现在的版本已经到了5.3.10.Final,6.0.0.Alpha2。围绕数据持久化或者DAL层也发展了多种工具,Hibernate Validator目前也是在很多的企业框架中被用作数据有效性检查。

接下来还有用过JPA来实现ORM。JPA全称Java Persistence API,是JSR-220(EJB3.0)规范的一部分,在JSR-220中规定实体对象(EntityBean)由JPA进行支持。在我的使用中,实际上底层实现仍然使用了Hibernate,只是标注或者操作类都是使用了JPA的接口标准而没有直接使用Hibernate。

Hibernate具有强大的ORM封装能力,极大的简化了CUD的操作,而且无需做太多的配置,使用标准注解就能解决很多问题。简单的查询操作也不在话下,多级关联、延迟查询等丰富特性基本上也可以说是极大覆盖了开发过程的各种需求。但是实际上在这么多团队中,很多人的反馈是这样的:“Hibernate的ORM确实很方便,但是在一些特殊条件下很难用,比如复杂查询就很难控制语句生成的效率”。Hibernate有三种查询方式:HQL、Criteria、Native Sql。确实在复杂查询下,如果使用Criteria,确实能够拼出想要的语句,但是可能对于其中的方法要非常熟悉,学习曲线很高,没办法做到团队中每个成员都能数量轻易的掌握,而且后期的审核很困难无法直接看清逻辑。HQL和NativeSql对我的感觉,似乎回到了JSP时代,HTML和Java代码混写,很难忍受。这时候大家找到了另外的框架Mybatis。

ORM框架现状

截止(2019/5/27)Mybatis的Star是10806,UsedBy140381;Hibernate的Star是3817,UsedBy157879。看使用量Hibernate和Mybatis其实已经差不多了,实际企业开发中,Mybatis可能还会更多一些。

Mybatis优缺点

Mybatis放弃了Hibernate的强封装,主要包含了映射的部分,而且放弃了自动解析生成Sql,而直接使用用户XML配置Sql的方式,只是在Sql的拼接上提供了一些标签来避免重复代码。这样的讨巧之处在于:

  • 门槛降低:开发人员不需要了解框架的内部语法,只需要了解Sql语法即可。
  • 可读性提高:审核代码时,很容易的就能看清楚多级关联以及关联使用的条件、语法是否正确。
  • 维护方便:当查询语法出错时,Mybatis只需要修改XML,而Hibernate则需要修改代码重新编译,操作相对复杂。

缺点也有几处:

  • 简单操作复杂:由于放弃了自动解析生成Sql,所以普通的CUD也需要手动编写Sql
  • 实体映射复杂:必须在XML文件中配置大量的字段映射
  • SqlMapper中的sql id风险:由于XML中的sql id是一个字符串,只能复制粘贴出来,所以出错的几率也比较大。

实际上,针对上面缺点,Mybatis也提供了解决方案。

先说sql id的,在新的Mybatis中,实际上已经采用了面向接口的编码方式,如下面的例子:

接口类

  1. public interface UserMapper {
  2. public User findUserById(Integer id);
  3. }

mapper的xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
  3. <mapper namespace="com.software5000.mapper.dao.UserMapper">
  4. <select id="findUserById" resultType="com.software5000.entity.User" parameterType="int" >
  5. select * from user where id =#{id}
  6. </select>
  7. </mapper>

这样就可以直接调用sql语句:

  1. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  2. User user = userMapper.findUserById(1);

再说映射复杂的,Mybatis提供了MyBatis Generator作为解决方案,一个命令生成下列内容:

  • 匹配表结构的Java POJOs。可能包括:

    • 表结构中主键字段(如果存在主键)
    • 表结构中的非主键字段(除了BLOB字段)
    • 表结构中的BLOB字段(如果有BLOB字段)
    • 动态查询、更新和删除的接口类

自动生成也能够合理的生成类之间的继承关系。注意生成器也能够定义生产不同的POJO层次 - 例如如果你想要可以为每个表格生成一个单独的领域对象。

  • Mybatis/iBATIS兼容的SQL MAP的XML文件。按照配置针对每个表生成简单的增删改查的SQL方法。生成的SQL包括:

    • 插入
    • 按主键更新
    • 使用example更新 (使用动态的where条件)
    • 按主键删除
    • 使用example删除 (使用动态的where条件)
    • 按主键查询
    • 使用example查询 (使用动态的where条件)
    • 使用example统计

生成的SQL语句取决于表格的结构(例如,表格如果没有主键,就不会生成按主键更新的方法)

Java客户端生成类能够合理使用上面的对象。生成的Java客户端类也是有选择性的。

  • 使用Mybatis 3.x的会生成:

    • 一个mapper接口和XML中的语句id相同,用于直接调用。
  • 使用iBATIS 2.x的会生成:
    • 适用于Spring框架的DAO层
    • 使用IBATIS SQL映射API的DAO层。这些DAO可以使用两种方式:使用构造函数提供SqlMapClient,或者通过注入方式提供。
    • DAOs that conform to the iBATIS DAO Framework (an optional part of iBATIS, this framework is now deprecated and we suggest that you use the Spring framework instead)
    • iBATIS的DAO框架符合的DAO层(iBATIS的一个额外部分,但是现在这个框架已经失效了,所以建议使用Spring DAO的框架代替)

但是,我对于MyBatis Generator的态度是坚定的反对。原因是我认为自动生成违反了简单的原则,“如无必要,勿增实体”。自动生成的可复用性和可读性一定是比较差的。我觉得最好的代码就是不存在的代码。因此我希望能够有一个简单框架在Mybatis之上,接入简单无侵入,能够提供基本的增删改查方法。这就是下面的 simple-orm-mybatis 。

simple-orm-mybatis设计思路介绍

simple-orm-mybatis设计的初衷就是希望提供一个简单无侵入,而且无需编写或者生成任何代码就可以使用直接操作对象的方式来进行增删改查的操作。要实现这样的要求,主要是两个主要技术点:

  1. 利用反射机制对应实体对象与数据库结构
  2. 解析对象并且生成对应操作的SQL语句

第一点核心就是反射,设计要点如下:

  • Java对象与数据库结构的对应规则
  • 虚字段(无数据库对应字段)的处理
  • 考虑多层继承的对象解析
  • 值的设置与获取方式

第二点核心在于SQL解析,设计要点如下:

  • 根据不同入口区分基本CRUD语法结构
  • 字段(列名)需要分为值字段与查询字段两类
  • 更新操作的时候,Null,空,有值的区分
  • 支持多种匹配操作符(大于、小于、Like等)

simple-orm-mybatis使用说明

  1. 首先引入依赖,项目已经发布在Maven Central上,可以直接引入。
  1. <dependency>
  2. <groupId>com.software5000</groupId>
  3. <artifactId>simple-orm-mybatis</artifactId>
  4. <version>1.0.2</version>
  5. </dependency>
  1. 接着需要将 BaseDaoMapper.xml 文件放在你的 mapper 的扫描文件夹内。

  2. 最后需要在你的代码中添加一个 BaseDao 实现类,用于提供数据库操作服务(注意:需要在spring的扫描包内,因为需要注入某些属性),整个复制即可,类名可以改为你自己需要的名字

  1. import com.software5000.base.BaseDao;
  2. import org.apache.ibatis.session.SqlSession;
  3. import org.apache.ibatis.session.SqlSessionFactory;
  4. import org.mybatis.spring.SqlSessionTemplate;
  5. import org.springframework.stereotype.Component;
  6. import javax.annotation.Resource;
  7. /**
  8. * 整个类以 <code>org.mybatis:mybatis-spring:2.0.0</code> 的 <code>org.mybatis.spring.supportSqlSessionDaoSupport</code>
  9. * 为参考编写而成
  10. */
  11. @Component
  12. public class MyBaseDao extends BaseDao {
  13. private SqlSessionTemplate sqlSessionTemplate;
  14. public MyBaseDao() {
  15. // 在默认构造函数中设置 数据库是否蛇形, 数据库格式大小写, 通用忽略的字段名称
  16. this.initConfig(true,false,"serialVersionUID");
  17. }
  18. @Resource
  19. public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
  20. if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
  21. this.sqlSessionTemplate = this.createSqlSessionTemplate(sqlSessionFactory);
  22. }
  23. }
  24. protected SqlSessionTemplate createSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
  25. return new SqlSessionTemplate(sqlSessionFactory);
  26. }
  27. @Override
  28. public SqlSession getSqlSession() {
  29. return this.sqlSessionTemplate;
  30. }
  31. }

simple-orm-mybatis实际使用

这里给了一个单元测试的例子,实际一般是在service层直接使用,无需添加任何代码。

示例中的 DailyRecord 是一个普通实体类,没有任何继承。

  1. // 获取启动类,加载配置,确定装载 Spring 程序的装载方法,它回去寻找 主配置启动类(被 @SpringBootApplication 注解的)
  2. @SpringBootTest
  3. // 让 JUnit 运行 Spring 的测试环境, 获得 Spring 环境的上下文的支持
  4. @RunWith(SpringRunner.class)
  5. public class BaseDaoTest {
  6. @Autowired
  7. private MyBaseDao myBaseDao;
  8. @Test
  9. public void testBaseDao(){
  10. DailyRecord dailyRecord = new DailyRecord();
  11. List<DailyRecord> dailyRecords = myBaseDao.selectEntity(dailyRecord);
  12. System.out.println(dailyRecords.size());
  13. }
  14. }

推荐最佳实践

虽说整体的设计基于无侵入,基本没有任何前提,但是还是有一些推荐的实践希望大家能够去尝试:


1、 数据结构设计建议包含int类型的自增主键设计,名称叫id。

原因:很多时候我们的业务主键是有一套特定规则,但是很有可能面对修改,所以底层关联主键统一使用id关联在后期面对修改时影响较小。

弊端:

1. 如mysql中int最长2147483647,考虑到自增id可能会有跳过不连续的情况,需要考虑实际可用的存储量。不过大部分的业务表是到不了这个数量级的。

2. mysql的InnoDB有自增主键锁表的问题,超大并发插入可能会影响效率。不过在5.1.22有提供了改进的策略。


2、 数据结构与实体结构尽量符合统一转换规则。

原因:这样研发过程中,实体与数据库的映射会比较简单,无需大量的自定义。建议的规则有三类:

- 两边都使用驼峰。

- 实体使用驼峰,数据库使用全小写蛇形

- 实体使用驼峰,数据库使用全大写蛇形


3、 代码中实体的字段类型使用封装类型而不是基本类型

原因:基本类型是有默认值存在,而数据库中我们一旦设置字段可空,就会有NULL值存在。所以建议全部使用封装类型。下面附上各种基本类型的默认值

基本类型 默认值
byte 0
short 0
int 0
long 0L
float 0.0f
double 0.0d
char ‘\u0000’
boolean false

4、 分页算法

原因:分页推荐使用PageHelper,是利用Mybatis的底层插件机制修改Sql语句,也是无侵入。


更多说明

更多说明,可以参考github上的wiki页面

[simple-orm-mybaits]基于Mybatis的ORM封装介绍的更多相关文章

  1. 基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil

    基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil,把日常能用到的各种CRUD都进行了简化封装,让普通程序员只需关注业务即可,因为非常简单,故直接贴源代码,大家若需使用可以直 ...

  2. MyBatis学习总结(一)——ORM概要与MyBatis快速起步

    程序员应该将核心关注点放在业务上,而不应该将时间过多的浪费在CRUD中,多数的ORM框架都把增加.修改与删除做得非常不错了,然后数据库中查询无疑是使用频次最高.复杂度大.与性能密切相关的操作,我们希望 ...

  3. JdbcTemplate 、Mybatis、ORM 、Druid 、HikariCP 、Hibernate是什么?它们有什么关系?

    JdbcTemplate .Mybatis.ORM .Druid .HikariCP .Hibernate是什么?它们有什么关系? 学完Spring和SpringMVC之后,就急于求成的开始学习起Sp ...

  4. Atitit  基于meta的orm,提升加速数据库相关应用的开发

    Atitit  基于meta的orm,提升加速数据库相关应用的开发 1.1. Overview概论1 1.2. Function & Feature功能特性1 1.2.1. meta api2 ...

  5. TinyFrame开篇:基于CodeFirst的ORM

    前言 做项目的这段时间,由于比较忙,一直没有机会闲下来思考.正好趁目前手头活儿轻松点,就花了一两天时间搭建了一个比较简单的框架,名称暂时就叫做:TinyFrame吧.顾名思义,就是微框架的意思.虽然这 ...

  6. mybatis关于ORM的使用以及设计(二)[DaoInterface 转换 Mapper代理对象]

    第一节中,分析了Mybatis的ORM框架的初始化,这篇来分析SQL执行过程中,对象->SQL是如何转换的 其中包含两种映射思想 ①DAO接口->Mapper实例 ②执行DAO的方法时,参 ...

  7. 基于mybatis的CRUD

    u  基于Mybatis的CRUD u  掌握MyBatis的结果类型-resultMap和resultType u  掌握MyBatis的参数类型 u  掌握#和$两种语法 1      基于myb ...

  8. 基于mybatis的BaseDao及BaseService深度结合(转)

    原文地址:http://zhaoshijie.iteye.com/blog/2003209 关键字:Mybatis通用DAO设计封装(mybatis) 说明: mybatis默认分页机制为逻辑分页,所 ...

  9. Android基于Retrofit2.0 +RxJava 封装的超好用的RetrofitClient工具类(六)

    csdn :码小白 原文地址: http://blog.csdn.net/sk719887916/article/details/51958010 RetrofitClient 基于Retrofit2 ...

随机推荐

  1. poj 2385 树上掉苹果问题 dp算法

    题意:有树1 树2 会掉苹果,奶牛去捡,只能移动w次,开始的时候在树1 问最多可以捡多少个苹果? 思路: dp[i][j]表示i分钟移动j次捡到苹果的最大值 实例分析 0,1  1,2...说明 偶数 ...

  2. Linux学习-进程管理

    为什么进程管理这么重要呢? 这是因为: 首先,我们在操作系统时的各项工作其实都是经过某个 PID 来达成的 (包括你的 bash 环境), 因此,能不能进行某项工作,就与该进程的权限有关了. 再来,如 ...

  3. mac 安装composer的方法

    打开命令后 cd /usr/local/bin 然后执行 curl -sS https://getcomposer.org/installer | php 接下来 sudo mv composer.p ...

  4. 有限状态机(FSM)的设计与实现

    有限状态机(FSM)是表示有限个状态及在这些状态之间的转移和动作等行为的数学模型,在计算机领域有着广泛的应用.通常FSM包含几个要素:状态的管理.状态的监控.状态的触发.状态触发后引发的动作.本文主要 ...

  5. Django Model two

    Django_model: eg: class XXXX(models.Model): nid = models.AutoField(primary_Key=True) name = models.C ...

  6. 从Windows想Linux上传文件 Linux(CentOS) 上安装vsftpd

    今天想在Linux上搭建个LAMP环境,以前用的Linux都安装了图形界面,但是这次用的阿里云服务器是纯命令模式,用起来有点不大适应. 最大的不适应就是获取apache等软件了,以前直接登录相应网站, ...

  7. 如何通过 Vue-Cli3 - Vuex 完成一个 TodoList

    昨天大概粗糙的了解了一下Vue的概况之后,并没有从框架.语法的细节来进一步学习.那今天通过一个简单的实例来继续完善一下Vue这方面的空白,用一些看得见的效果摸的着的代码在不断完成小目标的过程中慢慢消化 ...

  8. Android 资源文件local.properties使用以及Gradle文件中的值、Manifests文件中的值

    这篇也是因为Gradle存储密钥问题一路填坑总结的,期初连.properties创建都有疑问 因为当时是在Android下查看新建的properties一直没法看到 因为Gradle Scripts是 ...

  9. Python面试题(练习二)

    1.用Python实现一个二分查找的函数. data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35] def ...

  10. 老男孩全栈python学习进程表

     老男孩Python高级全栈开发工程师-1  0001.开学典礼_ALEX简介  00:55:53 ☆  0002.职业生涯_来培训的目的  01:12:29 ☆  0003.课程目标  00:29: ...