小黑子—MyBatis:第五章

news2024/11/19 16:21:37

MyBatis入门5.0

  • 十三 小黑子的MyBatis高级映射及延迟加载
    • 13.1 多对一映射
      • 13.1.1 实体类关系怎么设计
      • 13.1.2 第一种方式:级联属性映射
      • 13.1.2 第二种方式 association 关联
      • 13.1.3 第三种方式 分步查询
      • 13.1.3 延迟加载
    • 13.2 一对多映射
      • 13.2.1 一对多的映射原理
      • 13.2.2 第一种实现方式:collection
      • 13.2.3 第二种实现方式:分布查询
  • 十四 小黑子的MyBatis之缓存(内存)
    • 14.1 提供了哪些缓存机制
    • 14.2 理解一级缓存
      • 14.2.1 一级缓存的失效
    • 14.3 二级缓存的使用
      • 14.3.1 二级缓存的相关配置
    • 14.4 集成Ehcache
  • 十五 小黑子的MyBatis逆向工程
    • 15.1 逆向工程配置与生成(使用基础版)
      • 15.1.1 测试基础版
    • 15.2 使用增强版
      • 15.2.1 测试增强版的查询
    • 15.3 QBC的查询风格
  • 十六 小黑子的MyBatis使用PagHelper
    • 16.1 分页原理
    • 16.2 limit分页
    • 16.3 使用PageHelper插件
      • 16.3.1 获取PageInfo对象
  • 十七 小黑子的MyBatis注解式开发
    • 17.1 @Insert注解
    • 17.2 @Delete注解
    • 17.3 @Update注解
    • 17.4 @Select注解
    • 17.5 @Result注解

十三 小黑子的MyBatis高级映射及延迟加载

  • 环境准备
    模块名: mybatis-o09-advanced-mapping打包方式: jar
    依赖包: mybatis依赖、mysql驱动依赖、junit依赖、logback依赖
    配置文件: mybatis-config.xml、logback.xml、jdbc.properties
    拷贝工具类: SqlSessionUtil
    准备数据库表:一个班级对应多个学生。班级表: t_clazz。学生表: t_student

在这里插入图片描述
在这里插入图片描述
准备的目录展示:
在这里插入图片描述

13.1 多对一映射

13.1.1 实体类关系怎么设计

在这里插入图片描述

多种方式,常见的包括三种:

  1. 第一种方式:一条SQL语句,级联属性映射。
  2. 第二种方式:一条SQL语句,association。
  3. 第三种方式:两条SQL语句,分步查询。(这种方式常用:优点一是可复用。优点二是支持懒加载。)

13.1.2 第一种方式:级联属性映射

pojo类Student中添加一个属性:Clazz clazz; 表示学生关联的班级对象。

  • pojo类Studen
package com.powernode.mybatis.pojo;

public class Student { //Student是多的一方
    private Integer sid;
    private String sname;
    private Clazz clazz; //Clazz是一的一方

    @Override
    public String toString() {
        return "Student{" +
                "sid=" + sid +
                ", sname='" + sname + '\'' +
                ", clazz=" + clazz +
                '}';
    }

    public Clazz getClazz() {
        return clazz;
    }

    public void setClazz(Clazz clazz) {
        this.clazz = clazz;
    }

    public Integer getSid() {
        return sid;
    }

    public void setSid(Integer sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public Student() {
    }
}
  • StudentMapper接口
package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Student;

public interface StudentMapper {
    /*
     * @description: 根据id获取学生信息,同时获取学生关联的班级信息
     * @param id
     * @return 学生对象,但是学生对象当中含有班级对象
    */
    Student selectById(Integer id);
}
  • StudentMapper.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="com.powernode.mybatis.mapper.StudentMapper">

    <resultMap id="studentResultMap" type="Student">
        <id property="sid" column="sid"/>
        <result property="sname" column="sname"/>
        <result property="clazz.cid" column="cid"/>
        <result property="clazz.cname" column="cname"/>
    </resultMap>

    <select id="selectById" resultMap="studentResultMap">
        select
            s.sid,s.sname,c.cid,c.cname
        from
            t_stu s left join t_clazz c on s.cid = c.cid
        where
            s.sid = #{sid}
    </select>
</mapper>
  • 测试
package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.StudentMapper;
import com.powernode.mybatis.pojo.Student;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

public class StudentMapperTest {
    @Test
    public void testSelectById(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        Student student = mapper.selectById(1);
        System.out.println(student);
        System.out.println(student.getSid());
        System.out.println(student.getSname());
        System.out.println(student.getClazz().getCid());
        System.out.println(student.getClazz().getCname());


        sqlSession.commit();
        sqlSession.close();
    }

}

在这里插入图片描述

13.1.2 第二种方式 association 关联

association翻译为:关联。
一个学生对象关联一个班级对象。

  • property:提供要映射的POJO类的属性名
  • javaType:用来指定要映射的java类型
    <resultMap id="studentResultMapAssociation" type="Student">
        <id property="sid" column="sid"/>
        <result property="sname" column="sname"/>

        <association property="clazz" javaType="Clazz">
            <result property="cid" column="cid"/>
            <result property="cname" column="cname"/>
        </association>
    </resultMap>
  • StudentMapper接口
    //一条sql语句:association
    Student selectByIdAssciation(Integer id);
  • 测试
@Test
    public void testSelectByIdAssciation(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        Student student = mapper.selectByIdAssciation(4);
        System.out.println(student);


        sqlSession.commit();
        sqlSession.close();
    }

其他位置都不需要修改,只需要修改resultMap中的配置:association即可。

13.1.3 第三种方式 分步查询

第三种方式:两条SQL语句,分步查询。(这种方式常用:优点一是可复用,二是支持懒加载)

其他位置不需要修改,只需要修改以及添加以下三处:

第一处associationselect位置填写sqlIdsqlId=namespace+id。其中column属性作为这条子sql语句的条件。

    /*
     * 分布查询第一步:先根据学生的sid查询学生的信息
     * @param sid
     * @version 1.0
    */
    Student selectByIdStep1(Integer sid);
    <!--两条sql语句,完成多对一的分布查询-->
    <!--这是第一步:根据学生的id查询学生的所有信息,这些信息当中含有班级id(cid)-->
    <resultMap id="studentReultMapByStep" type="Student">
        <id property="sid" column="sid"/>
        <result property="sname" column="sname"/>
        <association property="clazz"
                    select="com.powernode.mybatis.mapper.ClazzMapper.selectByIdStep2"
                    column="cid"/>
    </resultMap>

    <select id="selectByIdStep1" resultMap="studentReultMapByStep">
        select sid,sname,cid from t_stu where sid =#{sid}
    </select>

第二处:在ClazzMapper接口中添加方法

package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Clazz;

public interface ClazzMapper {
    /*
     * 分别查询第二步:根据cid获取班级信息
     * @param cid
     * @version 1.0
    */
    Clazz selectByIdStep2(Integer cid);
}

第三处:在ClazzMapper.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="com.powernode.mybatis.mapper.ClazzMapper">
    <!--分布查询第二步:根据cid获取班级信息-->
    <select id="selectByIdStep2" resultType="Clazz">
        select cid,cname from t_clazz where cid = #{cid}
    </select>
</mapper>
  • 测试
@Test
    public void testSelectByIdStep1(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        Student student = mapper.selectByIdStep1(5);
        System.out.println(student);


        sqlSession.commit();
        sqlSession.close();
    }

在这里插入图片描述

13.1.3 延迟加载

什么是延迟加载(懒加载),有什么用?

延迟加载的核心原理是:用的时候再执行查询语句,不用的时候不查询

分步优点:

  • 第一个优点:代码复用性增强。
  • 第二个优点:支持延迟加载。【暂时访问不到的数据可以先不查询。提高程序的执行效率。】
  • 懒加载作用:
    • 提高性能,尽可能地不查,或者说尽可能的少查,来提高性能
  • 如何开启懒加载
    • association标签中添加fetchType="lazy"
    • 注意:默认情况下是没有开启延迟加载的。需要设置: fetchType="lazy"
    • 这种在association标签中配置fetchType="lazy",是局部的设置,只对当前的association关联的sql语句起作用。
    • 通过fetchType="eager"来关闭懒加载
  • 如何设置全局的懒加载开关?
    在mybatis的核心配置文件中添加lazyLoadingEnabled属性,设置为true

①:

    <resultMap id="studentReultMapByStep" type="Student">
        <id property="sid" column="sid"/>
        <result property="sname" column="sname"/>
        <association property="clazz"
                    select="com.powernode.mybatis.mapper.ClazzMapper.selectByIdStep2"
                    column="cid"
                    fetchType="lazy"/>
    </resultMap>

②:

    <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>

在这里插入图片描述

在实际的开发中,大部分都是需要使用加载的,所以建议开启全部的延迟加载机制:

  • 在mybatis核心配置文件中添加全局配置:lazyLoadingEnabled=true

在实际开发中,开启全局的延迟加载机制,对于特殊不需要使用懒加载的通过fetchType="eager"来关闭懒加载

13.2 一对多映射

13.2.1 一对多的映射原理

在这里插入图片描述

一对多的实现,通常是在一的一方中有List集合属性。

在Clazz类中添加List<Student> stus; 属性。

public class Clazz {
    private Integer cid;
    private String cname;
    private List<Student> stus;
    // set get方法
    // 构造方法
    // toString方法
}

一对多的实现通常包括两种实现方式:

  • 第一种方式:collection
  • 第二种方式:分布查询

13.2.2 第一种实现方式:collection

  • ClazzMapper接口
    /**
     * 根据cid获取Clazz信息
     * @param cid
     * @return
     */
    Clazz selectByCollection(Integer cid);
  • Clazz的pojo类
package com.powernode.mybatis.pojo;

import java.util.List;

public class Clazz {
    private Integer cid;
    private String cname;
    private List<Student> stus;

    @Override
    public String toString() {
        return "Clazz{" +
                "cid=" + cid +
                ", cname='" + cname + '\'' +
                ", stus=" + stus +
                '}';
    }

    public List<Student> getStus() {
        return stus;
    }

    public void setStus(List<Student> stus) {
        this.stus = stus;
    }

    public Integer getCid() {
        return cid;
    }

    public void setCid(Integer cid) {
        this.cid = cid;
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }

    public Clazz(Integer cid, String cname) {
        this.cid = cid;
        this.cname = cname;
    }

    public Clazz() {
    }
}

  • ClazzMapper.xml
 <resultMap id="clazzResultMap" type="Clazz">
        <id property="cid" column="cid"/>
        <result property="cname" column="cname"/>
        <!--一对多,这里是collection。collection是集合的意思-->
        <!-- ofType:属性用来指定集合当中的元素类型-->
        <collection property="stus" ofType="Student">
            <id property="sid" column="sid"/>
            <result property="sname" column="sname"/>
        </collection>
    </resultMap>

    <select id="selectByCollection" resultMap="clazzResultMap">
        select
            c.cid,c.cname,s.sid,s.sname
        from t_clazz c left join t_stu s on c.cid = s.cid
        where c.cid = #{cid}
    </select>

注意是ofType,表示“集合中的类型”。

  • 测试
package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.ClazzMapper;
import com.powernode.mybatis.pojo.Clazz;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

public class ClazzMapperTest {
    @Test
    public void testSelectByCollection(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        ClazzMapper mapper = sqlSession.getMapper(ClazzMapper.class);
        Clazz clazz = mapper.selectByCollection(1000);
        System.out.println(clazz);

        sqlSession.commit();
        sqlSession.close();
    }
}

在这里插入图片描述

13.2.3 第二种实现方式:分布查询

修改以下位置即可:

  • ClazzMapper接口
    /*
     * 分布查询:第一步,根据班级编号获取班级信息
     * @param cid 班级编号
     * @version 1.0
    */
    Clazz selectByStep1(Integer cid);

  • StudentMapper接口
    /*
     * 根据班级编号查询学生信息
     * @param cid
     * @version 1.0
    */
    List<Student> selectByCidStep2(Integer cid);
  • ClazzMapper.xml
    <resultMap id="clazzResultMapStep" type="Clazz">
        <id property="cid" column="cid"/>
        <result property="cname" column="cname"/>
        <collection property="stus"
                    select="com.powernode.mybatis.mapper.StudentMapper.selectByCidStep2"
                    column="cid"/>
    </resultMap>

    <select id="selectByStep1" resultMap="clazzResultMapStep">
        select cid,cname from t_clazz where cid = #{cid}
    </select>
  • StudentMapper.xml
   <select id="selectByCidStep2" resultType="Student">
        select * from t_stu where cid = #{cid}
    </select>
  • 测试
  @Test
    public void testSelectByStep1(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        ClazzMapper mapper = sqlSession.getMapper(ClazzMapper.class);
        Clazz clazz = mapper.selectByStep1(1000);

        System.out.println(clazz);

        //只访问班级名字
        System.out.println(clazz.getCname());

        //只有用到的时候才会去执行第二步sql
        System.out.println(clazz.getStus());


        sqlSession.commit();
        sqlSession.close();
    }

在这里插入图片描述

一对多延迟加载机制和多对一是一样的。同样是通过两种方式:
在这里插入图片描述

  • 第一种:fetchType=“lazy”
  • 第二种:修改全局的配置setting,lazyLoadingEnabled=true,如果开启全局延迟加载,想让某个sql不使用延迟加载:fetchType=“eager”

十四 小黑子的MyBatis之缓存(内存)

在这里插入图片描述

缓存:cache

缓存的作用:通过减少IO的方式,来提高程序的执行效率。

mybatis的缓存:将select语句的查询结果放到缓存(内存)当中,下一次还是这条select语句的话,直接从缓存中取,不再查数据库。一方面是减少了IO。另一方面不再执行繁琐的查找算法。效率大大提升。

常见的缓存技术:

  • 字符串常量池
  • 整数型常量池
  • 线程池
  • 连接池…

14.1 提供了哪些缓存机制

mybatis缓存包括:

  • 一级缓存:将查询到的数据存储到SqlSession中。
  • 二级缓存:将查询到的数据存储到SqlSessionFactory中。
  • 或者集成其它第三方的缓存:比如EhCache【Java语言开发的】、Memcache【C语言开发的】等。

缓存只针对于DQL语句,也就是说缓存机制只对应select语句。

14.2 理解一级缓存

一级缓存是默认开启的,不需要做任何配置。

原理:只要使用一个SqlSession对象执行一条SQL语句,就会走缓存

  • CarMapper.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="com.powernode.mybatis.mapper.CarMapper">
    <select id="selectById" resultType="Car">
        select * from t_car where id = #{id}
    </select>

</mapper>
  • CarMapper接口
package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Car;

public interface CarMapper {

    Car selectById(Long id);
}

  • 测试
package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;

public class CarMapperTest {

    @Test
    public void testSelectById() throws IOException {
        //如果要获取不同的SqlSession对象,不能使用以下代码
        // SqlSession sqlSession = SqlSessionUtil.openSession();
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();

        CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
        Car car1 = mapper1.selectById(34L);
        System.out.println(car1);

        CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);
        Car car2 = mapper2.selectById(34L);
        System.out.println(car2);
        //调用不同的sqlSession,缓存不一样

        sqlSession1.commit();
        sqlSession2.commit();
        sqlSession1.close();
        sqlSession2.close();
    }

//    @Test
//    public void testSelectById(){
//        SqlSession sqlSession = SqlSessionUtil.openSession();
//        CarMapper mapper1 = sqlSession.getMapper(CarMapper.class);
//        Car car1 = mapper1.selectById(34L);
//        System.out.println(car1);
//
//        CarMapper mapper2 = sqlSession.getMapper(CarMapper.class);
//        Car car2 = mapper2.selectById(34L);
//        System.out.println(car2);
//        //可见都是基于sqlSession的,所以只会调用一个sql语句
//        //一样的话就直接从缓存中调用出来
//
//        sqlSession.commit();
//        sqlSession.close();
//    }

}

在这里插入图片描述

14.2.1 一级缓存的失效

什么情况下不走缓存?

  1. 第一种:不同的SqlSession对象。
  2. 第二种:查询条件变化了。

一级缓存失效情况包括两种:

  • 第一种:第一次查询和第二次查询之间,手动清空了一级缓存。即执行了sqlSession的clearCache()方法
       @Test
    public void testSelectById(){
        SqlSession sqlSession = SqlSessionUtil.openSession();

        CarMapper mapper1 = sqlSession.getMapper(CarMapper.class);
        Car car1 = mapper1.selectById(34L);
        System.out.println(car1);

        //手动清空了一级缓存
        sqlSession.clearCache();

        CarMapper mapper2 = sqlSession.getMapper(CarMapper.class);
        Car car2 = mapper2.selectById(34L);
        System.out.println(car2);


        sqlSession.commit();
        sqlSession.close();
    }

在这里插入图片描述

  • 第二种:第一次查询和第二次查询之间,执行了增删改操作。【这个增删改和哪张表没有关系,只要有insert delete update操作,一级缓存就失效。】
    <insert id="insertClazz">
        insert into t_clazz values (#{cid},#{cname});
    </insert>
    /*
     * 保存班级信息
     * @param cid
     * @param cname
     * @version 1.0
    */
    int insertClazz(@Param("cid") Integer cid, @Param("cname") String cname);
       @Test
    public void testSelectById(){
        SqlSession sqlSession = SqlSessionUtil.openSession();

        CarMapper mapper1 = sqlSession.getMapper(CarMapper.class);
        Car car1 = mapper1.selectById(34L);
        System.out.println(car1);

        //手动清空了一级缓存
//        sqlSession.clearCache();

        //这里执行了insert delete update中的任意一个语句,并且和表没有关系
            CarMapper mapper = sqlSession.getMapper(CarMapper.class);
            mapper.insertClazz(2000,"高三三班");
            CarMapper mapper2 = sqlSession.getMapper(CarMapper.class);

            Car car2 = mapper2.selectById(34L);
        System.out.println(car2);


        sqlSession.commit();
        sqlSession.close();
    }

在这里插入图片描述

14.3 二级缓存的使用

二级缓存的范围是SqlSessionFactory。
使用二级缓存需要具备以下几个条件:

  1. <setting name="cacheEnabled" value="true"> 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。默认就是true,无需设置。

  2. 在需要使用二级缓存的SqlMapper.xml文件中添加配置:<cache />

  3. 使用二级缓存的实体类对象必须是可序列化的,也就是必须实现java.io.Serializable接口

    在这里插入图片描述

  4. SqlSession对象关闭或提交之后,一级缓存中的数据才会被写入到二级缓存当中。此时二级缓存才可用。

测试二级缓存:

  • XxxMapper.xml文件
<cache/>
  • Xxx类文件
public class Car implements Serializable {
//......
}
  • 测试
@Test
    public void testSelectById2() throws IOException {
        //这里只有一个SqlSessionFactory对象,二级缓存对应的就是SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
        CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);

        //这行代码执行结束之后,实际上数据是缓存到一级缓存当中了(sqlSession是一级缓存)
        Car car1 = mapper1.selectById2(34L);
        System.out.println(car1);

        //如果这里不关闭SqlSession对象的话,二级缓存中还是没有数据的

        //如果执行了这行代码,sqlSession1的一级缓存中的数据会放到二级缓存当中
        sqlSession1.close();

        //这行代码执行结束之后,实际上数据会缓存到一级缓存当中(sqlSession是二级缓存)
        Car car2 = mapper2.selectById2(34L);
        System.out.println(car2);

        //程序执行到这里的时候,会奖sqlSession1这个一级缓存中的数据写入到二级缓存当中
//        sqlSession1.close();
        //程序执行到这里的时候,会奖sqlSession2这个一级缓存中的数据写入到二级缓存当中
        sqlSession2.close();
    }

在这里插入图片描述

14.3.1 二级缓存的相关配置

二级缓存的失效:只要两次查询之间出现了增删改操作。二级缓存就会失效。【一级缓存也会失效】

二级缓存的相关配置:
在这里插入图片描述

  1. eviction:指定从缓存中移除某个对象的淘汰算法。默认采用LRU策略。
    • LRU:Least Recently Used。最近最少使用。优先淘汰在间隔时间内使用频率最低的对象。(其实还有一种淘汰算法LFU,最不常用。)
    • FIFO:First In First Out。一种先进先出的数据缓存器。先进入二级缓存的对象最先被淘汰。
    • SOFT:软引用。淘汰软引用指向的对象。具体算法和JVM的垃圾回收算法有关。
    • WEAK:弱引用。淘汰弱引用指向的对象。具体算法和JVM的垃圾回收算法有关。
  2. flushInterval:
    二级缓存的刷新时间间隔。单位毫秒。如果没有设置。就代表不刷新缓存,只要内存足够大,一直会向二级缓存中缓存数据。除非执行了增删改。
  3. readOnly:
    true:多条相同的sql语句执行之后返回的对象是共享的同一个。性能好。但是多线程并发可能会存在安全问题。
    false:多条相同的sql语句执行之后返回的对象是副本,调用了clone方法。性能一般。但安全。
  4. size:
    设置二级缓存中最多可存储的java对象数量。默认值1024。

14.4 集成Ehcache

集成EhCache是为了代替mybatis自带的二级缓存。一级缓存是无法替代的。

mybatis对外提供了接口,也可以集成第三方的缓存组件。比如EhCache、Memcache等。都可以。

EhCache是Java写的。Memcache是C语言写的。所以mybatis集成EhCache较为常见,按照以下步骤操作,就可以完成集成:

  • 第一步:引入mybatis整合ehcache的依赖。在pom文件里引入
        <!--mybatis集成ehcache的组件-->
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.2.2</version>
        </dependency>
  • 第二步:在类的根路径下新建echcache.xml文件,并提供以下配置信息。
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!--磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存-->
    <diskStore path="e:/ehcache"/>
  
    <!--defaultCache:默认的管理策略-->
    <!--eternal:设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断-->
    <!--maxElementsInMemory:在内存中缓存的element的最大数目-->
    <!--overflowToDisk:如果内存中数据超过内存限制,是否要缓存到磁盘上-->
    <!--diskPersistent:是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false-->
    <!--timeToIdleSeconds:对象空闲时间(单位:秒),指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问-->
    <!--timeToLiveSeconds:对象存活时间(单位:秒),指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问-->
    <!--memoryStoreEvictionPolicy:缓存的3 种清空策略-->
    <!--FIFO:first in first out (先进先出)-->
    <!--LFU:Less Frequently Used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存-->
    <!--LRU:Least Recently Used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存-->
    <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false"
                  timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"/>

</ehcache>

  • 第三步:修改SqlMapper.xml文件中的标签,添加type属性。
<!--集成Ehcache组件-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
  • 第四步:编写测试程序使用。
@Test
    public void testSelectById2() throws IOException {
        //这里只有一个SqlSessionFactory对象,二级缓存对应的就是SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
        CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);

        //这行代码执行结束之后,实际上数据是缓存到一级缓存当中了(sqlSession是一级缓存)
        Car car1 = mapper1.selectById2(34L);
        System.out.println(car1);

        //如果这里不关闭SqlSession对象的话,二级缓存中还是没有数据的

        //如果执行了这行代码,sqlSession1的一级缓存中的数据会放到二级缓存当中
        sqlSession1.close();

        //这行代码执行结束之后,实际上数据会缓存到一级缓存当中(sqlSession是二级缓存)
        Car car2 = mapper2.selectById2(34L);
        System.out.println(car2);

        //程序执行到这里的时候,会奖sqlSession1这个一级缓存中的数据写入到二级缓存当中
//        sqlSession1.close();
        //程序执行到这里的时候,会奖sqlSession2这个一级缓存中的数据写入到二级缓存当中
        sqlSession2.close();
    }

日志信息又不一样了
在这里插入图片描述

十五 小黑子的MyBatis逆向工程

所谓的逆向工程是:根据数据库表逆向生成Java的pojo类,SqlMapper.xml文件,以及Mapper接口类等。
要完成这个工作,需要借助别人写好的逆向工程插件。

思考:使用这个插件的话,需要给这个插件配置哪些信息?

  • pojo类名、包名以及生成位置。
  • SqlMapper.xml文件名以及生成位置。
  • Mapper接口名以及生成位置。
  • 连接数据库的信息。
  • 指定哪些表参与逆向工程。…

15.1 逆向工程配置与生成(使用基础版)

第一步:基础环境准备
新建模块:模块名
打包方式:jar

第二步:在pom中添加逆向工程插件

<!--定制构建过程-->
<build>
  <!--可配置多个插件-->
  <plugins>
    <!--其中的一个插件:mybatis逆向工程插件-->
    <plugin>
      <!--插件的GAV坐标-->
      <groupId>org.mybatis.generator</groupId>
      <artifactId>mybatis-generator-maven-plugin</artifactId>
      <version>1.3.7</version>
      <!--允许覆盖-->
      <configuration>
        <overwrite>true</overwrite>
      </configuration>
      <!--插件的依赖-->
      <dependencies>
        <!--mysql驱动依赖-->
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.30</version>
        </dependency>
      </dependencies>
    </plugin>
  </plugins>
</build>

第三步:配置generatorConfig.xml

该文件名必须叫做:generatorConfig.xml
该文件必须放在类的根路径下。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <!--
        targetRuntime有两个值:
            MyBatis3Simple:生成的是基础版,只有基本的增删改查。
            MyBatis3:生成的是增强版,除了基本的增删改查之外还有复杂的增删改查。
    -->
    <context id="DB2Tables" targetRuntime="MyBatis3Simple">
        <!--防止生成重复代码-->
        <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>

        <commentGenerator>
            <!--是否去掉生成日期-->
            <property name="suppressDate" value="true"/>
            <!--是否去除注释-->
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>

        <!--连接数据库信息-->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/powernode"
                        userId="root"
                        password="root">
        </jdbcConnection>

        <!-- 生成pojo包名和位置 -->
        <javaModelGenerator targetPackage="com.powernode.mybatis.pojo" targetProject="src/main/java">
            <!--是否开启子包-->
            <property name="enableSubPackages" value="true"/>
            <!--是否去除字段名的前后空白-->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <!-- 生成SQL映射文件的包名和位置 -->
        <sqlMapGenerator targetPackage="com.powernode.mybatis.mapper" targetProject="src/main/resources">
            <!--是否开启子包-->
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>

        <!-- 生成Mapper接口的包名和位置 -->
        <javaClientGenerator
                type="xmlMapper"
                targetPackage="com.powernode.mybatis.mapper"
                targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>

        <!-- 表名和对应的实体类名-->
        <table tableName="t_car" domainObjectName="Car"/>

    </context>
</generatorConfiguration>

第四步:在Mavn那里双击运行插件

在这里插入图片描述
但是注意,其他的什么源文件,比如:日志文件、核心配置文件、jdbc文件还是要自己弄

15.1.1 测试基础版

注意:自动生成的pojo类没有toString方法,要自己补上才能看到显示的

package com.powernode.mybatis.test;


import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class CarMapperTest {
    @Test
    public void testSelectAll(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectAll();
        cars.forEach(car -> System.out.println(car));

        sqlSession.commit();
        sqlSession.close();
    }
}

在这里插入图片描述

15.2 使用增强版

前面的步骤同基础版一样

第三步:改变的增强版

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <!--
        targetRuntime有两个值:
            MyBatis3Simple:生成的是基础版,只有基本的增删改查。
            MyBatis3:生成的是增强版,除了基本的增删改查之外还有复杂的增删改查。
    -->
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <!--防止生成重复代码-->
        <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>
      
        <commentGenerator>
            <!--是否去掉生成日期-->
            <property name="suppressDate" value="true"/>
            <!--是否去除注释-->
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>

        <!--连接数据库信息-->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/powernode"
                        userId="root"
                        password="root">
        </jdbcConnection>

        <!-- 生成pojo包名和位置 -->
        <javaModelGenerator targetPackage="com.powernode.mybatis.pojo" targetProject="src/main/java">
            <!--是否开启子包-->
            <property name="enableSubPackages" value="true"/>
            <!--是否去除字段名的前后空白-->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <!-- 生成SQL映射文件的包名和位置 -->
        <sqlMapGenerator targetPackage="com.powernode.mybatis.mapper" targetProject="src/main/resources">
            <!--是否开启子包-->
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>

        <!-- 生成Mapper接口的包名和位置 -->
        <javaClientGenerator
                type="xmlMapper"
                targetPackage="com.powernode.mybatis.mapper"
                targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>

        <!-- 表名和对应的实体类名-->
        <table tableName="t_car" domainObjectName="Car"/>

    </context>
</generatorConfiguration>

增强版会提供一些不同的方法,报错的原因是缺少相关依赖
在这里插入图片描述

15.2.1 测试增强版的查询

package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class CarMapperTest {

    //CarExample类负责封装查询条件的
    @Test
    public void testSelect(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        //执行查询
        //1.查询一个
        Car car = mapper.selectByPrimaryKey(34L);
        System.out.println(car);
        //2.查询所有,如果条件是null,则表示没有条件
        List<Car> cars = mapper.selectByExample(null);
        cars.forEach(car1-> System.out.println(car1));

        //3.按照条件进行查询

        sqlSession.commit();
        sqlSession.close();
    }

}

在这里插入图片描述

15.3 QBC的查询风格

package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.pojo.CarExample;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.math.BigDecimal;
import java.util.List;

public class CarMapperTest {

    //CarExample类负责封装查询条件的
    @Test
    public void testSelect(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        //执行查询
        //1.查询一个
        Car car = mapper.selectByPrimaryKey(34L);
        System.out.println(car);
        //2.查询所有,如果条件是null,则表示没有条件
        List<Car> cars = mapper.selectByExample(null);
        cars.forEach(car1-> System.out.println(car1));
        System.out.println("==========================================");
        //3.按照条件进行查询
        //QBC 风格:Query By Criteria 一种查询方式:比较面向对象,看不到sql语句
        // 封装条件,通过CarExample对象来封装查询条件
        CarExample carExample = new CarExample();
        //调用carExample.createCriteria()方法来创建查询条件
        carExample.createCriteria()
                .andBrandLike("byd")
                .andGuidePriceGreaterThan(new BigDecimal(5.0));

        //添加or
        carExample.or().andCarTypeEqualTo("电车");
        //执行查询
        List<Car> cars2 = mapper.selectByExample(carExample);
        cars2.forEach(car2-> System.out.println(car2));

        sqlSession.commit();
        sqlSession.close();
    }

}

在这里插入图片描述

QBC 风格:Query By Criteria 一种查询方式,比较面向对象,看不到sql语句。

十六 小黑子的MyBatis使用PagHelper

16.1 分页原理

在这里插入图片描述

16.2 limit分页

mysql的limit后面两个数字:

  • 第一个数字:startIndex(起始下标。下标从0开始。)
  • 第二个数字:pageSize(每页显示的记录条数)

假设已知页码pageNum,还有每页显示的记录条数pageSize,第一个数字可以动态的获取吗?

  • startIndex = (pageNum - 1) * pageSize
    所以,标准通用的mysql分页SQL:
select 
  * 
from 
  tableName ...... 
limit 
  (pageNum - 1) * pageSize, pageSize

使用mybatis应该怎么做?

  • CarMapper.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="com.powernode.mybatis.mapper.CarMapper">
    <select id="selectByPage" resultType="Car">
        select * from t_car limit #{startIndex},#{pageSize}
    </select>

</mapper>
  • CarMapper接口
package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface CarMapper {
    /*
     * @分页查询
     * @param startIndex 起始下标
     * @param pageSize 每页显示的记录条数
     * @version 1.0
    */
    List<Car> selectByPage(@Param("startIndex") int startIndex,@Param("pageSize") int pageSize);

}

  • 测试
package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class CarMapperTest {
    @Test
    public void testSelectByPage(){
        // 获取每页显示的记录条数
        int pageSize = 3;
        //显示第几页:页码
        int pageNum = 2;
        // 计算开始下标
        int startIndex = (pageSize - 1) *pageNum;

        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectByPage(startIndex, pageSize);
        cars.forEach(car -> System.out.println(car));

        sqlSession.commit();
        sqlSession.close();
    }
}

在这里插入图片描述

获取数据不难,难的是获取分页相关的数据比较难。可以借助mybatis的PageHelper插件。

16.3 使用PageHelper插件

使用PageHelper插件进行分页,更加的便捷。

第一步:在pom文件里引入依赖

<dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper</artifactId>
  <version>5.3.1</version>
</dependency>

第二步:在mybatis-config.xml文件中配置插件

typeAliases标签下面进行配置:

<plugins>
  <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

第三步:编写Java代码

    <select id="selectAll" resultType="Car">
        select * from t_car
    </select>

    /*
     * 查询所有car,通过分页查询插件PageHelper完成
     * @version 1.0
    */
    List<Car> selectAll();
  @Test
    public void testSelectAll(){

        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);

        //一定一定耀注意:在执行DQL语句之前。开启分页功能
        int pageNum = 2;
        int pageSize = 3;
        PageHelper.startPage(pageNum,pageSize);
        List<Car> cars = mapper.selectAll();
        cars.forEach(car -> System.out.println(car));

        sqlSession.commit();
        sqlSession.close();
    }

在这里插入图片描述

16.3.1 获取PageInfo对象

关键点:

  • 在查询语句之前开启分页功能。
  • 在查询语句之后封装PageInfo对象。(PageInfo对象将来会存储到request域当中。在页面上展示。)
 @Test
    public void testSelectAll(){

        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);

        //一定一定耀注意:在执行DQL语句之前。开启分页功能
        int pageNum = 2;
        int pageSize = 3;
        PageHelper.startPage(pageNum,pageSize);
        List<Car> cars = mapper.selectAll();
//        cars.forEach(car -> System.out.println(car));

        //封装分页信息对象new PageInfo()
        // PageInfo对象是PageHelper插件提供的,用来封装分页相关的信息对象
        PageInfo<Car> carPageInfo = new PageInfo<>(cars, 3);
        System.out.println(carPageInfo);

        sqlSession.commit();
        sqlSession.close();
    }

执行结果:

PageInfo{pageNum=2, pageSize=3, size=3, startRow=4, endRow=6, total=8, pages=3, 
list=Page{count=true, pageNum=2, pageSize=3, startRow=3, endRow=6, total=8, pages=3, reasonable=false, pageSizeZero=false}[Car{id=4, carNum='9999', brand='magua', guidePrice=30, produceTime='1999-11-10', carType='旧能源'}, 
Car{id=6, carNum='8888', brand='法克鱿', guidePrice=30, produceTime='2000-11-66', carType='捞车'}, 
Car{id=7, carNum='8888', brand='法克鱿', guidePrice=30, produceTime='2000-11-66', carType='捞车'}], 
prePage=1, nextPage=3, isFirstPage=false, isLastPage=false, hasPreviousPage=true, hasNextPage=true, navigatePages=3, navigateFirstPage=1, navigateLastPage=3, navigatepageNums=[1, 2, 3]}

pageNum页码
pageSize每页显示几条记录
startRow是整个mysql数据库表中从第几条记录开始
endRow是最后一条记录
total总记录条数
pages记录条数三页

十七 小黑子的MyBatis注解式开发

mybatis中也提供了注解式开发方式,采用注解可以减少Sql映射文件的配置。
当然,使用注解式开发的话,sql语句是写在java程序中的,这种方式也会给sql语句的维护带来成本。

官方是这么说的:

使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL
语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。

使用注解编写复杂的SQL是这样的:
在这里插入图片描述

原则:简单sql可以注解。复杂sql使用xml。

17.1 @Insert注解

package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Insert;

public interface CarMapper {

    @Insert(value="insert into t_car values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})")
    int insert(Car car);
}
package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

public class AnnotationTest {
    @Test
    public void testInsert() throws Exception{
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = new Car(null, "1112", "卡罗拉", 30.0, "2000-10-10", "燃油车");
        int count = mapper.insert(car);
        System.out.println("插入了几条记录:" + count);
        sqlSession.commit();
        sqlSession.close();
    }
}


17.2 @Delete注解

@Delete("delete from t_car where id = #{id}")
int deleteById(Long id);
@Test
public void testDelete() throws Exception{
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
    SqlSession sqlSession = sqlSessionFactory.openSession();
    CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    mapper.deleteById(89L);
    sqlSession.commit();
    sqlSession.close();
}

17.3 @Update注解

@Update("update t_car set car_num=#{carNum},brand=#{brand},guide_price=#{guidePrice},produce_time=#{produceTime},car_type=#{carType} where id=#{id}")
int update(Car car);
@Test
public void testUpdate() throws Exception{
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
    SqlSession sqlSession = sqlSessionFactory.openSession();
    CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    Car car = new Car(88L,"1001", "凯美瑞", 30.0,"2000-11-11", "新能源");
    mapper.update(car);
    sqlSession.commit();
    sqlSession.close();
}

17.4 @Select注解

@Select("select * from t_car where id = #{id}")
})
Car selectById(Long id);
@Test
public void testSelectById() throws Exception{
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
    SqlSession sqlSession = sqlSessionFactory.openSession();
    CarMapper carMapper = sqlSession.getMapper(CarMapper.class);
    Car car = carMapper.selectById(88L);
    System.out.println(car);
}

17.5 @Result注解

@Select("select * from t_car where id = #{id}")
@Results({
    @Result(column = "id", property = "id", id = true),
    @Result(column = "car_num", property = "carNum"),
    @Result(column = "brand", property = "brand"),
    @Result(column = "guide_price", property = "guidePrice"),
    @Result(column = "produce_time", property = "produceTime"),
    @Result(column = "car_type", property = "carType")
})
Car selectById(Long id);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1099158.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

lv8 嵌入式开发-网络编程开发 18 广播与组播的实现

目录 1 广播 1.1 什么是广播&#xff1f; 1.2 广播地址 1.3 广播的实现 2 组播 2.1 分类的IP地址 2.2 多播 IP 地址 2.3 组播的实现 1 广播 1.1 什么是广播&#xff1f; 数据包发送方式只有一个接受方&#xff0c;称为单播 如果同时发给局域网中的所有主机&#xff0…

Python浏览器自动化

如果你正在进行手机爬虫的工作&#xff0c;并且希望通过模拟浏览器行为来抓取数据&#xff0c;那么Pyppeteer将会是你的理想选择。Pyppeteer是一个强大的Python库&#xff0c;它可以让你控制浏览器进行自动化操作&#xff0c;如点击按钮、填写表单等&#xff0c;从而实现数据的…

以数智化指标管理,驱动光伏能源行业的市场推进

近年来&#xff0c;碳中和、碳达峰等降低碳排放、提升环境健康度的政策和技术改进正在不断地被社会所认可和引起重视&#xff0c;也被越来越多的企业在生产运营和基础建设中列为重要目标之一。而光伏能源行业作为全球绿色能源、新能源的优秀解决方案&#xff0c;充分利用太阳能…

Linux小程序---进度条

一&#xff1a;\r 和 \n \r --- 回车 --- 使光标回到这一行的开头 \n --- 换行 --- 会来到下一行与之平行的位置 缓冲区的问题&#xff1a; <1>: \n 的示例 正常输出 hehehehe 。 <2>: \r 的示例 为了方便观察&#xff0c;加入一个 sleep &#xff08;休眠函数…

[GSEP202306 一级] C++ 时间规划

题目描述 小明在为自己规划学习时间。现在他想知道两个时刻之间有多少分钟&#xff0c;你通过编程帮他做到吗? 输入格式 输入4行&#xff0c;第一行为开始时刻的小时&#xff0c;第二行为开始时刻的分钟&#xff0c;第三行为结束时刻的小时&#xff0c;第四行为结束时刻的分…

新能源电池试验中准确模拟高空环境大气压力的解决方案

摘要&#xff1a;针对目前新能源电池热失控和特性研究以及生产中缺乏变环境压力准确模拟装置、错误控制方法造成环境压力控制极不稳定以及氢燃料电池中氢气所带来的易燃易爆问题&#xff0c;本文提出了相应的解决方案。方案的关键一是采用了低漏率电控针阀作为下游控制调节阀实…

MySQL锁学习笔记

锁 事务的隔离性由锁来实现。 概述 锁是计算机协调多个进程或线程并发访问某一资源的机制。在程序开发中会存在多线程同步的问题&#xff0c;当多个线程并发访问某个数据的时候&#xff0c;尤其是针对一些敏感的数据&#xff08;比如订单、金额等&#xff09;&#xff0c;我…

第二届中国未来交通产业发展峰会在深举办 聚焦智能网联、低空经济

智慧交通、低空飞行、自动驾驶……交通产业“未来已来”。10月12日&#xff0c;2023第二届中国未来交通产业发展峰会在深圳成功举办。本次峰会是国内聚焦高级别智能网联、低空产业、智慧物流、新能源和交通装备发展的高水平行业盛会&#xff0c;为行业搭建上下游沟通交流的广阔…

编译链接(Compile Link)

文章目录 前言一、翻译环境1、概念2、翻译环境的组成3、什么是编译链接&#xff1f; 二、编译1、编译的阶段2、预编译3、编译1、什么是语法分析&#xff1f;2、什么是词法分析&#xff1f;3、什么是语义分析&#xff1f;4、什么是符号汇总&#xff1f; 4、汇编1、符号表展示 三…

逼近5%!本土供应商挑战智能驾驶SoC主力份额,这三家企业率先入列

随着汽车行业迈进电动化、智能化周期&#xff0c;动力电池&#xff08;满足动力&#xff09;和芯片&#xff08;满足算力&#xff09;两个核心赛道陆续刮起「中国」旋风。 其中&#xff0c;中国动力电池厂商无论是在中国还是全球&#xff0c;市场份额逐步赶超日韩&#xff0c;…

11-k8s-service网络

文章目录 一、网络相关资源介绍二、开启ipvs三、nginx网络示例四、pod之间的访问示例五、service反向代理示例 一、网络相关资源介绍 Servcie介绍 Service是对一组提供相同功能的Pods的抽象&#xff0c;并为它们提供一个统一的入口。借助Service&#xff0c;应用可以方便的实现…

C++继承重要知识点总结(上)

目录 一.前言 二.继承机制 三.父子类赋值兼容规则 四.继承中的作用域 五.子类的默认成员函数 1.构造函数 2.拷贝构造函数 3.赋值重载函数 4.析构函数 一.前言 继承作为C的三大特性之一&#xff0c;其重要性不言而喻&#xff0c;只有学好了继承才能为后面的多态打下基础…

数据结构-----红黑树的插入

目录 前言 红黑树的储存结构 一、节点旋转操作 左旋&#xff08;Left Rotation&#xff09; 右旋&#xff08;Right Rotation&#xff09; 二、插入节点 1.插入的是空树 2.插入节点的key重新重复 3.插入节点的父节点是黑色 4.插入节点的父节点是红色 4.1父节点是祖父…

“之江创客”亚洲赛区完美收官 助力浙亚经贸高质量发展

10月13日下午&#xff0c;由商务部中国国际电子商务中心指导&#xff0c;浙江省商务厅等十个部门主办&#xff0c;浙江省电子商务促进中心承办的“之江创客”2023全球电子商务创业创新大赛亚洲赛区决赛成功举办。浙江省商务厅党组成员、副厅长张钱江出席活动并致辞&#xff0c;…

DDoS攻击与CC攻击:网络安全的两大挑战

在今天的数字时代&#xff0c;网络安全问题越来越突出&#xff0c;其中分布式拒绝服务攻击&#xff08;DDoS攻击&#xff09;和HTTP洪泛攻击&#xff08;CC攻击&#xff09;是两种常见的网络威胁。本文将探讨这两种攻击的概念、原理以及如何有效地应对它们。 1. DDoS攻击&…

Python的logging模块(日志、DEBUG、INFO、WARNING、ERROR、CRITICAL)

1. 前言 logging 是 Python 标准库中用于记录日志的模块。它提供了一种灵活且可配置的方式来在应用程序中记录各种信息&#xff0c;包括调试信息、警告和错误消息。无论是写框架代码还是业务代码&#xff0c;都离不开日志的记录&#xff0c;它能给我们定位问题带来极大的帮助。…

哈夫曼树的建立(C++,最优树)

介绍&#xff1a; 哈夫曼树&#xff08;Huffman Tree&#xff09;是一种用于数据压缩的树形数据结构。它是由刚特哈夫曼于1952年发明的。 哈夫曼树的特点是&#xff1a;对于一个长度为n的字符集&#xff0c;它可以将每个字符在树上表示为一个唯一的二进制编码。在哈夫曼树中&am…

C语言——编译全过程的那些事

C语言——编译全过程的那些事 一、C语言的编译过程二、编译的详细过程2.1预编译过程2.2编译过程2.3 汇编过程2.4链接过程 三、编译全过程 一、C语言的编译过程 1.C语言的编译过程通常可以分为两个大的部分&#xff0c;编译和链接。 2.在ANSI C的任何一种实现中&#xff0c;存…

Vue检测数据的原理

Vue能够对用户的数据进行响应式&#xff0c;也就是你在data中写了什么&#xff0c;你在模板中用到data的部分就会渲染成什么&#xff0c;那么Vue是怎么知道用户修改了data中的数据变化并对模板重新进行解析的呢&#xff1f; 在Vue将数据存储为自身的_data之前&#xff0c;Vue会…

《中国工业经济》企业数字化转型与供应链配置—集中化还是多元化

文章利用2010-2021年A股上市公司数据&#xff0c;从供应链治理角度系统验证了企业数字化转型对供应链配置的影响及其作用机制 研究发现&#xff0c;企业数字化转型显著降低了供应链上游供应商、下游客户以及供应链整体集中度&#xff0c;推动供应链配置多元化&#xff1b;该推…