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
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容