Tigon MyBatis v0.0.5 发布
Release Notes
- Jdbc3KeyGen读取传入参数,先执行检查,避免在新版本MyBatis中报异常
- 优化
Search#isNull,生成is null查询条件 - 增加
Search#isNull相关单元测试 - 优化传入参数名
modelmodels等,避免与业务参数冲突
Tigon MyBatis
简介
Tigon MyBatis为Spring工程中MyBatis的Mapper提供增强,主要有以下特点
- 代码又少又壮,绝不做多余的事情
- 仅需Mapper继承接口,实现
增删改查,无额外配置,爽到没女朋友 - 用完即走,毫不留恋
开始使用
- 引入Maven依赖
<dependency> <groupId>me.chyxion.tigon</groupId> <artifactId>tigon-mybatis</artifactId> <version>0.0.5</version> </dependency>
使用示例
下面是使用示例,可以在源代码中找到更详细的单元测试。Talk is cheep,read the fine source code.
定义Entity
package me.chyxion.tigon.mybatis.entity;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
import lombok.ToString;
import java.io.Serializable;
import me.chyxion.tigon.mybatis.Table;
import me.chyxion.tigon.mybatis.NotUpdate;
@Getter
@Setter
@ToString
@Table("tb_user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
@NotUpdate
private String account;
private String mobile;
private String name;
private Gender gender;
private String password;
private Date birthDate;
private String city;
private String avatar;
private Boolean active;
private String remark;
private String createdBy;
private Date createdAt;
private String updatedBy;
private Date updatedAt;
public enum Gender {
MALE,
FEMALE
}
}
定义Mapper
package me.chyxion.tigon.mybatis.mapper;
import java.util.List;
import me.chyxion.tigon.mybatis.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import me.chyxion.tigon.mybatis.entity.User;
@Mapper
public interface UserMapper extends BaseMapper<Integer, User> {
}
注入Mapper对象
@Autowired private UserMapper mapper;
I. 插入
final User user = new User();
user.setName("Donghuang");
user.setAccount("donghuang");
user.setMobile("137647788xx");
user.setPassword(RandomStringUtils.randomAlphanumeric(16));
user.setGender(User.Gender.MALE);
user.setBirthDate(DateUtils.parseDate("1994-04-04"));
user.setCity("Shanghai");
user.setActive(true);
user.setRemark("Uncle Donghuang");
user.setCreatedBy("donghuang");
user.setCreatedAt(new Date());
// single insert
mapper.insert(user);
final User user1 = new User();
user1.setName("Gemily");
user1.setAccount("gemily");
user1.setMobile("15770780xxx");
user1.setPassword(RandomStringUtils.randomAlphanumeric(16));
user1.setGender(User.Gender.FEMALE);
user1.setBirthDate(DateUtils.parseDate("1990-06-06"));
user1.setCity("Hangzhou");
user1.setActive(true);
user1.setCreatedBy("donghuang");
user1.setCreatedAt(new Date());
final User user2 = new User();
user2.setName("Luffy");
user2.setAccount("luffy");
user2.setMobile("137647799xx");
user2.setPassword(RandomStringUtils.randomAlphanumeric(16));
user2.setGender(User.Gender.MALE);
user2.setBirthDate(DateUtils.parseDate("1997-07-07"));
user2.setCity("East sea");
user2.setActive(true);
user2.setRemark("Luffy");
user2.setCreatedBy("donghuang");
user2.setCreatedAt(new Date());
// batch insert
mapper.insert(Arrays.asList(user1, user2));
II. 查询
根据ID查询单个对象
final Integer id = 1154; final User user = mapper.find(id);
根据属性查询单个对象
final User user = mapper.find(
new Search("account", "donghuang")
.eq("mobile", "137647788xx"));
根据属性查询列表
final List<User> users = mapper.list(new Search()
.between("birth_date",
DateUtils.parseDate("1982-04-04"),
DateUtils.parseDate("1994-04-04")
)
.eq("gender", User.Gender.MALE)
.asc("birth_date")
.limit(42));
Search对象支持的API
andAnd anotherSearchascOrder ASCbetweenBetween two valuesbuildBuild query criterioncontainsValue contains stringdescOrder DSCendsWithValue ends with stringeqEqaulsgtGreater thangteEqauls or greater thaninIn valuesisNullValue is nulllikeValue likelimitReturn rows limitltLess thanlteEqauls or less thanneNot equalsnotInNot in valuesnotNullValue is not nulloffsetReturn rows offsetorOr anotherSearchorderByOrder bystartsWithValue starts with string
III. 更新
通过Entity根据ID更新
final User user = mapper.find(1);
user.setName("东皇大叔");
user.setUpdatedBy("SYS");
user.setUpdatedAt(new Date());
mapper.update(user);
通过Map<String, Object>更新
final Map<String, Object> update = new HashMap<>(6);
update.put("name", "东皇大叔");
update.put("updatedBy", "SYS");
update.put("updatedAt", new Date());
mapper.update(update, 1);
// OR
// mapper.update(update, new Search("id", 1));
// mapper.update(update, new Search(1));
更新列为NULL
// Update remark to NULL of id 274229
mapper.setNull("remark", 274229);
// Update remark to NULL of id 1154L
mapper.setNull("remark", new Search("id", 1154));
// Update all remarks to NULL. BE CAREFUL!!!
mapper.setNull("remark", new Search());
IV. 删除
通过ID删除数据
mapper.delete(1);
通过Search对象删除数据
mapper.delete(new Search("id", 1));
V. 杂项
除了上面说到的一些基础增删改查操作,还有一些实用功能,如@Transient @UseGeneratedKeys @NoPrimaryKey @NotUpdateWhenNull @RawValue等注解,插入、更新前回调,以及支持扩展自定义的方法等。
配置说明
- SpringBoot项目,无需其他操作,引入依赖即可
- Spring项目,注册Bean me.chyxion.tigon.mybatis.TigonMyBatisConfiguration
- 业务Mapper继承me.chyxion.tigon.mybatis.BaseMapper或相关衍生Mapper,Base(Query, Insert, Update, Delete)Mapper
原理
Tigon MyBatis并不改变MyBatis相关功能,所做的只是在程序启动期间检测业务Mapper接口,如果继承了相关BaseMapper.java,则注入相关方法MappedStatement,具体逻辑参见源码,超简单,超幼稚。
其他
在前面使用Search的例子中,我们需要一些User的属性常量字符串,比如
final User user = mapper.find(new Search("account", "donghuang"));
可以将这些常量定义在User类中,如
public static final String ACCOUNT = "account";
使用过程中可以使用属性常量,如
final User user = mapper.find(new Search(User.ACCOUNT, "donghuang"));
也可以使用Lombok的@FieldNameConstants注解生成,只是这个注解还处于试验阶段,有一定不稳定风险。
最后
为什么要有这个项目,其实这些代码本人从2014年就陆续在写在用,在自己参与的一些项目里默默奉献。
有想过开源,奈何一直忙着修福报,此外很重要的一点是,觉得方案并不完善,还是比较长比较臭。
开源界已经有很多MyBatis相关的项目了,包括官方出品的mybatis-dynamic-sql,这玩意把我可恶心坏了。最近接触的项目里有在用,看着那一坨一坨的完全没动力碰的垃圾代码,全世界都在看我们的笑话,Java什么时候变成这样了,让玩PHP,玩C#,玩GO,玩Ruby的同学怎么看待我们,哎卧槽。
魔幻2020年就快结束了,熬夜把拖延了好几年的待办事项做个了结,后续如果还有精力,我会考虑把生成代码的逻辑一并释放出来。