Mybatis

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&amp;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&amp;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。

1-1.jpg
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容