1.Mybatis簡介
持久層框架,使用xml將sql與程序解耦,便于維護,是jdbc的延伸。
2.開發(fā)流程
引入Mybatis依賴
-
創(chuàng)建核心配置文件
在resources下面創(chuàng)建mybatis-config.xml文件,配置數(shù)據(jù)庫環(huán)境信息<configuration> <!-- 設置默認指向的數(shù)據(jù)庫--> <environments default="dev"> <!-- 配置環(huán)境,不同的環(huán)境不同的id名字--> <environment id="dev"> <!-- 采用jdbc方式對數(shù)據(jù)庫事務進行commit/rollback--> <transactionManager type="JDBC"></transactionManager> <!-- 采用連接池方式管理數(shù)據(jù)庫連接--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/babytun?useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="111111"/> </dataSource> </environment> <environment id="prd"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/babytun?useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="111112"/> </dataSource> </environment> </environments> </configuration> <mappers> <!-- 對應的sql mapper映射文件--> <mapper resource="mappers/goods.xml"/> </mappers> ------goods.xml內容------ <?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"> <!--命名空間類似于java中的包 不同表或者功能的sql語句,用于區(qū)分不同的sql語句--> <mapper namespace="goods"> <!-- 同一個namespqce下的id要唯一,resultType返回的結果類型,進行包裝--> <select id="selectAll" resultType="org.example.entity.Goods"> select * from t_goods order by goods_id desc limit 10 </select> <!-- select單參數(shù)傳值--> <select id="selectById" parameterType="Integer" resultType="org.example.entity.Goods"> select * from t_goods where goods_id = #{value} </select> <!-- select多個參數(shù)傳值--> <select id="selectByPriceRange" parameterType="java.util.Map" resultType="org.example.entity.Goods"> select * from t_goods where current_price between #{min} and #{max} order by current_price limit 0,#{limit} </select> <!--利用LinkedHashMap保存多表關聯(lián)結果 MyBatis會將每一條記錄包裝成為Map對象 key是字段名 value是字段對應的值,字段類型根據(jù)標結果進行自動判斷 優(yōu)點:易于擴展,易于使用 缺點:太過靈活,無法進行編譯檢查 --> <select id="selectGoodsMap" resultType="java.util.LinkedHashMap"> select g.*, c.category_name,'1' as test from t_goods g,t_category c where g.category_id = c.category_id limit 10 </select> </mapper> ---------對應實體類--------- //查詢所有 List<Goods> list = session.selectList("goods.selectAll"); //單參數(shù)傳值 Goods goods = session.selectOne("goods.selectById",1602); //多個參數(shù)傳值 //可以不加namespace,確保id是唯一即可 List<Goods> list = session.selectList("selectByPriceRange",param); //多表關聯(lián) List<Map> list = session.selectList("goods.selectGoodsMap"); 創(chuàng)建實體(Entity)類
創(chuàng)建Mapper映射文件
初始化SessionFactory
SessionFactory是Mybatis的核心對象,用于初始化Mybatis,創(chuàng)建SqlSession對象,是全局唯一的
- 利用SqlSession對象操作數(shù)據(jù)
SqlSession是Mybatis操作數(shù)據(jù)庫的核心對象,使用JDBC方式與數(shù)據(jù)庫交互,提供了CRUD對應的方法
2.1.MyBatis數(shù)據(jù)查詢步驟
- 創(chuàng)建實體類(Entity)
- 創(chuàng)建Mapper XML
- 編寫<select>SQL標簽
- 開啟駝峰命名映射
- 新增<mapper>
- SqlSession執(zhí)行select語句
3.ResultMap結果映射
- ResulMap可以將查詢結果映射為復雜類型的Java對象
- ResultMap適用于Java對象保存多表關聯(lián)結果
- ResultMap支持對象關聯(lián)查詢登高級特性
xml中返回類型標簽用的是resultMap,并且創(chuàng)建DTO
<!-- 結果映射-->
<resultMap id="rmGoods" type="org.example.dto.GoodsDTO">
<!-- 設置主鍵字段與屬性映射-->
<id property="goods.goodsId" column="goods_id"></id>
<!-- 設置非主鍵字段與屬性映射-->
<result property="goods.originalCost" column="original_cost"></result>
<result property="goods.title" column="title"></result>
<result property="goods.subtitle" column="subtitle"></result>
<result property="goods.currentPrice" column="current_price"></result>
<result property="goods.discount" column="discount"></result>
<result property="goods.isFreeDelivery" column="is_free_delivery"></result>
<result property="goods.categoryId" column="category_id"></result>
<result property="category.categoryId" column="category_id"></result>
<result property="category.categoryName" column="category_name"></result>
<result property="category.parentId" column="parent_id"></result>
<result property="category.categoryLevel" column="category_level"></result>
<result property="category.categoryOrder" column="category_order"></result>
<result property="test" column="test"></result>
</resultMap>
<select id="selectGoodsDTO" resultMap="rmGoods">
select g.*, c.*,'1' as test from t_goods g,t_category c where g.category_id = c.category_id limit 10
</select>
----------------------------------
public class GoodsDTO {
private Goods goods;
private Category category;
-----------------------------------
List<GoodsDTO> list = session.selectList("goods.selectGoodsDTO");
for (int i = 0; i < list.size(); i++) {
GoodsDTO goodsDTO = list.get(i);
System.out.print(goodsDTO.getGoods().getTitle() + "------");
System.out.println(goodsDTO.getCategory().getCategoryName());
}
4.數(shù)據(jù)插入
4.1.數(shù)據(jù)庫事務
是保證數(shù)據(jù)庫操作完整性的基礎
- commit
- rollback
4.2.數(shù)據(jù)庫寫操作
4.2.1.插入-insert
使用<insert>標簽,如果想要獲得插入的id,可以使用
-
<selectKey>標簽查詢插入后的主鍵id
--goods.xml <!-- 數(shù)據(jù)插入--> <insert id="insert" parameterType="org.example.entity.Goods"> INSERT INTO t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id) VALUES (#{title}, #{subTitle}, #{originalCost}, #{currentPrice}, #{discount}, #{isFreeDelivery}, #{categoryId}) -- 插入數(shù)據(jù)庫后取最新插入的id復制給goodsId <selectKey resultType="Integer" keyProperty="goodsId" order="AFTER"> select last_insert_id() </selectKey> </insert> --調用 @Test public void testInsert() { SqlSession session = null; try { session = MyBatisUtils.openSession(); Goods goods = new Goods(); goods.setTitle("測試商品"); goods.setSubTitle("測試子標題"); goods.setOriginalCost(200f); goods.setCurrentPrice(100f); goods.setDiscount(0.5f); goods.setIsFreeDelivery(1); goods.setCategoryId(43); //insert方法返回值代表本次成功插入的記錄數(shù) int num = session.insert("goods.insert", goods); //提交事務 session.commit(); System.out.println(goods.getGoodsId()); }catch (Exception e) { if (session != null){ session.rollback();//回滾事務 } throw e; } MyBatisUtils.closeSession(session); } -
useGeneratedKeys屬性
--goods.xml <insert id="insert" parameterType="org.example.entity.Goods" useGeneratedKeys="true" keyProperty="goodsId" keyColumn="goods_id" > INSERT INTO t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id) VALUES (#{title}, #{subTitle}, #{originalCost}, #{currentPrice}, #{discount}, #{isFreeDelivery}, #{categoryId}) </insert> --調用 @Test public void testInsert() { SqlSession session = null; try { session = MyBatisUtils.openSession(); Goods goods = new Goods(); goods.setTitle("測試商品"); goods.setSubTitle("測試子標題"); goods.setOriginalCost(200f); goods.setCurrentPrice(100f); goods.setDiscount(0.5f); goods.setIsFreeDelivery(1); goods.setCategoryId(43); //insert方法返回值代表本次成功插入的記錄數(shù) int num = session.insert("goods.insert", goods); //提交事務 session.commit(); System.out.println(goods.getGoodsId()); }catch (Exception e) { if (session != null){ session.rollback();//回滾事務 } throw e; } MyBatisUtils.closeSession(session); }
對比:
- selectKey標簽是通用方案,適用于所有數(shù)據(jù)庫,但是編寫麻煩
- useGeneratedKeys屬性只支持“自增主鍵”數(shù)據(jù)庫,使用簡單(Oracle不支持自增主鍵)
4.2.2.更新-update
-
goods.xml
<update id="update" parameterType="org.example.entity.Goods">
UPDATE t_goods
SET
title = #{title},
sub_title = #{subTitle},
original_cost = #{originalCost},
current_price = #{currentPrice},
discount = #{discount},
is_free_delivery = #{isFreeDelivery},
category_id = #{categoryId}
WHERE
goods_id = #{goodsId}
</update>
-
測試方法
@Test public void testUpdate() { SqlSession session = null; try { session = MyBatisUtils.openSession(); Goods goods = session.selectOne("goods.selectById", 739); goods.setTitle("更新測試商品"); //insert方法返回值代表本次成功插入的記錄數(shù) int num = session.update("goods.update", goods); //提交事務 session.commit(); System.out.println(goods.getGoodsId()); }catch (Exception e) { if (session != null){ session.rollback();//回滾事務 } throw e; } MyBatisUtils.closeSession(session); }
4.2.3.刪除-delete
-
goods.xml
<!-- 刪除操作--> <delete id="delete" parameterType="Integer"> DELETE FROM t_goods WHERE goods_id = #{value} </delete> -
測試類
@Test public void testDelete() { SqlSession session = null; try { session = MyBatisUtils.openSession(); //insert方法返回值代表本次成功插入的記錄數(shù) int num = session.delete("goods.delete", 739); //提交事務 session.commit(); }catch (Exception e) { if (session != null){ session.rollback();//回滾事務 } throw e; } MyBatisUtils.closeSession(session); }
5.SQL注入
SQL注入是指攻擊者利用SQL漏洞,繞過系統(tǒng)約束,越權獲取數(shù)據(jù)的攻擊方式
SQL代碼:
"select * from a where name = '" + name + "'";
正常情況:
name:張三 -》 select * from a where name = '張三';
SQL注入攻擊:
name:' or 1=1 or 1= '
select * from a where name = ' '' or 1=1 or name='' ';
則可查詢所有數(shù)據(jù)。
原因:
${}是文本替換,未經(jīng)過任何處理對SQL文本替換,我們需要使用#{}預編譯傳值,使用預編譯傳值可以預防SQL注入
6.MyBatis工作流程
應用pom導入mybatis,mysql-connector-java依賴創(chuàng)建mybatis-config.xml,全局設置項,環(huán)境配置,mapper聲明,通過SqlSessionFactoryBuilder創(chuàng)建全局唯一的SqlSessionFactory,通過SqlSessionFactory創(chuàng)建SqlSession,解析mapper.xml,執(zhí)行對應的sql語句,數(shù)據(jù)修改時候需要調用commit方法,最后需要close對應的session。
