Mybaits3.X实战

一 添加maven依赖

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

        <!-- 使用JDBC链接mysql的驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>

</dependencies>

二 配置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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/xdclass?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="xdclass.net"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/VideoMapper.xml"/>
    </mappers>
</configuration>

三 配置VideoMapper.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="net.xdclass.online_class.dao.VideoMapper">
    <select id="selectById" resultType="net.xdclass.online_class.domain.Video">
    select * from video where id = #{video_id}
  </select>

</mapper>

获取参数中的值

  • 注意 :取java对象的某个值,属性名大小写要一致
#{value} : 推荐使用, 是java的名称

${value} : 不推荐使用,存在sql注入风险

四 编写代码 获取 SqlSession,以xml方式读取数据库

public static void main(String [] args) throws IOException {

        String resouce = "config/mybatis-config.xml";

        //读取配置文件
        InputStream inputStream =  Resources.getResourceAsStream(resouce);

        //构建Session工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //获取Session
        try(SqlSession sqlSession = sqlSessionFactory.openSession()){

            VideoMapper videoMapper = sqlSession.getMapper(VideoMapper.class);

            Video video = videoMapper.selectById(44);

            //System.out.println(video.toString());


            List<Video> videoList =  videoMapper.selectList();

            System.out.println(videoList.toString());
        }

    }

五 Mybatis使用流程

  • 创建mybatis-config.xml 全局的配置文件

  • 创建XXXMapper.xml配置文件

  • 创建SqlSessionFactory

  • 用SqlSessionFactory创建SqlSession对象

  • 用SqlSession执行增删改查CRUD

内置的日志工厂提供日志功能, 使用log4j配置打印sql,添加依赖

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.30</version>
</dependency>

在应用的classpath中创建名称为log4j.properties的文件

log4j.rootLogger=ERROR, stdout
log4j.logger.net.xdclass=DEBUG
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
  • mysql自带函数使用
     

    <select id="selectByPointAndTitleLike" resultType="net.xdclass.online_class.domain.Video">
    
    select * from video where point=#{point} and title like concat('%', #{title},'%')
    
    </select>
    

     新增一条视频记录
     

    <insert id="add" parameterType="net.xdclass.online_class.domain.Video">
    
            INSERT INTO `video` ( `title`, `summary`, `cover_img`, `price`, `create_time`, `point`)
            VALUES
          (#{title,jdbcType=VARCHAR},#{summary,jdbcType=VARCHAR},#{coverImg,jdbcType=VARCHAR},#{price,jdbcType=INTEGER},
           #{createTime,jdbcType=TIMESTAMP},#{point,jdbcType=DOUBLE});
    
    </insert>

    如何获得插入的自增主键
     

    <insert id="add" parameterType="net.xdclass.online_class.domain.Video" useGeneratedKeys="true" keyProperty="id" keyColumn="id" >

    六 Mybatis foreach批量插入语法的使用

  • 批量插入多条视频记录

  • foreach: 用于循环拼接的内置标签,常用于 批量新增、in查询等常见
     

    包含以下属性:
      collection:必填,值为要迭代循环的集合类型,情况有多种
        入参是List类型的时候,collection属性值为list
        入参是Map类型的时候,collection 属性值为map的key值
      
        item:每一个元素进行迭代时的别名
        index:索引的属性名,在集合数组情况下值为当前索引值,当迭代对象是map时,这个值是map的key
        open:整个循环内容的开头字符串
        close:整个循环内容的结尾字符串
        separator: 每次循环的分隔符

    例子
     

    <!--批量插入-->
    <insert id="addBatch" parameterType="net.xdclass.online_class.domain.Video" useGeneratedKeys="true" keyProperty="id" keyColumn="id" >
    
    INSERT INTO `video` ( `title`, `summary`, `cover_img`, `price`, `create_time`, `point`)
    VALUES
    
    <foreach collection="list" item="video" separator=",">
            
    (#{video.title,jdbcType=VARCHAR},#{video.summary,jdbcType=VARCHAR},#{video.coverImg,jdbcType=VARCHAR},
    #{video.price,jdbcType=INTEGER},
    #{video.createTime,jdbcType=TIMESTAMP},#{video.point,jdbcType=DOUBLE})
    
    </foreach>

    七 更新操作
     

     <update id="updateVideo" parameterType="net.xdclass.online_class.domain.Video">
    
            UPDATE video
    
            set
              title = #{title,jdbcType=VARCHAR},
    
              summary = #{summary,jdbcType=VARCHAR},
    
              cover_img = #{coverImg,jdbcType=VARCHAR},
    
              price = #{price,jdbcType=INTEGER},
    
              c_id = #{cId,jdbcType=INTEGER},
    
             point = #{point,jdbcType=INTEGER},
    
             learn_base = #{learnBase,jdbcType=VARCHAR},
    
             learn_result = #{learnResult,jdbcType=VARCHAR},
    
             total_episode = #{totalEpisode,jdbcType=INTEGER},
    
             update_time = now()
    
             WHERE
    
             id = #{id}
    
        </update>
     

    if test标签介绍

  • if 标签可以通过判断传入的值来确定查询条件,test 指定一个OGNL表达式

  • 常见写法
     

    //当前字段符合条件才更新这个字段的值
    <if test='title != null and id == 87 '> title = #{title}, </if>
    
    <if test="title!=null"> title = #{title}, </if>

    delete删除语法

  • 需求:删除某个时间段之后 且金额大于 10元的数据
    <delete id="deleteByCreateTimeAndPrice" parameterType="java.util.Map">
    
            delete from video where create_time <![CDATA[ > ]]> #{createTime} and price <![CDATA[ >= ]]> #{price}
    
    </delete>
    
    大于等于 <![CDATA[ >= ]]>
    
    小于等于 <![CDATA[ <= ]]>

    八 Mybatis的mybatis-config.xml常见配置
     

    核心配置文件(dom节点顺序要求,不然报错)

  • 记住常用的,不常用的简单介绍,
    configuration(配置)
        properties(属性)
        settings(设置)
        typeAliases(类型别名)
        typeHandlers(类型处理器)
        objectFactory(对象工厂)
        plugins(插件,少用)
        environments(环境配置,不配多环境,基本在Spring里面配置)
        environment(环境变量)
          transactionManager(事务管理器)
          dataSource(数据源)
      databaseIdProvider(数据库厂商标识)
      mappers(映射器)
  • 官方文档:https://mybatis.org/mybatis-3/zh/configuration.html#
     

九 Mybatis的查询类别名typeAlias的使用

  • typeAlias

    • 类型别名,给类取个别名,可以不用输入类的全限定名
      <!--<select id="selectById" parameterType="java.lang.Integer" resultType="net.xdclass.online_class.domain.Video">-->
          <select id="selectById" parameterType="java.lang.Integer" resultType="Video">
              select * from video where id = #{video_id,jdbcType=INTEGER}
      
          </select>
      

      如果有很多类,是否需要一个个配置?

    • 不用一个个配置,使用包扫描即可
      <typeAliases>
      
              <!--<typeAlias type="net.xdclass.online_class.domain.Video" alias="Video"/>-->
              <package name="net.xdclass.online_class.domain"/>
      
      </typeAliases>
    • 本身就内置很多别名,比如Integer、String、List、Map 等

十 Sql片段使用

什么是sql片段

  • 根据业务需要,自定制要查询的字段,并可以复用
     

     <sql id="base_video_field">
            id,title,summary,cover_img
        </sql>
        
         <select id="selectById" parameterType="java.lang.Integer" resultType="Video">
    
            select <include refid="base_video_field"/>  from video where id = #       {video_id,jdbcType=INTEGER}
    
        </select>
    
    
        <select id="selectListByXML" resultType="Video">
    
            select <include refid="base_video_field"/>  from video
    
        </select>
    

十一 Mybatis的resultMap讲解

  • Mybatis的SQL语句返回结果有两种

    • resultType

      • 查询出的字段在相应的pojo中必须有和它相同的字段对应,或者基本数据类型
      • 适合简单查询
    • resultMap

      • 需要自定义字段,或者多表查询,一对多等关系,比resultType更强大
      • 适合复杂查询
        <resultMap id="VideoResultMap" type="Video">
        
                <!--
                id 指定查询列的唯一标示
                column 数据库字段的名称
                property pojo类的名称
                -->
                <id column="id" property="id" jdbcType="INTEGER" />
        
                <result column="video_tile" property="title"  jdbcType="VARCHAR" />
                <result column="summary" property="summary"  jdbcType="VARCHAR" />
                <result column="cover_img"  property="coverImg"  jdbcType="VARCHAR" />
        
        </resultMap>
        <select id="selectBaseFieldByIdWithResultMap" resultMap="VideoResultMap">
        select id , title as video_tile, summary, cover_img from video where id = #{video_id}
        </select>
        

 十二 ResultMap的association一对一查询

  • association: 映射到POJO的某个复杂类型属性,比如订单order对象里面包含 user对象
    <resultMap id="VideoOrderResultMap" type="VideoOrder">
            <id column="id" property="id"/>
    
            <result column="user_id" property="userId"/>
            <result column="out_trade_no" property="outTradeNo"/>
            <result column="create_time" property="createTime"/>
            <result column="state" property="state"/>
            <result column="total_fee" property="totalFee"/>
            <result column="video_id" property="videoId"/>
            <result column="video_title" property="videoTitle"/>
            <result column="video_img" property="videoImg"/>
    
    
            <!--
             association 配置属性一对一
             property 对应videoOrder里面的user属性名
             javaType 这个属性的类型
             -->
            <association property="user" javaType="User">
                <id property="id"  column="user_id"/>
                <result property="name" column="name"/>
                <result property="headImg" column="head_img"/>
                <result property="createTime" column="create_time"/>
                <result property="phone" column="phone"/>
            </association>
    
        </resultMap>
    
        <!--一对一管理查询订单, 订单内部包含用户属性-->
        <select id="queryVideoOrderList" resultMap="VideoOrderResultMap">
    
            select
    
             o.id id,
             o.user_id ,
             o.out_trade_no,
             o.create_time,
             o.state,
             o.total_fee,
             o.video_id,
             o.video_title,
             o.video_img,
             u.name,
             u.head_img,
             u.create_time,
             u.phone
             from video_order o left join user u on o.user_id = u.id
    
        </select>

十三 ResultMap的collection一对多查询 

  • collection: 一对多查询结果查询映射,比如user有多个订单
    <resultMap id="UserOrderResultMap" type="User">
    
            <id property="id"  column="id"/>
            <result property="name" column="name"/>
            <result property="headImg" column="head_img"/>
            <result property="createTime" column="create_time"/>
            <result property="phone" column="phone"/>
    
            <!--
            property 填写pojo类中集合类属性的名称
            ofType 集合里面的pojo对象
            -->
            <collection property="videoOrderList" ofType="VideoOrder">
    
                <!--配置主键,管理order的唯一标识-->
                <id column="order_id" property="id"/>
                <result column="user_id" property="userId"/>
                <result column="out_trade_no" property="outTradeNo"/>
                <result column="create_time" property="createTime"/>
                <result column="state" property="state"/>
                <result column="total_fee" property="totalFee"/>
                <result column="video_id" property="videoId"/>
                <result column="video_title" property="videoTitle"/>
                <result column="video_img" property="videoImg"/>
            </collection>
        </resultMap>
    
        <select id="queryUserOrder" resultMap="UserOrderResultMap">
            select
            u.id,
            u.name,
            u.head_img,
            u.create_time,
            u.phone,
            o.id order_id,
            o.out_trade_no,
            o.user_id,
            o.create_time,
            o.state,
            o.total_fee,
            o.video_id,
            o.video_title,
            o.video_img
            from user u left join video_order o on u.id = o.user_id
    
        </select>
    

    十四 ResultMap复杂对象查询总结
     

  • association 映射的是一个pojo类,处理一对一的关联关系。
  • collection 映射的一个集合列表,处理的是一对多的关联关系。
  • 模板
<!-- column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性-->
<resultMap id="唯一的标识" type="映射的pojo对象">
  <id column="表的主键字段,或查询语句中的别名字段" jdbcType="字段类型" property="映射pojo对象的主键属性" />
  <result column="表的一个字段" jdbcType="字段类型" property="映射到pojo对象的一个属性"/>

  <association property="pojo的一个对象属性" javaType="pojo关联的pojo对象">
    <id column="关联pojo对象对应表的主键字段" jdbcType="字段类型" property="关联pojo对象的属性"/>
    <result  column="表的字段" jdbcType="字段类型" property="关联pojo对象的属性"/>
  </association>

  <!-- 集合中的property 需要为oftype定义的pojo对象的属性-->
  <collection property="pojo的集合属性名称" ofType="集合中单个的pojo对象类型">
    <id column="集合中pojo对象对应在表的主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" />
    <result column="任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属性" />  
  </collection>
</resultMap>

十五 Mybatis一级缓存

  • 什么是缓存

    • 程序经常要调用的对象存在内存中,方便其使用时可以快速调用,不必去数据库或者其他持久化设备中查询,主要就是提高性能
  • Mybatis一级缓存

    • 简介:一级缓存的作用域是SQLSession,同一个SqlSession中执行相同的SQL查询(相同的SQL和参数),第一次会去查询数据库并写在缓存中,第二次会直接从缓存中取
    • 基于PerpetualCache 的 HashMap本地缓存
    • 默认开启一级缓存
  • 失效策略:当执行SQL时候两次查询中间发生了增删改的操作,即insert、update、delete等操作commit后会清空该SQLSession缓存; 比如sqlsession关闭,或者清空等

十六 Mybatis二级缓存

  • Mybatis二级缓存

    • 简介:二级缓存是namespace级别的,多个SqlSession去操作同一个namespace下的Mapper的sql语句,多个SqlSession可以共用二级缓存,如果两个mapper的namespace相同,(即使是两个mapper,那么这两个mapper中执行sql查询到的数据也将存在相同的二级缓存区域中,但是最后是每个Mapper单独的名称空间)
    • 基于PerpetualCache 的 HashMap本地缓存,可自定义存储源,如 Ehcache/Redis等
    • 默认是没有开启二级缓存
    • 操作流程:第一次调用某个namespace下的SQL去查询信息,查询到的信息会存放该mapper对应的二级缓存区域。 第二次调用同个namespace下的mapper映射文件中,相同的sql去查询信息,会去对应的二级缓存内取结果

  • 失效策略:执行同个namespace下的mapepr映射文件中增删改sql,并执行了commit操作,会清空该二级缓存

  • 注意:实现二级缓存的时候,MyBatis建议返回的POJO是可序列化的, 也就是建议实现Serializable接口

  • 缓存淘汰策略:会使用默认的 LRU 算法来收回(最近最少使用的)

  • 如何开启某个二级缓存 mapper.xml里面配置
     

    <!--开启mapper的namespace下的二级缓存-->
        <!--
            eviction:代表的是缓存回收策略,常见下面两种。
            (1) LRU,最近最少使用的,一处最长时间不用的对象
            (2) FIFO,先进先出,按对象进入缓存的顺序来移除他们
    
            flushInterval:刷新间隔时间,单位为毫秒,这里配置的是100秒刷新,如果不配置它,当SQL被执行的时候才会去刷新缓存。
    
            size:引用数目,代表缓存最多可以存储多少个对象,设置过大会导致内存溢出
    
            readOnly:只读,缓存数据只能读取而不能修改,默认值是false
        -->
    <cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>
    全局配置:
    <settings>
    <!--这个配置使全局的映射器(二级缓存)启用或禁用缓存,全局总开关,这里关闭,mapper中开启了也没用-->
            <setting name="cacheEnabled" value="true" />
    </settings>

  • 配置实操

  • 如果需要控制全局mapper里面某个方法不使用缓存,可以配置 useCache="false"
     

    <select id="selectById" parameterType="java.lang.Integer" resultType="Video" useCache="false">
    
    select <include refid="base_video_field"/>  from video where id = #{video_id,jdbcType=INTEGER}
    
    </select>
  • 一级缓存和二级缓存使用顺序

    • 优先查询二级缓存-》查询一级缓存-》数据库

十七 Mybatis3.x的懒加载 

  • 什么是懒加载: 按需加载,先从单表查询,需要时再从关联表去关联查询,能大大提高数据库性能,并不是所有场景下使用懒加载都能提高效率
  • Mybatis懒加载: resultMap里面的association、collection有延迟加载功能
    <!--全局参数设置-->
    <settings>
        <!--延迟加载总开关-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--将aggressiveLazyLoading设置为false表示按需加载,默认为true-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    <resultMap id="VideoOrderResultMapLazy" type="VideoOrder">
            <id column="id" property="id"/>
    
            <result column="user_id" property="userId"/>
            <result column="out_trade_no" property="outTradeNo"/>
            <result column="create_time" property="createTime"/>
            <result column="state" property="state"/>
            <result column="total_fee" property="totalFee"/>
            <result column="video_id" property="videoId"/>
            <result column="video_title" property="videoTitle"/>
            <result column="video_img" property="videoImg"/>
    
    <!-- 
    select: 指定延迟加载需要执行的statement id 
    column: 和select查询关联的字段
    -->
            <association property="user" javaType="User" column="user_id" select="findUserByUserId"/>
    
    
    </resultMap>
    
        <!--一对一管理查询订单, 订单内部包含用户属性  懒加载-->
    <select id="queryVideoOrderListLazy" resultMap="VideoOrderResultMapLazy">
    
            select
             o.id id,
             o.user_id ,
             o.out_trade_no,
             o.create_time,
             o.state,
             o.total_fee,
             o.video_id,
             o.video_title,
             o.video_img
             from video_order o
    
    </select>
    
    
    <select id="findUserByUserId" resultType="User">
    
           select  * from user where id=#{id}
    
    </select>

  • dubug模式测试懒加载不准确,可以直接run
    // resultmap association关联查询(测试懒加载)
    VideoOrderMapper videoOrderMapper = sqlSession.getMapper(VideoOrderMapper.class);
    List<VideoOrder> videoOrderList = videoOrderMapper.queryVideoOrderListLazy();
    System.out.println(videoOrderList.size());
    
    //课程里面演示是6条订单记录,但是只查询3次用户信息,是因为部分用户信息走了一级缓存sqlsession
    for(VideoOrder videoOrder : videoOrderList){
    
        System.out.println(videoOrder.getVideoTitle());
        System.out.println(videoOrder.getUser().getName());
    }

    十八 整合Mysql数据库事务
     

  • 使用JDBC的事务管理

    • 使用 java.sql.Connection对象完成对事务的提交(commit())、回滚(rollback())、关闭(close())
  • 使用MANAGED的事务管理

    • MyBatis自身不会去实现事务管理,而让程序的容器如(Spring, JBOSS)来实现对事务的管理
  • <environment id="development">
                <!-- mybatis使用jdbc事务管理方式 -->
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://127.0.0.1:3306/xdclass?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false"/>
                    <property name="username" value="root"/>
                    <property name="password" value="xdclass.net"/>
                </dataSource>
    </environment>

事务工厂TransactionFactory 的两个实现类

  • JdbcTransactionFactory->JdbcTransaction
  • ManagedTransactionFactory->ManagedTransaction
  • 注意:如果不是web程序,然后使用的事务管理形式是MANAGED, 那么将没有事务管理功能

 十九 Mysql的Innodb和MyISAM引擎的区别

区别项Innodbmyisam
事务支持不支持
锁粒度行锁,适合高并发表锁,不适合高并发
是否默认默认非默认
支持外键支持外键不支持
适合场景读写均衡,写大于读场景,需要事务读多写少场景,不需要事务
全文索引可以通过插件实现, 更多使用ElasticSearch支持全文索引

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值