mybatis泛型(一)

时间:2022-11-04 08:27:18

mybatis的确很方便,可以随意配置sql语句,并根据参数生成指定的sql,也可以根据查询结果生成指定对象

但是有一点非常恐怖,就是每个数据库表都必须有一个配置,等于在一个系统里做了很多重复的工作,

因为几乎每个表都用到getById,update等操作,今天我们就尝试着把这些操作提取出来,一次性完成.

而不要重复重复再重复. 设想一下一个大型项目,几百张表,要生成几百个mapper.xml  而且这些xml内容差不多.

先来看看准备工作

定义entity的基类,

import java.util.Date;

public class BaseEntity<ID> {
private ID id;
private ID creatorId;
private ID updaterId;
private Date createDate;
private Date updateDate;
private Long updateCount;
private Integer isDelete; public ID getId() {
return id;
} public void setId(ID id) {
this.id = id;
} public Date getUpdateDate() {
return updateDate;
} public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
} public Date getCreateDate() {
return createDate;
} public void setCreateDate(Date createDate) {
this.createDate = createDate;
} public ID getCreatorId() {
return creatorId;
} public void setCreatorId(ID creatorId) {
this.creatorId = creatorId;
} public ID getUpdaterId() {
return updaterId;
} public void setUpdaterId(ID updaterId) {
this.updaterId = updaterId;
} public Long getUpdateCount() {
return updateCount;
} public void setUpdateCount(Long updateCount) {
this.updateCount = updateCount;
} public Integer getIsDelete() {
return isDelete;
} public void setIsDelete(Integer isDelete) {
this.isDelete = isDelete;
}
}

id字段很重要,其余看公司规定.

这里Id使用的是泛型,也就是说它可以使 int,long,甚至String

真正的entity对象定义起来就很容易啦

public class SysUser extends BaseEntity<Integer> {
private Integer userAge;
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getUserAge() {
return userAge;
}
public void setUserAge(Integer userAge) {
this.userAge = userAge;
}
}

然后是定义mapper接口

public interface BaseMapper<T extends BaseEntity<ID>,ID> {
T getById(ID id);
int insert(T entity);
int update(T entity); int deleteByIds(@Param("ids")ID... ids);
int deleteBy(Criteria criteria); int removeByIds(@Param("ids")ID... ids);
int removeBy(Criteria criteria); List<T> getBy(Criteria criteria); int countAll();
int countBy(Criteria criteria); int insertAll(List<T> list);
int updateBy(@Param("criteria")Criteria criteria,@Param("params")T entity); List<T> findAll();
}

这里基本包含我们常用的查询,其余需要级联查询,多表关联的继承这个接口,然后定义这个不常用查询的mapper.xml

public interface SysUserMapper extends BaseMapper<SysUser,Integer>{
int maxId();
}

这个只是Demo自然没什么复杂的东西可以定义

了解过mybatis的人应该知道,mapper接口是需要注册才能使用的,

要写使用这些公用的方法还需要一些步骤.

我们可以使用代码生成器,生成如下类:

public class MapperContainer {
public static interface SysUserMapper extends BaseMapper<SysUser,Integer>{ } public static interface UserlogMapper extends BaseMapper<Userlog,Integer>{ }
}

再有复杂定义时可以继承MapperContainer.XXX,  MapperContainer 有两个作用,第一个作用是防止某些表根本没有复杂定义,使用基本查询即可. 这样不用手写一个接口

第二就是为了方便注册

我们先来看看使用的Demo

public class Demo {

    public static void main(String[] args) throws IOException {
Reader reader = Resources.getResourceAsReader("mybaits-config.xml");
Configuration config = new XMLConfigBuilder(reader, null, null).parse();
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config); OrmProvider.getMapperRegister().registerContainer(MapperContainer.class, config); SqlSession session = factory.openSession(false); MapperContainer.UserlogMapper mapper = session.getMapper(MapperContainer.UserlogMapper.class); List<Userlog> list = new ArrayList<Userlog>();
for(int i=0;i<10;i++){
list.add(new Userlog());
list.get(i).setContext("这是测试内容"+i);
list.get(i).setIpAddress("192.168.56." + i);
}
mapper.insertAll(list); session.commit();
session.close();
} }
OrmProvider.getMapperRegister().registerContainer(MapperContainer.class, config);就是在对这些mapper做注册操作
我们先来看看这个注册接口
public interface MapperRegister {
InputStream createMapper(Class<?> cls);
void register(Class<?> cls,Configuration config);
void registerContainer(Class<?> container,Configuration config);
}

从这个接口上就能看出方便性来,因为如果不是使用容器类,就必须对这些接口一个个注册.

当然这只是一个接口,因为不同数据库的sql也不尽相同,所以需要有不同的调用方式

注册过程如下

public class MysqlMapperRegister extends AbstractMapperRegister {

    public final static String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">";

    private static HashSet<Integer> set = new HashSet<Integer>();

    @SuppressWarnings("rawtypes")
public InputStream createMapper(Class<?> cls) {
if(!BaseMapper.class.isAssignableFrom(cls)){
throw new RuntimeException(cls.getName() + "不是BaseMapper的子类,无法完成注册");
} Class entityCls = (Class) ((ParameterizedType) cls.getGenericInterfaces()[0]).getActualTypeArguments()[0];
Class idCls = (Class) ((ParameterizedType) cls.getGenericInterfaces()[0]).getActualTypeArguments()[1]; StringBuilder builder = new StringBuilder(XML_HEADER);
builder.append("<mapper namespace='");
builder.append(cls.getName());
builder.append("'>"); builder.append("<resultMap type='"+entityCls.getName()+"' id='"+entityCls.getName().replaceAll("[.]", "")+"_resultMap'>");
for(Field field:getAllFields(entityCls)){
builder.append("<id property='"+field.getName()+"' column='"+OrmProvider.getCurrentOrmStrategy().filed2Column(field)+"' />");
}
builder.append("</resultMap>"); builder.append("<select id='getById' parameterType='"+idCls.getName()+"' resultType='");
builder.append(entityCls.getName());
builder.append("'>select * from ");
builder.append(OrmProvider.getCurrentOrmStrategy().class2Table(entityCls));
builder.append(" where id = #{id} and ");
builder.append(OrmProvider.getCurrentODeleteStrategy().getUnDeleteCnd());
builder.append("</select>"); builder.append("<insert id='insert' parameterType='");
builder.append(entityCls.getName());
builder.append("' useGeneratedKeys='true' keyProperty='id' >insert into ");
builder.append(OrmProvider.getCurrentOrmStrategy().class2Table(entityCls)); builder.append(" <trim prefix='(' suffix=')' suffixOverrides=',' >");
for(Field field:getAllFields(entityCls)){
builder.append("<if test='"+field.getName()+" != null' >"+OrmProvider.getCurrentOrmStrategy().filed2Column(field)+",</if>");
}
builder.append("</trim>"); builder.append("<trim prefix='values (' suffix=')' suffixOverrides=',' >");
for(Field field:getAllFields(entityCls)){
builder.append("<if test='"+field.getName()+" != null' >#{"+field.getName()+"},</if>");
}
builder.append("</trim>"); builder.append("</insert>"); builder.append("<update id='deleteByIds' parameterType='java.util.List'>");
builder.append(OrmProvider.getCurrentODeleteStrategy().createDeleteSql(entityCls));
builder.append(" where id in ");
builder.append("<foreach item='item' index='index' collection='ids' open='(' separator=',' close=')'>#{item}</foreach>");
builder.append(" </update>"); builder.append("<update id='deleteBy' parameterType='com.qdyq.common.criteria.Criteria'>");
builder.append(OrmProvider.getCurrentODeleteStrategy().createDeleteSql(entityCls));
builder.append("<if test='_parameter != null' ><where ><include refid='Global.Where_Clause' /></where></if>");
builder.append(" </update>"); builder.append("<update id='update' parameterType='");
builder.append(entityCls.getName());
builder.append("'>update ");
builder.append(OrmProvider.getCurrentOrmStrategy().class2Table(entityCls));
builder.append(" <set>");
for(Field field:getAllFields(entityCls)){
builder.append("<if test='"+field.getName()+" != null' >"+OrmProvider.getCurrentOrmStrategy().filed2Column(field)+" = #{"+field.getName()+"},</if>");
}
builder.append("</set> ,update_count=update_count+1 where id = #{id} and ");
builder.append(OrmProvider.getCurrentODeleteStrategy().getUnDeleteCnd());
builder.append("</update>"); builder.append("<delete id='removeByIds' parameterType='java.util.List'>");
builder.append("delete from ");
builder.append(OrmProvider.getCurrentOrmStrategy().class2Table(entityCls));
builder.append(" where id in ");
builder.append("<foreach item='item' index='index' collection='ids' open='(' separator=',' close=')'>#{item}</foreach>");
builder.append(" </delete>"); builder.append("<delete id='removeBy' parameterType='com.qdyq.common.criteria.Criteria'>");
builder.append("delete from ");
builder.append(OrmProvider.getCurrentOrmStrategy().class2Table(entityCls));
builder.append(" <if test='_parameter != null' ><where ><include refid='Global.Where_Clause' /></where></if>");
builder.append(" </delete>"); builder.append("<select id='findAll' resultMap='");
builder.append(entityCls.getName().replaceAll("[.]", "")+"_resultMap");
builder.append("'>select * from ");
builder.append(entityCls.getSimpleName());
builder.append(" where ");
builder.append(OrmProvider.getCurrentODeleteStrategy().getUnDeleteCnd());
builder.append("</select>"); builder.append("<insert id='insertAll' parameterType='java.util.List'");
builder.append(" useGeneratedKeys='true' keyProperty='id' >insert into ");
builder.append(OrmProvider.getCurrentOrmStrategy().class2Table(entityCls)); builder.append(" (");
boolean notFirst = false;
StringBuilder valuesBuilder = new StringBuilder("(");
for(Field field:getAllFields(entityCls)){
if("id".equals(field.getName()))continue;
if(notFirst){
builder.append(',');
valuesBuilder.append(',');
}else
notFirst = true; valuesBuilder.append("#{item." + field.getName() +"}");
builder.append(OrmProvider.getCurrentOrmStrategy().filed2Column(field));
}
builder.append(") values ");
valuesBuilder.append(")");
builder.append("<foreach collection='list' item='item' index='index' separator=',' > ");
builder.append(valuesBuilder.toString());
builder.append("</foreach>");
builder.append("</insert>"); builder.append("<select id='getBy' parameterType='com.qdyq.common.criteria.Criteria' resultMap='"+entityCls.getName().replaceAll("[.]", "")+"_resultMap' >");
builder.append("select * from ");
builder.append(OrmProvider.getCurrentOrmStrategy().class2Table(entityCls));
builder.append("<if test='_parameter != null' ><where ><include refid='Global.Where_Clause' /></where></if>");
builder.append("<if test='hasOrderBy' >order by<foreach collection='orderBys' item='orderBy' separator=',' >${orderBy}</foreach></if>");
builder.append("</select>"); builder.append("<select id='countBy' parameterType='com.qdyq.common.criteria.Criteria' resultType='int'>");
builder.append("select count(*) from ");
builder.append(OrmProvider.getCurrentOrmStrategy().class2Table(entityCls));
builder.append("<if test='_parameter != null' ><where ><include refid='Global.Where_Clause' /></where></if>");
builder.append("</select>"); builder.append("<select id='countAll' resultType='int'>");
builder.append("select count(*) from ");
builder.append(OrmProvider.getCurrentOrmStrategy().class2Table(entityCls));
builder.append(" where ");
builder.append(OrmProvider.getCurrentODeleteStrategy().getUnDeleteCnd());
builder.append("</select>"); builder.append("<update id='updateBy' parameterType='com.qdyq.common.criteria.Criteria'>");
builder.append("update ");
builder.append(OrmProvider.getCurrentOrmStrategy().class2Table(entityCls));
builder.append(" <set>");
for(Field field:getAllFields(entityCls)){
if("id".equals(field.getName()))continue;
builder.append("<if test='params."+field.getName()+" != null' >"+OrmProvider.getCurrentOrmStrategy().filed2Column(field)+" = #{params."+field.getName()+"},</if>");
}
builder.append("</set> ,update_count=update_count+1 ");
builder.append("<if test='criteria != null' ><where><include refid='Global.Where_Clause2'/></where></if>");
builder.append("</update>"); builder.append("</mapper>"); System.out.println(builder.toString()); return new ByteArrayInputStream(builder.toString().getBytes());
} public void register(Class<?> cls, Configuration config) { if(!set.contains(config.hashCode())){
synchronized(this){
if(!set.contains(config.hashCode()))
try {
set.add(config.hashCode());
new XMLMapperBuilder(Resources.getResourceAsStream("GlobalMapper.xml"),config,"xmlCoder_Global",config.getSqlFragments()).parse();
} catch (IOException e) {
e.printStackTrace();
}
}
} new XMLMapperBuilder(createMapper(cls),config,"xmlCoder_" + cls.getName().replaceAll("[.]", ""),config.getSqlFragments()).parse();
} private List<Field> getAllFields(Class<?> cls){
if(!BaseEntity.class.isAssignableFrom(cls)){
throw new RuntimeException("entity的基類必須是BaseEntity");
}
Field[] fs = cls.getDeclaredFields();
List<Field> result = new ArrayList<Field>();
for(Field f:fs){
if(f.getAnnotation(MapForbidden.class)==null){
result.add(f);
}
}
if(!cls.equals(BaseEntity.class))result.addAll(getAllFields(cls.getSuperclass()));
return result;
} }

过程并不复杂