Mybatis

1.Mybatis简介

持久层框架,使用xml将sql与程序解耦,便于维护,是jdbc的延伸。

2.开发流程

  • 引入Mybatis依赖

  • 创建核心配置文件
    在resources下面创建mybatis-config.xml文件,配置数据库环境信息

      <configuration>
      <!--    设置默认指向的数据库-->
          <environments default="dev">
      <!--        配置环境,不同的环境不同的id名字-->
              <environment id="dev">
      <!--            采用jdbc方式对数据库事务进行commit/rollback-->
                  <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="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语句,用于区分不同的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单参数传值-->
          <select id="selectById" parameterType="Integer" resultType="org.example.entity.Goods">
              select * from t_goods where goods_id = #{value}
          </select>
          <!--    select多个参数传值-->
          <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保存多表关联结果
              MyBatis会将每一条记录包装成为Map对象
              key是字段名 value是字段对应的值,字段类型根据标结果进行自动判断
              优点:易于扩展,易于使用
              缺点:太过灵活,无法进行编译检查
          -->
          <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");
      //单参数传值
      Goods goods = session.selectOne("goods.selectById",1602);
      //多个参数传值
      //可以不加namespace,确保id是唯一即可
      List<Goods> list = session.selectList("selectByPriceRange",param);
      //多表关联
      List<Map> list = session.selectList("goods.selectGoodsMap");
    
  • 创建实体(Entity)类

  • 创建Mapper映射文件

  • 初始化SessionFactory

SessionFactory是Mybatis的核心对象,用于初始化Mybatis,创建SqlSession对象,是全局唯一的

  • 利用SqlSession对象操作数据

SqlSession是Mybatis操作数据库的核心对象,使用JDBC方式与数据库交互,提供了CRUD对应的方法

2.1.MyBatis数据查询步骤

  • 创建实体类(Entity)
  • 创建Mapper XML
  • 编写<select>SQL标签
  • 开启驼峰命名映射
  • 新增<mapper>
  • SqlSession执行select语句

3.ResultMap结果映射

  • ResulMap可以将查询结果映射为复杂类型的Java对象
  • ResultMap适用于Java对象保存多表关联结果
  • ResultMap支持对象关联查询登高级特性

xml中返回类型标签用的是resultMap,并且创建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.数据插入

4.1.数据库事务

是保证数据库操作完整性的基础

  • commit
  • rollback

4.2.数据库写操作

4.2.1.插入-insert

使用<insert>标签,如果想要获得插入的id,可以使用

  • <selectKey>标签查询插入后的主键id

      --goods.xml
    
      <!--    数据插入-->
      <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})
          --         插入数据库后取最新插入的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方法返回值代表本次成功插入的记录数
              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方法返回值代表本次成功插入的记录数
              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标签是通用方案,适用于所有数据库,但是编写麻烦
  • useGeneratedKeys属性只支持“自增主键”数据库,使用简单(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方法返回值代表本次成功插入的记录数
              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方法返回值代表本次成功插入的记录数
              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漏洞,绕过系统约束,越权获取数据的攻击方式

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='' ';

则可查询所有数据。

原因:
${}是文本替换,未经过任何处理对SQL文本替换,我们需要使用#{}预编译传值,使用预编译传值可以预防SQL注入

6.MyBatis工作流程

应用pom导入mybatis,mysql-connector-java依赖创建mybatis-config.xml,全局设置项,环境配置,mapper声明,通过SqlSessionFactoryBuilder创建全局唯一的SqlSessionFactory,通过SqlSessionFactory创建SqlSession,解析mapper.xml,执行对应的sql语句,数据修改时候需要调用commit方法,最后需要close对应的session。

1-1.jpg
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,635评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,628评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,971评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,986评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,006评论 6 394
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,784评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,475评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,364评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,860评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,008评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,152评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,829评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,490评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,035评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,428评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,127评论 2 356

推荐阅读更多精彩内容