本人一开始是用hibernate做开发的。换了公司之后,公司内部用mybatis,于是开始使用mybatis。在使用mybatis的过程中, 发现一些通用的操作,比如单表的CURD,在每一个xml文件中都需要定义一遍。而且每个人写的风格又不统一。于是寻找了一个解决 办法,使用maven插件mybatis-generator。使用一段时间之后,发现还是不能令人满意。每次修改表结构,都要重新生成代码。 还要把自定义的代码和自动生成的代码手工合并到一起。并且自动生成的代码体积庞大,结构相同。开始怀念hibernate,but,问题 还是需要解决的。于是阅读mybatis的源码,设计一个能够自动生成通用sql、又能够将通用sql和手写的sql分离的解决方案。经历过好 几个版本的迭代,当前版本已经在生产环境可用了。(sirenia是一个金属乐队,是海妖的意思)
-
mybatis分页查询插件以及分页参数和结果的封装
public PageRes<User> queryUserByPage(User condition,Pageable page) { //... //List<User> rows = UserMapper.queryUserByPage(condition ,page); //return PageRes.of(rows,page); return userMapper.queryUser(condition, page).getPageRes(); }
Pageable有两个子类LimitPage和IndexPage,分别用于limit-offset方式的分页和index-size方式的分页。
-
mybatis单表CURD通用dao @ResultType(Integer.class)
- int countByExample(EXAMPLE example);//根据Example条件统计条数
- int deleteByExample(EXAMPLE example);//根据Example条件删除
- int insert(ENTITY record);//插入一条,必须指定所有字段
- int insertSelective(ENTITY record);//插入一条,只设置不为null的字段
- List selectByExample(EXAMPLE example);//根据Example查询
- ENTITY selectUniqueByExample(EXAMPLE example);//根据Example查询唯一一条
- int updateByExampleSelective(@Param("record") ENTITY record, @Param("example") EXAMPLE example);//根据Example更新
- int updateByExample(@Param("record")ENTITY record, @Param("example")EXAMPLE example);//根据Example更新,null值会更新表字段为null
- PageResWraper selectByExample(@Param("example") EXAMPLE example, @Param("page") Pageable page);
- int batchInsert(@Param("recordList") List recordList);
- int batchInsertSelective(@Param("recordList") List recordList);
- int deleteByPrimaryKey(@Param("id") PK id);
- int deleteByPrimaryKeyAndVersion(@Param("id") PK id,@Param("version")Integer version);
- ENTITY selectByPrimaryKey(@Param("id") PK id);
- int updateByPrimaryKeySelective(ENTITY record);
- int updateByPrimaryKeySelectiveAndVersion(ENTITY record);//支持乐观锁的更新
- int updateByPrimaryKey(ENTITY record);
- int updateByPrimaryKeyAndVersion(ENTITY record);
- int insertSelectiveSelectKey(ENTITY record);*/
- PK selectKey();//获取id,对于postgresql,要先执行它再执行insert。对于mysql相反。
-
通用dao支持两种查询条件的封装方式;
-
支持mybatis-generator的Example以及该项目中自定义的Example。 mybatis-generator的XXXExample,每个实体类都需要一个XXXExample,每次修改表结构都需要重新生成XXXExample, 缺点是重构麻烦,优点是享受编译器静态语法检查,适合需要稳步前进的大项目。
-
项目中定义的通用Example,代码简单。比如构建一个查询条件
Example example = new Example(); example.createCriteria().and("scene_id").equalTo(sceneId) .and("datetime").equalTo(datetime); return sceneEciCountMapper.selectByExample(example );
缺点是基于字符串,不能享受静态检查,优点是重构时不需要重新生成代码,适合快速开发小项目。
- 两种Example方式可以很容易的相互转换。因为通用Example就是基于mybatis-generator插件生成的XXXExample设计的。
-
-
对乐观锁的支持;
支持乐观锁,不过有些要求,乐观锁列名必须为opti_version,对应的java类型必须为Integer或者Long。 乐观锁的使用方式,仅支持 开启事务->查询->比较版本->更新 方式,不支持 开启事务->更新(已版本作为更新条件之一)。 需要数据库设置乐观锁字段的默认值。 如果需要对某个表使用乐观锁功能,在对应的Mapper.java上加上@OptimistionLock注解。
仅仅解决了单表的CURD问题,没有对表关联的问题提出解决方案。并且对于单表的CURD,也不是完全支持,比如不支持SUM等聚合操作; 项目中有些强制约定,比如主键名字必须是id;