【Xdclss项目】MyBatis(4.28-c13)


在这里插入图片描述

1.就从JDBC开始吧

1.1. JDBC是啥

JDBC是java访问数据库的基石,JDO、Hibernate、MyBatis等只是更好的封装了JDBC。JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统(MySQL、O)、通用的SQL数据库存取和操作的公共接口(一组API)。
在这里插入图片描述

1.2.如何用JDBC连接数据库

spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/online_xdclass?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=1111

VS.

user=root//JDBC链接
password=1111
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
driverClass=com.mysql.jdbc.Driver

数据库连接

@Test
public  void testConnection5() throws Exception {
	//1.加载配置文件
    InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
    Properties pros = new Properties();
    pros.load(is);
    
    //2.读取配置信息
    String user = pros.getProperty("user");
    String password = pros.getProperty("password");
    String url = pros.getProperty("url");
    String driverClass = pros.getProperty("driverClass");

    //3.加载驱动
    Class.forName(driverClass);

    //4.获取连接
    Connection conn = DriverManager.getConnection(url,user,password);
    System.out.println(conn);

}

1.3.SQL 注入的前世今生

SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令

SELECT user, password FROM user_table WHERE user='a' OR 1 = ' AND password = ' OR '1' = '1'

在这里插入图片描述

从而利用系统的 SQL 引擎完成恶意行为的做法。

对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(从Statement扩展而来) 取代 Statement 就可以了。PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句。

1.4.两种思想

  • 面向接口编程的思想
  • ORM思想(object relational mapping)
    • 一个数据表对应一个java类
    • 表中的一条记录对应java类的一个对象
    • 表中的一个字段对应java类的一个属性

2. Mybatis

Mybatis是一个sql映射框架,提供的数据库的操作能力。增强的JDBC。减轻使用JDBC的复杂性,不用编写重复的创建 Connetion , Statement 。 不用编写关闭资源代码。直接使用java对象,表示结果数据。让开发者专注 SQL 的处理。

2.1初体验

什么是工厂设计模式

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>
    <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?serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="1111"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mapper/VideoMapper.xml"/>
    </mappers>
</configuration>

main

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
    //这是jdk8语法(设置file > file structure > modules),可以自动关闭sqlSession 
    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();
        List<Video> videoList = videoMapper.selectListByXML();
        System.out.println(videoList.toString());
    }
}

dao层的两种方式

public interface VideoMapper {
    Video selectById(@Param("video_id") int videoId);//结合XML配置文件
    List<Video> selectListByXML();
    @Select("select * from video")//注解配置
    List<Video> selectList();
}

resources下的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">
<!--
namespace: 名称空间,一般需要保持全局唯一, 最好是和dao层的java接口一致,
可以映射 sql语句 到对应的方法名称和参数、返回类型

mybatis是使用接口动态代理
-->
<mapper namespace="net.xdclass.online_class.dao.VideoMapper">
    <!--
    statement sql
    id: 当前mapper下需要唯一
    resultType : sql查询结果集的封装
    -->
    <select id="selectById" resultType="net.xdclass.online_class.domain.Video">
        select * from video where id = #{video_id}
    </select>

    <select id="selectListByXML" resultType="net.xdclass.online_class.domain.Video">
        select * from video
    </select>
</mapper>

2.2.进阶-增删改查

2.2.1.多参数模糊查询

查询指定评分,标题包含指定字符的视频

dao层

List<Video> selectByPointAndTitleLike(@Param("point") double point, @Param("title") String title);

resources下的mapper

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

2.2.2.配置驼峰字段映射java对象和数据库字段

Mybatis 配置驼峰字段映射java对象和数据库字段

2.2.3.新增和自增主键

新增一条

<insert id="add" 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
    (#{title,jdbcType=VARCHAR},#{summary,jdbcType=VARCHAR},#{coverImg,jdbcType=VARCHAR},#{price,jdbcType=INTEGER},
     #{createTime,jdbcType=TIMESTAMP},#{point,jdbcType=DOUBLE});
</insert>

在这里插入图片描述
在main函数中操作插入

Video video =  new Video();
video.setTitle("小滴课堂面试专题900道");
video.setCoverImg("xdclass.net/aaa.png");
video.setPoint(9.4);
video.setCreateTime(new Date());
video.setPrice(9900);
video.setSummary("这个是面试专题概要");
int rows = videoMapper.add(video);

如何批量插入?利用foreach

    <!--批量插入-->
<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>
</insert>
List<Video> list = new ArrayList<>();
list.add(video1);
list.add(video2);
int rows =  videoMapper.addBatch(list);

2.2.3.更新

<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},
    create_time = #{createTime,jdbcType=TIMESTAMP},
    point = #{point,jdbcType=DOUBLE}
    where
    id = #{id}
</update>
   Video video =  new Video();
   video.setId(59);
   video.setTitle("小滴课堂面试专题900道 2021年新版");
   video.setCoverImg("xdclass.net/6666.png");
   videoMapper.updateVideo(video);

选择性更新

利用Mybatis里面的 if test 语法

<update id="updateVideoSelective" parameterType="net.xdclass.online_class.domain.Video">
    update video
    <trim prefix="set" suffixOverrides=",">
        <if test="title != null "> title = #{title,jdbcType=VARCHAR},</if>
        <if test="summary != null "> summary = #{summary,jdbcType=VARCHAR},</if>
        <if test="coverImg != null "> cover_img = #{coverImg,jdbcType=VARCHAR},</if>
        <if test="price != 0 "> price = #{price,jdbcType=INTEGER},</if>
        <if test="createTime !=null "> create_time = #{createTime,jdbcType=TIMESTAMP},</if>
        <!--一定要看pojo类里面的是基本数据类型,还是包装数据类型-->
        <if test="point != null "> point = #{point,jdbcType=DOUBLE},</if>
    </trim>
    where
    id = #{id}
</update>

2.2.4.删除

<delete id="deleteByCreateTimeAndPrice" parameterType="java.util.Map">
    delete from video where create_time <![CDATA[ > ]]> #{createTime} and price <![CDATA[ >= ]]> #{price}
</delete>
Map<String,Object> map = new HashMap<>();
map.put("createTime","2021-01-11 09:33:20");
map.put("price",9000);
int rows = videoMapper.deleteByCreateTimeAndPrice(map);

总结:
1.为了避免与标签的< >混淆,大于小于这样表示

大于等于 <![CDATA[ >= ]]>
小于等于 <![CDATA[ <= ]]>

2.parameterType指的是接收的数据类型(能够增删改得)

2.3.配置mybatis-config.xml

2.3.1.起个别名呗

<typeAliases>
    <!--<typeAlias type="net.xdclass.online_class.domain.Video" alias="Video"/>-->
    <package name="net.xdclass.online_class.domain"/>  
    <!--这个包下的类都以最后一级(即video)为别名,上下两种写法效果一样-->
</typeAliases>

配置修改后,resources > mapper下则可以简化

<!--<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>

2.3.2.sql片段

查询指定值,并不是用select * 把所有字段全部查出

 <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>

2.4.复杂查询(进阶)

2.4.1.resultMap

resultType只能查java对应的pojo类,在多表查询条件下,需要查指定字段则不能胜任。所以需要resultMap(等于一个自定义的字段集合,可能是几个表共有的)

<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>

2.4.2.association

用于查询复杂对象,比如查询视频订单,除了具有基本属性外,还有user对象属性。就在这时利用association返回指定resultMap

<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属性名
         javType 这个属性的类型
         -->
        <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>

2.4.3.association

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>

2.4.多级缓存和懒加载

2.4.1.Mybatis一级缓存

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

2.4.2.Mybatis二级缓存

  • 简介:二级缓存是namespace级别的,多个SqlSession去操作同一个namespace下的Mapper的sql语句,多个SqlSession可以共用二级缓存,如果两个mapper的namespace相同,(即使是两个mapper,那么这两个mapper中执行sql查询到的数据也将存在相同的二级缓存区域中,但是最后是每个Mapper单独的名称空间)
  • 基于PerpetualCache 的 HashMap本地缓存(底层也是hash),可自定义存储源,如 Ehcache/Redis等, 默认是没有开启二级缓存
  • 开启某个二级缓存步骤
    mapper.xml里面配置
<!--开启mapper的namespace下的二级缓存-->
    <!--
        eviction:代表的是缓存回收策略,常见下面两种。
        (1) LRU,最近最少使用的,一处最长时间不用的对象
        (2) FIFO,先进先出,按对象进入缓存的顺序来移除他们

        flushInterval:刷新间隔时间,单位为毫秒,这里配置的是100秒刷新,如果不配置它,当SQL被执行的时候才会去刷新缓存。

        size:引用数目,代表缓存最多可以存储多少个对象,设置过大会导致内存溢出

        readOnly:只读,缓存数据只能读取而不能修改,默认值是false
    -->
<cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>

mybatis-config.xml

全局配置:
<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>
  • 一级缓存和二级缓存使用顺序
    优先查询二级缓存 > 查询一级缓存 > 数据库
    在这里插入图片描述

2.4.3.懒加载

按需加载,先从单表查询,需要时再从关联表去关联查询,能大大提高数据库性能,并不是所有场景下使用懒加载都能提高效率

  • Mybatis懒加载: resultMap里面的association、collection有延迟加载功能
  • 设置
<!--全局参数设置-->
<settings>
    <!--延迟加载总开关-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--将aggressiveLazyLoading设置为false表示按需加载,默认为true-->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>
  • 两个点
    1、VideoOrderMapper.xml 用到关联查询
    在这里插入图片描述
    2.main
    在这里插入图片描述
    实验结果
    在这里插入图片描述

2.5.事务

2.5.1. Mybatis的事务管理形式

快捷键:ctrl+shift+N
查找 TransactionFactory 接口
快捷键:Ctrl + Alt + B
查看接口的实现类

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

  • 使用MANAGED的事务管理
    MyBatis自身不会去实现事务管理,而让程序的容器如(Spring, JBOSS)来实现对事务的管理
    在这里插入图片描述

2.5.2.两种存储引擎的区别

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

MyISAM不支持事务,如果需要事务则改为innodb引擎 更改数据库的表里面的引擎

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

|7_7|

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

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

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

打赏作者

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

抵扣说明:

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

余额充值