內(nèi)容接著上一篇文章,Mybatis搭建環(huán)境(2)
先把dao層的接口給出來(lái),和UserMapper.xml中的mapper標(biāo)簽的namespace屬性對(duì)接邓萨。
package cn.com.mybatis.dao;
import cn.com.mybatis.po.User;
public interface UserDao {
User findUserById(int id);
User findUserByUsername(String username);
int insertUser(User user);
int deleteUser(int id);
User updateUserName(String username);
}
1. 模糊查詢樣例
要對(duì)數(shù)據(jù)庫(kù)中User表的數(shù)據(jù)進(jìn)行模糊查詢冰寻,需要通過(guò)匹配名字的某個(gè)字來(lái)查詢?cè)撚脩艟踉模紫仍赨serMapper.xml文件中配置SQL映射:
<!--根據(jù)用戶姓名進(jìn)行模糊查詢-->
<select id="findUserByUsername" parameterType="java.lang.String" resultType="cn.com.mybatis.po.User">
SELECT * FROM USER WHERE username LIKE '%${value}'
</select>
這里“${}”符號(hào)表示拼接SQL串,將收到的參數(shù)內(nèi)容不加任何修飾地拼接在SQL中嗜闻,在“${}”中只能使用value代表其中的參數(shù)蜕依。然而在Web項(xiàng)目中,如果沒(méi)有防范SQL注入的機(jī)制琉雳,要謹(jǐn)慎使用“${}”符號(hào)拼接SQL語(yǔ)句串样眠,因?yàn)檫@可能會(huì)引起SQL注入的風(fēng)險(xiǎn)。
然后在MyBatisTest測(cè)試類(lèi)中寫(xiě)一個(gè)新的測(cè)試方法TestFuzzySearch翠肘,來(lái)查詢所有名稱中含有“麗”字的用戶信息檐束。
@Test
public void TestFuzzySearch() throws IOException{
SqlSession sqlSession = dataConn.getSqlSession();
List<User> userList = sqlSession.selectList("cn.com.mybatis.dao.UserDao.findUserByUsername","麗");
for(User user : userList){
System.out.println("姓名:"+user.getUsername());
System.out.println("性別:"+user.getGender());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
System.out.println("生日:"+sdf.format(user.getBirthday()));
System.out.println("所在地:"+user.getProvince()+user.getCity());
}
sqlSession.close();;
}
2. 新增樣例
要對(duì)數(shù)據(jù)庫(kù)中User表進(jìn)行新增數(shù)據(jù),在UserMapper.xml文件中配置SQL映射:
<!--在表中新增數(shù)據(jù)信息-->
<insert id="insertUser" parameterType="cn.com.mybatis.po.User">
INSERT INTO USER(username, password, gender, birthday, email, province, city)
VALUE (#{username}, #{password}, #{gender}, #{birthday,jdbcType=DATE}, #{email}, #{province}, #{city})
</insert>
在測(cè)試類(lèi)MyBatisTest中添加名為T(mén)estInsert方法锯茄,向User表新插入一條用戶數(shù)據(jù)厢塘。
@Test
public void TestInsert() throws Exception{
SqlSession sqlSession = dataConn.getSqlSession();
User user = new User();
user.setUsername("孫佳佳");
user.setGender("男");
user.setPassword("5555");
user.setEmail("5555@126.com");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
user.setBirthday(sdf.parse("1991-02-16"));
user.setProvince("湖北省");
user.setCity("武漢市");
sqlSession.insert("cn.com.mybatis.dao.UserDao.insertUser",user);
sqlSession.commit();
sqlSession.close();
}
如果想在插入之后不執(zhí)行查詢語(yǔ)句而立即獲取id信息,有兩種方法肌幽,這里針對(duì)Mysql為例:
- 通過(guò)Mysql的函數(shù)SELECT LAST_INSERT_ID()來(lái)獲取剛剛插入記錄的自增主鍵(即取出最后一個(gè)主鍵)晚碾。
這里order參數(shù)表示該SQL函數(shù)相對(duì)于insert語(yǔ)句的執(zhí)行時(shí)間,有BEFORE和AFTER喂急。這里程序執(zhí)行完insert之后格嘁,就可以在測(cè)試類(lèi)中,從user對(duì)象中直接拿到該id的信息(取出的主鍵信息會(huì)放置在輸入?yún)?shù)user對(duì)象中)廊移。
- 通過(guò)Mysql的函數(shù)SELECT LAST_INSERT_ID()來(lái)獲取剛剛插入記錄的自增主鍵(即取出最后一個(gè)主鍵)晚碾。
<!--在表中新增數(shù)據(jù)信息-->
<insert id="insertUser" parameterType="cn.com.mybatis.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO USER(username, password, gender, birthday, email, province, city)
VALUE (#{username}, #{password}, #{gender}, #{birthday,jdbcType=DATE}, #{email}, #{province}, #{city})
</insert>
- 在insert標(biāo)簽中添加屬性“useGenerateKeys”和“keyProperty”,其中userGeneratedKeys表示使用自增主鍵糕簿,而keyProperty是Java對(duì)象的屬性名。
<!--在表中新增數(shù)據(jù)信息-->
<insert id="insertUser" parameterType="cn.com.mybatis.po.User"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO USER(username, password, gender, birthday, email, province, city)
VALUE (#{username}, #{password}, #{gender}, #{birthday,jdbcType=DATE}, #{email}, #{province}, #{city})
</insert>
進(jìn)行完上面的配置后狡孔,MyBatis執(zhí)行完insert語(yǔ)句后懂诗,會(huì)自動(dòng)將自增長(zhǎng)id值賦給對(duì)象User的屬性id,然后在邏輯處理層就可以通過(guò)User的get方法獲得該id苗膝。
3. 刪除與修改樣例
對(duì)于刪除和修改殃恒,同樣需要在UserMapper.xml配置文件中編寫(xiě)相關(guān)的SQL配置:
<!--刪除用戶-->
<delete id="deleteUser" parameterType="java.lang.Integer">
DELETE FROM USER WHERE id=#{id}
</delete>
<!--修改用戶-->
<update id="updateUserName" parameterType="cn.com.mybatis.po.User">
UPDATE USER SET username=#{username} where id=#{id}
</update>
在MyBatisTest測(cè)試類(lèi)中添加TestDelete和TestUpdate測(cè)試方法:
@Test
public void TestDelete() throws Exception{
SqlSession sqlSession = dataConn.getSqlSession();
sqlSession.delete("cn.com.mybatis.dao.UserDao.deleteUser",5);
sqlSession.commit();
sqlSession.close();
}
@Test
public void TestUpdate() throws Exception{
SqlSession sqlSession = dataConn.getSqlSession();
User user = new User();
user.setId(4);
user.setUsername("孫麗");
sqlSession.update("cn.com.mybatis.dao.UserDao.updateUserName", user);
sqlSession.commit();
sqlSession.close();
}
到此Mybatis的基本入門(mén)操作就完成了,下面補(bǔ)充一下注意的事項(xiàng):
- 關(guān)于parameterType:
在執(zhí)行SQL配置時(shí)辱揭,需要指定輸入?yún)?shù)的類(lèi)型离唐。parameterType就是用來(lái)在SQL映射文件指定輸入?yún)?shù)類(lèi)型的。使用parameterType可以指定參數(shù)為基本數(shù)據(jù)類(lèi)型(如 int问窃、float等)亥鬓、包裝數(shù)據(jù)類(lèi)型(Integer類(lèi)、Double類(lèi))以及用戶編寫(xiě)的JavaBean封裝類(lèi)域庇。 - 關(guān)于resultType:
在加載SQL配置嵌戈,并綁定制定輸入?yún)?shù)和運(yùn)行SQL之后覆积,會(huì)得到數(shù)據(jù)庫(kù)返回的相應(yīng)結(jié)果,此時(shí)使用resultType來(lái)指定數(shù)據(jù)庫(kù)返回的信息對(duì)應(yīng)Java的數(shù)據(jù)類(lèi)型咕别。輸出參數(shù)的類(lèi)型為基本數(shù)據(jù)類(lèi)型(如 int技健、float等)、包裝數(shù)據(jù)類(lèi)型(Integer類(lèi)惰拱、Double類(lèi))以及用戶自己編寫(xiě)的JavaBean的封裝類(lèi)妥凳。 - 關(guān)于“#{}”:
在SQL配置文件中咒循,輸入?yún)?shù)需要占位符來(lái)標(biāo)識(shí)對(duì)應(yīng)的位置。在傳統(tǒng)的JDBC的編程中凯旋,占位符用"?"來(lái)表示馋没,然后在加載SQL之前按照"?"的位置設(shè)置參數(shù)昔逗。在MyBatis中也是一種占位符,它接受輸入?yún)?shù)篷朵,在大括號(hào)中編寫(xiě)參數(shù)名稱來(lái)接受對(duì)應(yīng)參數(shù)勾怒。“#{}”接受的可以是簡(jiǎn)單類(lèi)型声旺、普通JavaBean或者HashMap笔链。里面可以寫(xiě)value或者其他名稱。若接受的是JavaBean腮猖,它通過(guò)OGNL讀取對(duì)象中的屬性值鉴扫,通過(guò)“屬性1.屬性2.屬性3等”的方式獲取對(duì)象屬性值。 - 關(guān)于“${}”:
在SQL配置中澈缺,有時(shí)需要拼接SQL語(yǔ)句坪创。例如在模糊查詢時(shí),就需要在查詢條件的兩側(cè)拼接兩個(gè)“%”字符串姐赡,這時(shí)“#{}”就不行莱预。在MyBatis中,“${}”在SQL配置文件中表示的是一個(gè)“拼接符號(hào)”项滑,可以在原有SQL語(yǔ)句上拼接新的符合SQL語(yǔ)法的語(yǔ)句依沮。單用“${}”會(huì)引起SQL注入,慎用杖们。另外悉抵,當(dāng)接受簡(jiǎn)單類(lèi)型時(shí),“${}”中只能寫(xiě)“value”摘完,而不能寫(xiě)其他名稱姥饰。其他內(nèi)容同上。
注意 ${} 和 #{} 的區(qū)別:
動(dòng)態(tài) sql 是 mybatis 的主要特性之一孝治,在 mapper 中定義的參數(shù)傳到 xml 中之后列粪,在查詢之前 mybatis 會(huì)對(duì)其進(jìn)行動(dòng)態(tài)解析审磁。mybatis 為我們提供了兩種支持動(dòng)態(tài) sql 的語(yǔ)法:#{} 以及 ${}。
- ${}哪邊都能使用岂座,只是存在sql注入風(fēng)險(xiǎn)态蒂,相當(dāng)于直接拼接字符串,不對(duì)參數(shù)做任何處理费什。
- #{}會(huì)進(jìn)行預(yù)編譯钾恢,對(duì)參數(shù)進(jìn)行處理,防止注入鸳址。
<!--在下面的語(yǔ)句中瘩蚪,如果 username 的值為 zhangsan,則兩種方式無(wú)任何區(qū)別:--> select * from user where name = #{name}; select * from user where name = ${name}; <!--解析出來(lái)的結(jié)果都是如下:--> select * from user where name = 'zhangsan';
- 但是 #{} 和 ${} 在預(yù)編譯中的處理是不一樣的稿黍。#{} 在預(yù)處理時(shí)疹瘦,會(huì)把參數(shù)部分用一個(gè)占位符 ? 代替,變成如下的 sql 語(yǔ)句:
elect * from user where name = ?;
- 而 ${} 則只是簡(jiǎn)單的字符串替換巡球,在動(dòng)態(tài)解析階段言沐,該 sql 語(yǔ)句會(huì)被解析成:
select * from user where name = 'zhangsan';
- 以上,#{} 的參數(shù)替換是發(fā)生在 DBMS 中酣栈,而 ${} 則發(fā)生在動(dòng)態(tài)解析過(guò)程中险胰。
那么,在使用過(guò)程中我們應(yīng)該使用哪種方式呢钉嘹?
答案是鸯乃,優(yōu)先使用 #{}。因?yàn)?${} 會(huì)導(dǎo)致 sql 注入的問(wèn)題跋涣∮看下面的例子:select * from ${tableName} where name = #{name} <!--若表名為user; delete user; 則動(dòng)態(tài)解析之后 sql 如下:-- --> select * from user; delete user; -- where name = ?;
之后的語(yǔ)句被注釋掉,而原本查詢用戶的語(yǔ)句變成了查詢所有用戶信息+刪除用戶表的語(yǔ)句陈辱,會(huì)對(duì)數(shù)據(jù)庫(kù)造成重大損傷奖年,極大可能導(dǎo)致服務(wù)器宕機(jī)
- 既然這樣那為什么還要用${}呢。
因?yàn)槭褂?{}存在一個(gè)不足沛贪,當(dāng)參數(shù)為字符串時(shí)會(huì)加上'',這就導(dǎo)致某些情況下sql失效陋守。
SELECT * FROM #{tableName},當(dāng)使用#{}傳入?yún)?shù)user利赋,sql就會(huì)變成
SELECT * FROM 'user'. 這樣就會(huì)報(bào)錯(cuò)查詢不到數(shù)據(jù)
- 關(guān)于“selectOne”與“selectList”:
它們都屬于SqlSession類(lèi)提供的方法,在使用查詢語(yǔ)句時(shí)媚送,如果查詢的數(shù)據(jù)只有一條數(shù)據(jù)中燥,那么可以使用“selectOne”方法進(jìn)行查詢;如果查詢的數(shù)據(jù)可能多于一條塘偎,那么可以使用“selectList”方法進(jìn)行查詢疗涉。 - MyBatis與Hibernate區(qū)別:
MyBatis的特點(diǎn)就是以SQL語(yǔ)句為核心的不完全的ORM(關(guān)系型映射)框架拿霉。與Hiberna相比,Hibernate的學(xué)習(xí)成本比較高咱扣,而SQL語(yǔ)句并不需要開(kāi)發(fā)人員完成绽淘,只需調(diào)用相關(guān)API即可。這對(duì)于開(kāi)發(fā)效率是一個(gè)優(yōu)勢(shì)闹伪,但是缺點(diǎn)時(shí)沒(méi)辦法對(duì)SQL語(yǔ)句進(jìn)行優(yōu)化和修改沪铭。而MyBatis雖然需要開(kāi)發(fā)人員自己配置SQL語(yǔ)句,MyBatis來(lái)實(shí)現(xiàn)映射關(guān)系偏瓤,但是這樣的項(xiàng)目可以適應(yīng)經(jīng)常變化的項(xiàng)目需求伦意。所以,使用MyBatis的場(chǎng)景是:對(duì)SQL優(yōu)化要求比較高硼补,或是項(xiàng)目需求或業(yè)務(wù)經(jīng)常變動(dòng)。