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;
} }

过程并不复杂

mybatis泛型(一)的更多相关文章

  1. JPA实现泛型baseServcie+Mybatis

    在开发的过程中,我们总无法避免不同的实体类会去实现相同的操作(增删查改,分页查询等),因此在开发时,我们期望泛型将通用的方法进行包装,使我们能够专注于实体类自身的独特方法,而非一般性常用且重复性高的方 ...

  2. Mybatis框架基础支持层——反射工具箱之泛型解析工具TypeParameterResolver(4)

    简介:TypeParameterResolver是一个工具类,提供一系列的静态方法,去解析类中的字段.方法返回值.方法参数的类型. 在正式介绍TypeParameterResolver之前,先介绍一个 ...

  3. MyBatis的一系列问题的处理(遍历Map集合和智能标签和属性和字段不一样的解决办法 和sql片段)(三)

    一.字段名与属性名(数据库的名字)不一样怎么办? 方案一:在小配置中配置一个resultMapper <!--方案一:resultMapper 字段名与属性名不一致 --> <res ...

  4. mybatis入门基础(二)----原始dao的开发和mapper代理开发

    承接上一篇 mybatis入门基础(一) 看过上一篇的朋友,肯定可以看出,里面的MybatisService中存在大量的重复代码,看起来不是很清楚,但第一次那样写,是为了解mybatis的执行步骤,先 ...

  5. IBatis 2.x 和 MyBatis 3.0.x 的区别(从 iBatis 到 MyBatis)

    从 iBatis 到 MyBatis,你准备好了吗? 对于从事 Java EE 的开发人员来说,iBatis 是一个再熟悉不过的持久层框架了,在 Hibernate.JPA 这样的一站式对象 / 关系 ...

  6. Mybatis框架基于映射文件和配置文件的方式,实现增删改查,可以打印日志信息

    首先在lib下导入: 与打印日志信息有关的架包 log4j-1.2.16.jar mybatis架包:mybatis-3.1.1.jar 连接数据库的架包:mysql-connector-java-5 ...

  7. Mybatis配置文件

    XML 映射配置文件 MyBatis 的配置文件包含了设置(settings)和属性(properties)信息. properties 这些属性都是可外部配置且可动态替换的,既可以在典型的 Java ...

  8. Cause: org.apache.ibatis.reflection.ReflectionException: Could not set property 'orderdetails' of 'class com.luchao.mybatis.first.po.Orders' with value 'Orderdetail [id=null, ordersId=3, itemsId=1, it

    从上面异常的解释来看是因为反射不能将Orders设置到orderdetails属性上,仔细检查了MyBatis的配置文件,发现: <collection property="order ...

  9. MyBatis学习--mybatis开发dao的方法

    简介 使用Mybatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper接口开发方法. 主要概念介绍: MyBatis中进行Dao开发时候有几个重要的类,它们是SqlSessionFac ...

随机推荐

  1. java学习笔记37(sql工具类:JDBCUtils)

    在之前的内容中,我们发现,当我们执行一条语句时,每新建一个方法,就要重新连接一次数据库,代码重复率很高,那么能不能把这些重复代码封装成一个类呢,我们学习方法时,就学习到方法就是为了提高代码的利用率,所 ...

  2. alignedReID: surpassing human-level performance in person re-identification (paper reading)

    关键点: 1)对齐 (8%) 2)mutual learning (3%) 3)classification loss, hard triplet同时 4)re-ranking (5~6%) 关于对齐 ...

  3. 链接属性external的使用

    //demo1.c #include<stdio.h> ; //static int x = 10; void print(void) //static void print(void) ...

  4. 温度转换-python

    #接收一段字符串 TempStr = input("请输入带有符号的温度值:") #如果 TS 最后一位是大写或是小写 f if TempStr[-1] in ['F','f']: ...

  5. switch语句判断学生成绩

    下面通过判断学生成绩来展示switch语句的使用. Q:判断学生成绩的等级,90-100分为A级,80-89为B级,70-79为C级,60-69为D级,60以下不及格. package main im ...

  6. 洛谷1101:单词方阵(DFS)

    题目描述 给一n×nn \times nn×n的字母方阵,内可能蕴含多个"yizhong"单词.单词在方阵中是沿着同一方向连续摆放的.摆放可沿着888个方向的任一方向,同一单词摆放 ...

  7. python基础-闭包

    def bibao(): li = [] n = [1] def inner(): li.append(n[0]) n[0] +=1 print(li) return inner b = bibao( ...

  8. LeetCode - Unique Email Addresses

    Every email consists of a local name and a domain name, separated by the @ sign. For example, in ali ...

  9. 在linux中编译grpc

    环境: centos_7_x86_x64 一.下载 1)下载grpc源代码:grpc-1.2.0.zip 2)下载grpc依赖库: 1)benchmark-master.zip 2)boringssl ...

  10. algernon 基于golang 的独立的支持redis lua pg。。。 的web server

    algernon 看到github 的介绍很很强大,一下子想到了openresty,功能看着很强大,支持 redis pg lua markdown quic http2 mysql 限速 pongo ...