mybatis简介

什么是mybatis?

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

mybatis开发流程

  1. 引入依赖
  2. 创建核心配置文件
  3. 创建实体类
  4. 创建Mapper映射文件
  5. 初始化SessionFactory
  6. 利用sqlSession对象操作数据

引入依赖

pom.xml

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.1</version>
</dependency>

创建核心配置文件

resources/mybatis-config.xml

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 驼峰命名设置 -->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <property name="helperDialect" value="mysql"/>
            <property name="reasonable" value="true"/>
        </plugin>
    </plugins>
    <!--  设置默认指向的数据库  -->
    <environments default="dev">
        <!-- 配置环境,不同的环境不同的id名字 -->
        <environment id="dev">
            <!-- 采用JDBC的方式对数据库事务进行commit/rollback-->
            <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?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="xxxx"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mappers/goods.xml"/>
    </mappers>
</configuration>

创建实体类

public class Goods {
    private Integer goodsId; //商品编号
    private String title; // 标题
    private String subTitle; //子标题
    private Float originalCost; // 原始价格
    private Float currentPrice; // 当前价格
    private Float discount; // 折扣率
    private Integer isFreeDelivery; // 是否包邮 1-包邮 0-不包邮
    private Integer categoryId; // 分类编号
	private List<GoodsDetail> goodsDetails;
	//省略getter/setter
}

public class GoodsDetail {
    private Integer gdId;
    private Integer goodsId;
    private String gdPicUrl;
    private Integer gdOrder;
    private Goods goods;
}

public class Category {
    private Integer categoryId;
    private String categoryName;
    private Integer parentId;
    private Integer categoryLevel;
    private Integer categoryOrder;
}

public class GoodsDTO {
    private Goods goods = new Goods();
    private Category category;
    private String test;
}

创建mapper映射文件

resources/mapper/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">
<mapper namespace="goods">
<!--    开启二级缓存
    eviction策略
    LRU – 最近最少使用:移除最长时间不被使用的对象。
    FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
    SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
    WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

    flushInterval /ms
-->
    <cache eviction="LRU" flushInterval="600000" size="512" readOnly="true"/>
    <select id="selectAll" resultType="com.imooc.mybatis.entity.Goods">
        select * from t_goods order by goods_id desc limit 10
    </select>
<!-- 单参数传递,使用parameterType指定参数的数据类型即可,SQL中#{value}提取参数   -->
    <select id="selectById" parameterType="Integer" resultType="com.imooc.mybatis.entity.Goods">
        select * from t_goods where goods_id = #{value}
    </select>
<!--  多参数传递,使用parameterType指定Map接口,SQL中#{key}提取参数  -->
    <select id="selectByPriceRange" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
        select * from t_goods
        where
            current_price between #{min} and #{max}
        order by current_price
        limit 0, #{limit}
    </select>

    <!-- 利用LinkedHashMap保存多表关联结果
    MyBatis会将每一条记录包装为LinkedHashMap对象
    key是字段名  value是字段对应的值 , 字段类型根据表结构进行自动判断
    优点: 易于扩展,易于使用
    缺点: 太过灵活,无法进行编译时检查
 -->
    <select id="selectGoodsMap" resultType="java.util.LinkedHashMap" flushCache="true">
        select g.* , c.category_name,'1' as test from t_goods g , t_category c
        where g.category_id = c.category_id
    </select>

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

    <insert id="insert" parameterType="com.imooc.mybatis.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})
        <selectKey resultType="Integer" keyProperty="goodsId" order="AFTER">
            select last_insert_id()
        </selectKey>
    </insert>

    <update id="update" parameterType="com.imooc.mybatis.entity.Goods">
        update t_goods
        set
            title = #{title}
        where
            goods_id = #{goodsId}
    </update>

    <delete id="delete" parameterType="Integer">
        delete from t_goods where goods_id = #{value}
    </delete>

    <select id="dynamicSQL" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
        select * from t_goods
        <where>
            <if test="categoryId != null">
                and category_id = #{categoryId}
            </if>
            <if test="currentPrice != null">
                and current_price &lt; #{currentPrice}
            </if>
        </where>

    </select>

    <!--
    resultMap可用于说明一对多或者多对一的映射逻辑
    id 是resultMap属性引用的标志
    type 指向One的实体(Goods)
-->
    <resultMap id="rmGoods1" type="com.imooc.mybatis.entity.Goods">
        <!-- 映射goods对象的主键到goods_id字段 -->
        <id column="goods_id" property="goodsId"></id>
        <!--
            collection的含义是,在
            select * from t_goods limit 0,1 得到结果后,对所有Goods对象遍历得到goods_id字段值,
            并代入到goodsDetail命名空间的findByGoodsId的SQL中执行查询,
            将得到的"商品详情"集合赋值给goodsDetails List对象.
        -->
        <collection property="goodsDetails" select="goodsDetail.selectByGoodsId"
                    column="goods_id"/>
    </resultMap>
    <select id="selectOneToMany" resultMap="rmGoods1">
        select * from t_goods limit 0,10
    </select>

    <select id="selectPage" resultType="com.imooc.mybatis.entity.Goods">
        select * from t_goods where current_price &lt; 1000
    </select>

    <insert id="batchInsert" parameterType="java.util.List">
        insert into
            t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id)
        values
        <foreach collection="list" item="item" index="index" separator=",">
            (#{item.title}, #{item.subTitle}, #{item.originalCost}, #{item.currentPrice}, #{item.discount}, #{item.isFreeDelivery}, #{item.categoryId})
        </foreach>
    </insert>
</mapper>

初始化SessionFactory(已整合到工具类)

SqlSessionFactory根据官方建议,使用单例模式保持全局唯一。

SqlSession则保证生命周期只在一次请求之中

public class MyBatisUtils {
    private static SqlSessionFactory sqlSessionFactory = null;

    static {
        try {
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static SqlSession openSession() {
        return sqlSessionFactory.openSession();
    }

    public static void closeSession(SqlSession sqlSession) {
        if (sqlSession != null) {
            sqlSession.close();
        }
    }
}

利用sqlSession对象操作数据

public class MyBatisTestor {

    @Test
    public void testSqlSessionFactory() throws IOException {
        //利用Reader加载classpath下的mybatis-config.xml核心配置文件
        Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
        //初始化sqlsessionFactory对象,同时解析mybatis-config.xml文件
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        SqlSession sqlSession = null;
        try {
            sqlSession = sqlSessionFactory.openSession();
            Connection connection = sqlSession.getConnection();
            System.out.println(connection);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (sqlSession != null) {
                //如果type="POLLED",代表使用连接池,close则是将连接回收到连接池中
                //如果type="UNPOLLED",代表直连,close则会调用connection.close直接将连接关闭
                sqlSession.close();
            }
        }
    }

    @Test
    public void testMybatisUtils() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.openSession();
            Connection connection = sqlSession.getConnection();
            System.out.println(connection);
        } catch (Exception e) {
            throw e;
        } finally {
            MyBatisUtils.closeSession(sqlSession);
        }
    }

    @Test
    public void testSelectAll() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.openSession();
            List<Goods> goodsList = sqlSession.selectList("goods.selectAll");
            for (Goods goods : goodsList) {
                System.out.println(goods.getTitle());
            }
        } catch (Exception e) {
            throw e;
        } finally {
            MyBatisUtils.closeSession(sqlSession);
        }
    }

    @Test
    public void testSelectById() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.openSession();
            Goods goods = sqlSession.selectOne("goods.selectById", 739);
            System.out.println(goods.getTitle());
        } catch (Exception e) {
            throw e;
        } finally {
            MyBatisUtils.closeSession(sqlSession);
        }
    }

    @Test
    public void testSelectByPriceRange() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.openSession();
            Map param = new HashMap();
            param.put("min", 100);
            param.put("max", 500);
            param.put("limit", 10);
            List<Goods> goodsList = sqlSession.selectList("goods.selectByPriceRange", param);
            for (Goods goods : goodsList) {
                System.out.println(goods.getTitle() + ":" + goods.getCurrentPrice());
            }
        } catch (Exception e) {
            throw e;
        } finally {
            MyBatisUtils.closeSession(sqlSession);
        }
    }


    /**
     * 利用Map接收关联查询结果
     * @throws Exception
     */
    @Test
    public void testSelectGoodsMap() throws Exception {
        SqlSession session = null;
        try{
            session = MyBatisUtils.openSession();
            List<Map> list = session.selectList("goods.selectGoodsMap");
            for(Map map : list){
                System.out.println(map);
            }
        }catch (Exception e){
            throw e;
        }finally {
            MyBatisUtils.closeSession(session);
        }
    }

    @Test
    public void testSelectGoodsDTO() {
        SqlSession session = null;
        try{
            session = MyBatisUtils.openSession();
            List<GoodsDTO> list = session.selectList("goods.selectGoodsDTO");
            for(GoodsDTO dto : list){
                System.out.println(dto.getGoods().getTitle() + ":" + dto.getCategory().getCategoryName());
            }
        }catch (Exception e){
            throw e;
        }finally {
            MyBatisUtils.closeSession(session);
        }
    }

    @Test
    public void testInsert() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.openSession();
            Goods goods = new Goods();
            goods.setTitle("testTitle");
            goods.setSubTitle("testSubTitle");
            goods.setOriginalCost(200f);
            goods.setCurrentPrice(100f);
            goods.setDiscount(0.5f);
            goods.setIsFreeDelivery(1);
            goods.setCategoryId(43);
            int num = sqlSession.insert("goods.insert", goods);
            sqlSession.commit();
            System.out.println(goods.getGoodsId());
        } catch (Exception e) {
            if (sqlSession != null) {
                sqlSession.rollback();
            }
            throw e;
        } finally {
            MyBatisUtils.closeSession(sqlSession);
        }
    }

    @Test
    public void testUpdate() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.openSession();
            Goods goods = sqlSession.selectOne("goods.selectById", 2677);
            goods.setTitle("sdfkssdfksdk");
            int num = sqlSession.update("goods.update", goods);
            sqlSession.commit();
            System.out.println(goods.getGoodsId());
        } catch (Exception e) {
            if (sqlSession != null) {
                sqlSession.rollback();
            }
            throw e;
        } finally {
            MyBatisUtils.closeSession(sqlSession);
        }
    }

    @Test
    public void testDelete() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.openSession();
            int num = sqlSession.update("goods.delete", 2677);
            sqlSession.commit();
        } catch (Exception e) {
            if (sqlSession != null) {
                sqlSession.rollback();
            }
            throw e;
        } finally {
            MyBatisUtils.closeSession(sqlSession);
        }
    }

    @Test
    public void testDynamicSQL() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.openSession();
            Map param = new HashMap();
            param.put("categoryId", 44);
            param.put("currentPrice", 500);
            List<Goods> list = sqlSession.selectList("goods.dynamicSQL", param);
            for (Goods g : list) {
                System.out.println(g.getTitle() + " : " + g.getCategoryId() + " : " + g.getCurrentPrice());
            }
        } catch (Exception e) {
            throw e;
        } finally {
            MyBatisUtils.closeSession(sqlSession);
        }
    }

    /**
     * 一对多对象关联查询
     * @throws Exception
     */
    @Test
    public void testOneToMany() throws Exception {
        SqlSession session = null;
        try {
            session = MyBatisUtils.openSession();
            List<Goods> list = session.selectList("goods.selectOneToMany");
            for(Goods goods:list) {
                System.out.println(goods.getTitle() + ":" + goods.getGoodsDetails().size());
            }
        } catch (Exception e) {
            throw e;
        } finally {
            MyBatisUtils.closeSession(session);
        }
    }

    @Test
    public void testManyToOne() throws Exception {
        SqlSession session = null;
        try {
            session = MyBatisUtils.openSession();
            List<GoodsDetail> list = session.selectList("goodsDetail.selectManyToOne");
            for(GoodsDetail goodsDetail : list) {
                System.out.println(goodsDetail.getGdPicUrl() + ":" + goodsDetail.getGoods().getTitle());
            }
        } catch (Exception e) {
            throw e;
        } finally {
            MyBatisUtils.closeSession(session);
        }
    }

    @Test
    public void testSelectPage() {
        SqlSession session = null;
        try {
            session = MyBatisUtils.openSession();
            // startPage方法会自动将下一次查询进行分页
            PageHelper.startPage(2, 10);
            Page<Goods> page = (Page) session.selectList("goods.selectPage");
            System.out.println("总页数:" + page.getPages());
            System.out.println("总记录:" + page.getTotal());
            System.out.println("当前页码:" + page.getPageNum());
            List<Goods> data = page.getResult();
            for (Goods g : data) {
                System.out.println(g.getTitle());
            }
        } catch (Exception e) {
            throw e;
        } finally {
            MyBatisUtils.closeSession(session);
        }
    }

    @Test
    public void testBatchInsert() {
        SqlSession session = null;
        try {
            long st = System.currentTimeMillis();
            session = MyBatisUtils.openSession();
            List list = new ArrayList();
            for (int i=0; i < 10000; i++) {
                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()方法返回值代表本次成功插入的记录总数
                list.add(goods);
            }
            session.insert("goods.batchInsert", list);
            session.commit();
            long et = System.currentTimeMillis();
            System.out.println("执行时间:" + (et - st) + "毫秒");
        } catch (Exception e) {
            if (session != null) {
                session.rollback();
            }
            throw e;
        } finally {
            MyBatisUtils.closeSession(session);
        }
    }
}

细节补充

selectKey和useGenerateKeys属性的用法和区别

selectKey以标签形式应用于xml的执行语句标签中,需要明确指定获取属性值,适合所有关系型数据库

useGenerateKeys作为标签属性,使用起来较为方便,但是只能适用于支持“自增主键”的数据库。

mybatis的两种传值方式

${value}

这种方式会直接做字符替换,因此有sql注入的风险,使用建议尽量在代码中由开发者使用,而不要通过用户输入来决定输入值,如果一定要使用用户输入的方案,需要对输入字符串进行校验和转义

#{value}

这种方式会预编译传值,会将字符转义后插入sql,比较安全,也是平时常用的方案

mybatis的一些高级用法

日志

日志用于记录操作事件的时间和执行动作,可以用来查看历史操作数据以及诊断问题

在mybatis中,如果没有引入日志相关的jar包,会自动忽略这个功能,如果有引入jar包,则会根据jar包提供的日志功能打印相关操作信息

关于日志的详细,可以参考日志

动态SQL

如果需要灵活的使用sql,而不必纠结于各种动态使用sql中的种种细节,就需要使用mybatis提供的动态sql功能。

官方文档 针对 if, where, choose, foreach等标签都有详细解释

缓存

利用好缓存,可以高效利用mybatis查询数据而不必频繁访问数据库

mybatis中对缓存的支持分为一级缓存和二级缓存,一级缓存是会话级别的,随着会话的结束而被清理。如果需要全局缓存的情况下,就需要手动开启二级缓存(全局缓存也只是针对mybatis3 所提出的命名空间的全局缓存)

详见文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冬天的锦绣江山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值