Mybatis

一、SSM框架介绍

1.框架

(1)什么是框架

框架是可被应用开发者定制的应用骨架

框架是一种规则,保证开发者遵循相同的方式开发程序

框架提倡”不要重复造轮子”,对基础功能进行封装

(2)框架的优点

极大提高了开发效率

统一的编码规则,利于团队管理

灵活配置的应用,拥有更好的维护性

2.SSM

(1)Spring

Spring是一个对象容器框架,作用是对系统中的各个对象进行管理。

是一种框架的框架,也就是其他的框架,要基于Spring这个容器框架进行开发。

(2)SpringMVC

SpringMVC是一种架构模式,帮助我们对Web应用程序进行分层,进行有效的解耦,是一种Spring的分支产品,让我们更有效的进行Web开发。

(3)Mybatis 

数据交互的框架,封装和扩展JDBC的操作,简化开发。

(4)三者相互作用

Spring提供了底层的对象管理,SpringMVC提供了Web层面的交互,Mybatis则提供了数据库的从删改查的便捷操作。

二、Mybatis介绍

1.什么是Mybatis

MyBatis是优秀的持久层框架

MyBatis使用XML将SQL与程序解耦,便于维护

MyBatis学习简单,执行高效,是JDBC的延伸

2.Mybatis开发流程 6步

引入MyBatis依赖

创建核心配置文件

创建实体(Entity)类

创建Mapper映射文件

初始化SessionFactory

利用SgISession对象操作数据

三、Mybatis基本使用

1.Mybatis环境配置

环境配置就是要配置Mysql的驱动,连接,用户名,密码等信息,这些信息一帮配置在Mybatis的

mybatis-config.xml文件里面

MyBatis采用XML格式配置数据库环境信息

MyBaits环境配置标签<environment>

environment包含数据库驱动、URL、用户名与密码

f8d3796b70c94137bed92c49c033cd7b.png

005a4d800a3347d38ead32b28dbefb67.png

2.SqlSessionFactory

SqlSessionFactory是MyBatis的核心对象

用于初始化MyBatis(加载配置文件),创建SgISession对象

保证SglSessionFactory在应用中全局唯一

3.SqlSession

SqlSession是MyBatis操作数据库的核心对象

SqISession使用JDBC方式与数据库交互

SqISession对象提供了数据表CRUD对应方法

创建SqlSessionFactory和SqlSession示例代码 

//利用Reader加载classpath下的mybatis-config.xml核心配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//初始化SqlSessionFactory对象,同时解析mybatis-config.xml文件 构造者模式
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//创建SqlSession对象,SqlSession是JDBc的扩展类,用于与数据库交互
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建数据库连接(测试用)实际上mybatis自动创建连接
Connection conn = null;
try {
    conn = sqlSession.getConnection();
} catch (Exception e) {
    throw new RuntimeException(e);
} finally {
    //如果type="POOLED",代表使用连接池,close则是将连接回收到连接池中
    //如果type=""UNPOOLED",代表直连,close则会调用Connection.close()方法关闭连接
    conn.close();
}

4.初始化工具类MybatisUtils

每次使用Mybatis时,要先创建SqlSessionFactory对象,要不断的cv代码,而且还要保证SglSessionFactory在应用中全局唯一,于是我们提取出公共的部分作为工具类使用。并提供获得SqlSession方法和关闭SqlSession的方法

/**
 * MyBatisUtils工具类,创建全局唯一的SqlSessionFactory对象
 */
public class MybatisUtils {
    //利用static(静态)属于类不属于对象,且全局唯一
    private static SqlSessionFactory sqlSessionFactory = null;
    //利用静态块在初始化类时实例化sqlSessionFactory
    static {
        Reader reader = null;
        try {
            reader = Resources.getResourceAsReader("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            //初始化错误时,通过抛出异常ExceptionInInitializerError通知调用者
            throw new ExceptionInInitializerError(e);
        }
    }
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
    public static void closeSqlSession(SqlSession sqlSession){
        if (sqlSession != null){
            sqlSession.close();
        }
    }
}

5.MyBatis数据查询

(1)步骤

创建实体类(Entity)

创建Mapper XML

编写<select>SQL标签

开启驼峰命名映射

新增<mapper>

SqlSession执行select语句

 (2)示例

创建实体类

public class Goods {

    private Integer goodsId;
    private String title;
    private String subTitle;
    private Float originalCost;
    private Float currentPrice;
    private Float discount;
    private Integer isFreeDelivery;
    private Integer categoryId;

    //还有对应的getter,setter方法
}

创建Mapper XML

编写<select>SQL标签

6af2423c3f7144128d33b0e23d29b4e2.png

<?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">
<mapper namespace="goods">
    <select id="selectAll" resultType="com.pzh.entity.Goods">
        select * from t_goods order by goods_id desc limit 10
    </select>
</mapper>

在Mybatis配置文件开启驼峰命名映射

<settings>
<!--        goods_id==>goodsId驼峰命名转换-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

在Mybatis配置文件新增<mapper>坐标,指明哪个mapper文件加入mybatis中

<mappers>
        <mapper resource="mappers/goods.xml"/>
</mappers>

最后的mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
<!--        goods_id==>goodsId驼峰命名转换-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <environments default="dev">
        <environment id="dev">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/babytun"/>
                <property name="username" value="root"/>
                <property name="password" value="12345678"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mappers/goods.xml"/>
    </mappers>
</configuration>

测试SqlSession执行select语句

@Test
    public void testSelectAll(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //参数是命名空间.id
        List<Goods> list = sqlSession.selectList("goods.selectAll");
        for(Goods goods : list){
            System.out.println(goods.getGoodsId());
        }
        MybatisUtils.closeSqlSession(sqlSession);
    }

四、SQL传参

查询-<select>为例

1.单参数传递

6fd0f464bb4a4722b1a8dd95c81eda04.png

parameterType表示传入参数的类型,resultType表示sql查询结果的返回类型

需求:

        按照goodsId查询商品信息 

配置mapper文件

<select id="selectById" parameterType="Integer" resultType="com.pzh.entity.Goods">
    select * from t_goods where goods_id = #{value}
</select>

测试方法

@Test
    public void testSelectById(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            //参数1   指明执行哪个SQL
            //参数2   指定SQL的参数
            Goods goods = sqlSession.selectOne("goods.selectById", 765);
            System.out.println(goods);

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            MybatisUtils.closeSqlSession(sqlSession);
        }
    }

2.多参数传递

在单参传递的基础上,将parameterType的值改为Map集合,即java.util.Map

需求:

        按照价格范围查询商品,并指定前几条数据

 配置mapper文件

<select id="selectByPriceRange" parameterType="java.util.Map" resultType="com.pzh.entity.Goods">
        select * from t_goods
        where current_price
        between #{min} and #{max}
        order by current_price desc
        limit #{limit}
</select>

 测试方法

@Test
public void testSelectByPriceRange(){
    SqlSession sqlSession = null;
    try {
        sqlSession = MybatisUtils.getSqlSession();
        HashMap<String, Integer> map = new HashMap<>();
        map.put("min", 100);
        map.put("max", 500);
        map.put("limit",10);
        List<Goods> list = sqlSession.selectList("goods.selectByPriceRange", map);
        list.stream().forEach(System.out::println);

    } catch (Exception e) {
        throw new RuntimeException(e);
    } finally {
        MybatisUtils.closeSqlSession(sqlSession);
    }
}

五、多表关联查询

1.分装复杂查询结果为dto类

多表关联查询的结果一般涉及多个不同表的列,我们的实体类是相对于单表的所有列的,不够用了,所以我们可以创建一个dto包,下面存放可以存放多表关联查询结果的dto类

select g.*, c.category_name, '1' as test
from t_goods g , t_category c
where g.category_id = c.category_id

对上面的多表查询可以封装为

public class GoodsDTO {
    private Goods goods = new Goods();
    private String categoryName;
    private String test;

    //对应的getter,setter方法
}

2.ResultMap结果映射

ResultMap可以将查询结果映射为复杂类型的Java对象

ResultMap适用于Java对象保存多表关联结果

ResultMap支持对象关联查询等高级特性

3.一对一查询

首先写多表关联查询的sql语句,分析出查询的结果的结构

创建接收查询结果的dto

public class GoodsDTO {
    private Goods goods = new Goods();
    private String categoryName;
    private String test;

    //对应的getter,setter方法
}

mapper配置文件 

<?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">
<mapper namespace="goods">
    <!--结果映射-->
    <resultMap id="oneToOne" type="com.pzh.dto.GoodsDTO">
        <!--设置主键与属性映射-->
        <id property="goods.goodsId" column="goods_id"></id>
        <!--设置非主键字段与属性映射-->
        <result property="goods.title" column="title"></result>
        <result property="goods.currentPrice" column="current_price"></result>
        <result property="goods.originalCost" column="original_cost"></result>
        <result property="goods.subTitle" column="sub_title"></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="categoryName" column="category_name"></result>
        <result property="test" column="test"></result>
    </resultMap>
    <select id="selectGoods" resultMap="oneToOne">
        select g.*, c.category_name, '1' as test
        from t_goods g , t_category c
        where g.category_id = c.category_id
    </select>
</mapper>

测试方法

@Test
public void testSelectGoodsDTO(){
    SqlSession sqlSession = null;
    try {
        sqlSession = MybatisUtils.getSqlSession();
        List<GoodsDTO> list = sqlSession.selectList("goods.selectGoods");
        list.stream().forEach(System.out::println);

    } catch (Exception e) {
        throw new RuntimeException(e);
    } finally {
        MybatisUtils.closeSqlSession(sqlSession);
    }
}

4.一对多查询

商品表t_goods的一行对应商品订单表t_goods_cover的多个行

首先写多表关联查询的sql语句,分析出查询的结果的结构

这里用内连接一样的

        select g.goods_id,f.*
        from t_goods g,t_goods_cover f
        where g.goods_id=f.goods_id
        order by g.goods_id desc

定义接收结果结构类dto

public class GoodsCoverDTO {
    private Integer goodsId;
    private List<GoodsCover> goodsCoverList;
   
    //对应的getter,setter。。

}

mapper文件添加配置

    <resultMap id="oneToMore" type="com.pzh.dto.GoodsCoverDTO">
        <id property="goodsId" column="goods_id"></id>
        <collection property="goodsCoverList" ofType="com.pzh.entity.GoodsCover">
            <id property="gcId" column="gc_id"></id>
            <result property="goodsId" column="goods_id"></result>
            <result property="gcPicUrl" column="gc_pic_url"></result>
            <result property="gcThumbUrl" column="gc_thumb_url"></result>
            <result property="gcOrder" column="gc_order"></result>
        </collection>
    </resultMap>
    <select id="selectGoodsCover" resultMap="oneToMore">
        select g.goods_id,f.*
        from t_goods g,t_goods_cover f
        where g.goods_id=f.goods_id
        order by g.goods_id desc
    </select>

测试方法

    @Test
    public void testSelectGoodsCoverDTO(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            List<GoodsCoverDTO> list = sqlSession.selectList("goods.selectGoodsCover");
            list.stream().forEach(System.out::println);

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            MybatisUtils.closeSqlSession(sqlSession);
        }
    }

4.多对一

一张商品表t_goods的一行对应商品详情表t_goods_detail的多个行,如果我们想要查询某个商品的所有详情就需要使用到多对一的对象关联查询。

在接收查询结果类DAO里面不仅有商品详情信息还要加上商品类

mapper配置文件

5.多对多查询

多对多的查询需要使用中间表,具体参考

09【MyBatis多表关联查询】-CSDN博客

两个dto类定义和1对多一样。

五、数据插入

1.Mybatis事务

c04bc5ccca27431cb5f3da17976bfe26.jpg

 2.mapper配置文件

17436b953e004542959e5c1f7fec3e8c.jpg

 用selectKey将最新的主键值返回

3.测试方法

f4c986dcbe0746358ecdb8e2f7066df3.jpg

4.selectKey和useGeneratedKeys的区别

selectKey和useGeneratedKeys都是将最新的主键值返回,但他们有区别

selectKey必须写在insert标签里面

f4f6d15cd01a4d498a0cbb4b9e70c22c.jpg

 useGeneratedKeys则是insert标签的一个属性

7fc98a27e18346e8964ee2604d388f9a.jpg

 其他区别

01a7de8633a44804bdd55eb4e202a9bc.jpg

919fa13708364bbd888608fc45f26fe4.jpg

76056cc83ecd4b9886ae4f2c2fefdc22.jpg

 Oracle不支持useGeneratedKeys

 总结

b161ad16a6e04f819ba4f6efa852c30b.jpg

 六、数据更新和删除

1.mapper文件

f16ee1cd5087411b89b9e17fc14697b3.jpg

5eff664708384f99beb2fef61b4b4a9b.jpg

 2.测试方法

3e83c08ecd984e26bf08f0988bf87944.jpg

ff4dfd030d9c45cfbba1499e4ac2d486.jpg

 七、预防SQL注入攻击

1.SQL注入

3ff7a6f5ba2c4d929d7a4812b992b556.jpg

2.Mybatis两种传值方式

3b2b125a27694815a9cf455c18d870cb.jpg

${} 应用于非用户输入的传值,一般用于SQL子句的拼接。

#{}应用于用户的输入,不能用于SQL子句的拼接 ,一般用于用户输入传值。

f83e1f5a18054a289a1c6ff253b93456.jpg

68a39441ec8941d1acba427da988a860.jpg

 八、总结Mybatis工作流程

ea3b33eb948c40288aec06d20b645aa9.jpg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值