最近工作比較閑,維護一個政府機關的短信發(fā)送平臺,大部分業(yè)務邏輯都在Oracle數(shù)據(jù)庫上,但自己明明應聘的是java開發(fā)啊!!!整天寫存儲過程的我還是有一顆寫高級語言的心啊!!!好吧!!!先找個數(shù)據(jù)庫方面的框架學起來吧!
手頭項目比較老,還在用ibatis,就找了它的后繼者Mybatis3來學習(3.3.0 released,24 May 2015)。
學習的期望是:
從這幾個部分理解:
沒耐心的可以直接跳到最后看總結。
找來官方文檔(還好有中文的)就讀起來。
每個基于 MyBatis 的應用都是以一個 SqlsessionFactory 的實例為中心的。我們可以從 SqlSessionFactory 中獲取 SqlSession ,SqlSession 完全包含了面向數(shù)據(jù)庫執(zhí)行 SQL 命令所需的所有方法。
我認為 SqlSessionFactory 相當于 ibatis中的SqlMapClient ,因為后者的方法中也有一個openSession()。SqlSession 相當于ibatis中的 SqlMapSession。
相比之下,Mybatis采用更清晰并且類型安全的方式來執(zhí)行SQL映射。

1 SqlSession session = sqlSessionFactory.openSession();2 try {3 BlogMapper mapper = session.getMapper(BlogMapper.class);4 Blog blog = mapper.selectBlog(101);5 } finally {6 session.close();7 }
對于簡單的增刪改查,這只需要在Java中添加注解(復雜的映射文檔中說了最好還是在XML中定義)

1 package org.mybatis.example;2 public interface BlogMapper {3 @Select("SELECT * FROM blog WHERE id = #{id}")4 Blog selectBlog(int id);5 }
當然,在ibatis中通過XML定義SQL語句映射的方式也是支持的。
XML映射文件是mybatis的重點。

1 <select id="selectPerson" parameterType="int" resultType="hashmap">2 SELECT * FROM PERSON WHERE ID = #{id}3 </select>
跟ibatis很像有木有~不同的是這里用#{parameter}來表示映射字段 而ibatis中是#patameter#。而在JDBC中,你需要像這樣來映射字段,并且在得到結果集后一一手動映射到對象。這就是Mybatis框架可以節(jié)省代碼的地方。
在JDBC中是這樣子的:

1 String selectPerson = "SELECT * FROM PERSON WHERE ID=? and name = ? and age = ?"; 2 PReparedStatement ps = conn.prepareStatement(selectPerson); 3 ps.setInt(1,id); 4 ps.setString(2,name); 5 ps.setInt(3,age); 6 ResultSet res = ps.executeQuery(); 7 while(res.next()){ 8 Student stu = new Student(); 9 stu.setId(res.getInt(1));10 stu.setName(res.getString(2));11 stu.setAge(res.getInt(3));12 }
而Mybatis中是這樣子的:

1 <typeAliases>2 <typeAlias alias="stu" type="domain.Student"/>3 </typeAliases>4 <select id="selectStudent" resultType="stu">5 select id, username, passWord6 from users7 where id = #{id}8 </select>
除去標簽占去的代碼行數(shù),當映射對象的屬性更多時,代碼量差距會更加明顯。
select中可以設置屬性,常用的就是id(命名空間中的唯一標識符,用來被引用)、parameterType(傳入?yún)?shù)的完整包名或別名)、resultType(返回結果的完整報名或別名,不和resultMap同時使用)、resultMap(外部resultMap的命名引用,稍后會詳細講)、flushCache(清空緩存)、useCache(使用緩存)、timeout(等待數(shù)據(jù)庫返回結果的最大時間)
對于Oracle,一般在插入中都需要獲得主鍵,可以使用<selectKey>標簽來獲得主鍵ID。

1 <!--Mybatis中Oracle的主鍵使用方法 --> 2 <insert id="insertSMSInpojo" parameterType="SMSINPojo"> 3 <selectKey keyProperty="id" resultType="int"> 4 select s_sms_in.nextval from dual 5 </selectKey> 6 insert into sms_in( 7 msgContent, 8 mobile, 9 destNO,10 linkId,11 curTime12 ) values(13 #msgContent#,14 #mobile#,15 #destNO#,16 #linkId#,17 #curTime#18 )19 </insert>
對于參數(shù)映射,Mybatis中提供了強大的resultMap來支持。對于簡單的查詢(列名與屬性名一一對應),你可以使用hashmap或pojo類來實現(xiàn)

1 <!-- In mybatis-config.xml file --> 2 <typeAlias type="com.someapp.model.User" alias="User"/> 3 4 <!-- In SQL Mapping XML file --> 5 <select id="selectUsers" resultType="User"> 6 select id, username, hashedPassword 7 from some_table 8 where id = #{id} 9 </select>10 11 or use this 12 13 <select id="selectUsers" resultType="map">14 select id, username, hashedPassword15 from some_table16 where id = #{id}17 </select>
如果列明沒有精確匹配,可以通過 as 來設置別名

1 <select id="selectUsers" resultType="User">2 select3 user_id as "id",4 user_name as "userName",5 hashed_password as "hashedPassword"6 from some_table7 where id = #{id}8 </select>
或是通過更強大的resultMap來解決,因為實現(xiàn)了列名和屬性名分離,更易于在不同語句中重用。

1 <resultMap id="userResultMap" type="User"> 2 <id property="id" column="user_id" /> 3 <result property="username" column="user_name"/> 4 <result property="password" column="hashed_password"/> 5 </resultMap> 6 7 <select id="selectUsers" resultMap="userResultMap"> 8 select user_id, user_name, hashed_password 9 from some_table10 where id = #{id}11 </select>
而且不僅是代碼量的差距,我也相信你一定維護過像這樣 逗號,拼接 的代碼:

1 public void insertIntoHddx(TbSmsSync tbsyncpojo, SmsTaskPojo smstask, int num, String optionList) { 2 String hddxSql = "insert into sms_hddx values("; 3 hddxSql += tbsyncpojo.getTaskId() + ","; 4 hddxSql += "'" + smstask.getTaskName() + "',"; 5 hddxSql += "'" + tbsyncpojo.getMsgContent() + "',"; 6 hddxSql += "0 ,"; 7 hddxSql += "to_date('" + smstask.getSendTime() + "','yyyy-mm-dd hh24:mi:ss') ,"; 8 hddxSql += num + ")"; 9 String[] items = optionList.split(";");10 for (String item : items) {11 String[] itemIdAndName = item.split(",");12 String itemId = itemIdAndName[0];13 String itemName = itemIdAndName[1];14 String searchItemSql = "insert into sms_hddx_option values(";15 searchItemSql += "'" + itemId + "',";16 searchItemSql += "'" + itemName + "',";17 searchItemSql += "0,";18 searchItemSql += tbsyncpojo.getTaskId() + ")";19 JdbcTemplate template = dbTemplate.getJdbcTemplate();20 template.execute(searchItemSql);21 }22 JdbcTemplate template = dbTemplate.getJdbcTemplate();23 template.execute(hddxSql);24 }
或是這樣 #動態(tài)字段映射# 的代碼

1 public PageInfo showTasks(SearchSMS searchSMS, int page) { 2 String sql = "select id from SMS_TASK sms_task where id = ? " 3 } 4 if (StringUtils.isNotBlank(searchSMS.getEndtime())) { 5 sql += "and createtime < to_date('" + searchSMS.getEndtime() + "','yyyy-mm-dd') + 1 "; 6 } 7 if (StringUtils.isNotBlank(searchSMS.getSendContent())) { 8 sql += "and id in (select TASKID from SMS_SYNC where TASKID=sms_task.id and msgcontent like '%" + searchSMS.getSendContent() + "%')"; 9 }10 if (StringUtils.isNotBlank(searchSMS.getSendPhone())) {11 sql += "and id in (select TASKID from SMS_SYNC where TASKID=sms_task.id and mobile like '%" + searchSMS.getSendPhone() + "%')";12 }
你一定感受過為了一個逗號而抓狂的經(jīng)歷,拼接的時候提醒自己一定不能忘了添加前后的空格和刪除句末的逗號。
幸運的是,通過動態(tài)SQL這樣的問題在Mybatis中不復存在。通過<where>來智能識別語句前后的and/or,<set>來識別語句前后的逗號,或使用<trim>來自定義實現(xiàn)。
通過<if test>來判斷字段是否為空,<choose><when><otherwise>來實現(xiàn)類似switch……case的效果,<foreach>來實現(xiàn)集合的遍歷,這里介紹了動態(tài)SQL。
總結:Mybatis框架優(yōu)越之處在于使用XML映射文件替代了JDBC中手工設置屬性,降低SQL代碼耦合性,將動態(tài)SQL與其他Java代碼分離,使得代碼看起來更加整潔并有利于重用;提供緩存、自動映射功能,并通過一系列設置合理的默認值來簡化開發(fā)者的工作。
新聞熱點
疑難解答