<!-- 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。