<!-- 2016-11-13更新 start -->java
1 新增批量操做数据方法:批量插入,根据条件删除,根据条件更新指定的列名-字段值。mysql
2 新增高级查询方法:可设置查询列,查询条件,排序,分页。git
3 根据一、2更新接口。github
4 更改dao接口方法实现方式,统一采用GeneralMapper.xml编写sql,弃用GeneralDaoProvider。sql
<!-- 2016-11-13更新 end -->数据库
1 轻量级ORM 。缓存
2 提供了完善的缓存机制。mybatis
3 mapper.xml 原声SQL更清晰灵活,且sql便于SQL调优。oracle
4 resultType resultMap 处理返回结果集,与pojo解耦。app
这里只将Mybatis不便于使用之处作以说明。
1 须要为每张表写一个dao接口和mapper.xml,这对于开发者来说就不是很友好了,假设系统有30张业务表,呵呵。
2 虽然有generator 工具,能够自动生成dao 接口和mapper.xml,是能够不用本身去写这些代码了,可是仍是有2个缺点:
(1) generator只是提供了基础的增删改查功能,复杂的sql仍是要本身去添加。
(2) 仍是上面的问题,每张表都要有dao接口和mapper.xml。
对于分页的功能,仁者见仁,智者见智吧,就我我的的观点来说,我以为不必。
上面也描述了mybatis的优势之一就是mapper.xml中的原声SQL,特别是对于复杂的SQL语句,原声SQL颇有魅力。
若是你分页的sql封装成以下的格式,
<!-- mysql page封装 --> select count(1) as 'totalNum',t.* from (select user_id , user_name from user ) t limit startRowNo,rowNum <!-- mysql 原生分页 --> select count(1) as 'totalNum', user_id , user_name from user limit startRowNo,rowNum
我以为,仍是算了吧,不如原声SQL来的实在。select * 我就不讲了,select * from (sql) 根本就不必嘛。
若是说你但愿实现一个灵活的查询方法,有分页参数就按分页查询,没有分页参数就查询所有。那么个人观点是,mybatis 提供了<if></if>标签,代码以下:
<!-- mapper.xml --> <select id="selectByPage" parameterType="map" resultType="hashmap"> select count(1) as 'totalNum',user_id,user_name from user <if test="pageParam != null" > limit #{pageParam.startRowNo},#{pageParam.pageSize} </if> </select>
若是说你但愿分页方法可以更灵活,但愿实现一个方法对任何一张表均可以分页,代码能够这样写
<select id="selectByPage" parameterType="map" resultType="hashmap"> select ${queryColumn} from ${tableName} <if test="page != null" > limit #{page.startRowNo},#{page.pageSize} </if> </select>
关于分页,就这么多,仅我的观点,欢迎批评、建议或讨论。
基于1.2,但愿提供相似于hibernate中的load、insert、delete、save方法,对于基础的数据访问层操做,系统只须要存在一处,便于统一的管理,减小没必要要的代码。
基于1.1,避免使用java封装字符串sql,mapper.xml,@select,@selectProvider三选一。
但愿实现的功能方法接口,因篇幅有限,这里就只给出主键查询的接口。
所有接口声明能够查看对应代码,或者,
查看上一篇博文Mybatis 通用Crud-接口预览,https://my.oschina.net/LittleNewbie/blog/785947
/** * 通用Crud 数据访问层接口 * * @author svili * @date 2016年11月11日 * */ public interface CrudServiceInter { /** * 根据主键查询 * @param <T> pojo类 * @param clazz pojo类-class对象 * @param primaryValue 主键值 * @return pojo对象 */ <T> T selectByPrimaryKey(Class<T> clazz, Object primaryValue) throws Exception; }
<T> T selectByPrimaryKey(Class<T> clazz, Object primaryValue) throws Exception;
<2017-02-18更新>
主键类型不作限制。
<select id="selectByPrimaryKey" parameterType="map" resultType="hashmap"> select <foreach item="columnName" index="index" collection="queryColumn" separator="," > ${columnName} </foreach> from ${tableName} where ${primaryKey} = #{primaryValue} </select>
注意:不要使用<![CDATA[ ]]>去尝试对这段sql进行转义,会致使<foreach></foreach>标签不被解析处理。
关于xml中的<![CDATA[ ]]> ,自行百度get噢。
sql中须要传递的参数有4个,分别是:tableName(表名),queryColumn(查询字段集),primaryKey(主键列名),primaryValue(主键值)。
(1)tableName
从Java类到数据库的表名,咱们能够获取两个信息,一个是类名,第二个是JPA的@Table注解。
要注意两点,1.注解优先,2.Java的命名规则为驼峰,数据库的命名规则为下划线。若是你不按套路出牌,仍是要好好想一想如何去对应转换。
//获取pojo表名 public static String getTableName(Class<?> clazz) { // 驼峰转下划线 String tableName = StringUtil.camelToUnderline(clazz.getName()); // 判断是否有Table注解 if (clazz.isAnnotationPresent(Table.class)) { // 获取注解对象 Table table = clazz.getAnnotation(Table.class); // 设置了name属性 if (!table.name().trim().equals("")) { return table.name(); } } return tableName; }
(2)queryColumn
直接获取字段名就好,注意驼峰转下划线。
//获取全部字段名 public static List<String> getAllColumns(Class<?> clazz) { List<String> columns = new ArrayList<String>(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { columns.add(StringUtil.camelToUnderline(field.getName())); } return columns; }
(3)primaryKey
这只能靠JPA的@Id了。
固然你可本身定制一套标准,好比每张表都固定一个主键字段名为table_id。可是我以为彻底不必,既然有JPA的标准,为何要去本身费脑经呢。若是说你使用oracle的guid,没脾气,呵呵。
//获取主键字段 public static Field getPrimaryFieldNotCareNull(Class<?> clazz) { Field field = FieldReflectUtil.findField(clazz, Id.class); if (field != null) { return field; } else { return null; } } //获取指定注解类型的字段 public static Field findField(Class<?> clazz, Class<? extends Annotation> annotationType) { Class<?> searchType = clazz; while (!Object.class.equals(searchType) && searchType != null) { Field[] fields = searchType.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(annotationType)) { return field; } } searchType = searchType.getSuperclass(); } return null; }
关于其余接口,其实大同小异,这里就不作说明了,只须要按照2.2.2 中的思路去查看源码就OK了。
源码地址:https://github.com/LittleNewbie/portal
如何阅读源码:
主要4个文件 GeneralDao,GeneralMapper.xml,GeneralDaoProvider,CrudServiceImpl
GeneralDao声明了数据访问层接口;
GeneralMapper.xml 和GeneralDaoProvider(已弃用2016-11-13)配合GeneralDao。
GeneralDaoProvider已弃用 from 2016-11-13。
CrudServiceImpl 实现由接口参数转化为GeneralDao参数,并封装返回类型。
GeneralQueryParam 查询参数封装,start from 2016-11-13。