项目前的知识回顾

news2024/10/6 16:24:54

杂谈

什么是框架

应用方面:框架是整个或者部分系统的可重用设计

目的方面:框架是可被开发者定制的应用骨架

统一的舞台,不同人表演不同的节目

框架解决什么问题

框架主要解决技术整合的问题

MYBATIS

什么是Mybatis

Mybatis是一款半自动ORM持久层框架,具有较高的SQL灵活性,支持高级映射(一对一,多对多),动态SQL,延迟加载,缓存等

什么是ORM

对象关系映射(Object Relation Mapping)对象是指java对象,关系是指数据库中的关系模型,映射就是对象与关系模型之间的联系

解决的问题

  • 数据库频繁的创建链接,销毁内存,造成了资源浪费,使用数据库连接池可以解决这个问题
  • sql语句在代码中硬编码,sql变化可能较大,sql变化需要改变java代码
  • prepareStatement向占位符传参存在硬编码,where语句不一定,修改where需要修改java代码
  • 结果集存在硬编码,sql变化导致解析代码变化,系统不易维护

Mybatis与Hibernate的区别

Mybatis:

  • 入门简单,即学即用,提供了数据库查询的自动对象绑定功能

  • 可以进行更为细致的SQL优化,可以减少查询字段

  • 缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改

  • 二级缓存机制不佳

Hibernate : 

  • 功能强大,数据库无关性好,对象关系(O/R)映射能力强

  • 有更好的二级缓存机制,可以使用第三方缓存

  • 缺点就是学习门槛不低,要精通门槛更高,而且怎么设计对象关系(O/R)映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate方面需要你的经验和能力都很强才行

快速开发

引入项目依赖

	<dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.10</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </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>
  <!-- 链接数据库只需要一个属性来配置文件,就会自动解析 -->
  <properties resource="jdbc.properties" />
  <!--  设置别名,然后就可以使用别名来代替前面的路径 -->
    <typeAliases>
    <typeAlias type="com.tledu.zrz.model.User" alias="User"/>
    <typeAlias type="com.tledu.zrz.model.Address" alias="Address"/>
    </typeAliases>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <!-- 映射文件 -->
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

创建数据库配置文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/erp16?useUnicode=true&characterEncoding=UTF-8
username=root
password=root

创建对应数据库字段的实体类

package com.wzx.SSMOne.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String username;
    private String password;
    private String nickname;
    private Integer type;
}

创建接口书写方法

package com.wzx.MybatisOne.dao;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface InterUserMapper {
//    @Select("select * from t_user where id = #{id}")
    /*@Select("select * from t_user where id = #{id}")
    User getById(int id);*/

    int add(User user);

    User getById(int id);


    List<User> getList(@Param("username") String username);


}

创建上面接口的映射文件   同名的mapper.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">
<!--
    namespace 是用于调用的时候的映射,对应绑定的接口类
 -->

<mapper namespace="com.wzx.MybatisOne.dao.InterUserMapper">
  <insert id="add" parameterType="User" >
    <!-- 这里的#username 就等于是用 ? 的方式,等方法调用的时候,会传递一个参数,就会自动映射到username的属性上 -->
    insert into t_user (username,password,nickname) values (#{username},#{password},#{nickname})
  </insert>

  <select id="getList" resultType="User" parameterType="String">
    select * from t_user
    where username = #{username}
  </select>

  <select id="getById" parameterType="int" resultType="User">
    select * from t_user where id = #{id}
  </select>


</mapper>

他俩的关系如图所示

 测试---使用sqlSession测试

import com.wzx.MybatisOne.dao.InterUserMapper;
import com.wzx.MybatisOne.dao.User;
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.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.AfterAll;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestInter {

    SqlSession sqlSession;
    @Before
    public void beforeSome() throws IOException {
        String resource = "mybatis-config.xml";

        //读取配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream(resource);

        //获取session工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //获取session
        sqlSession = factory.openSession();
    }


    @Test
    public void insertSome(){
        User user = new User();
        user.setUsername("1234");
        user.setPassword("1234");
        user.setNickname("1234");
        user.setNickname("1234");

        User byId = sqlSession.getMapper(InterUserMapper.class).getById(2);
        System.out.println(byId);

    }

    @Test
    public void insertInterfaceSome(){
        User user = new User();
        user.setUsername("1234");
        user.setPassword("1234");
        user.setNickname("1234");
        user.setNickname("1234");

        sqlSession.getMapper(InterUserMapper.class).add(user);
    }


    @Test
    public void getByName(){
        List<User> wzx = sqlSession.getMapper(InterUserMapper.class).getList("wzx");
        wzx.stream().forEach(System.out::println);
    }

    @After
    public void afterSome(){
        sqlSession.commit();
    }
}

 

总结:

  • 引入依赖,加载依赖
  • 编写全局配置文件,配置数据源
  • 编写对应数据库字段的实体类
  • 编写实现接口
  • 编写接口的映射文件---同名
  • 通过全局配置文件,创建SqlSessionFactory
  • 调用sqlSession上的一系列方法

各个子标签

<properties>

一般将数据源的信息单独放在一个properties文件中,然后用这个标签引入,在下面environment标签中,就可以用${}占位符快速获取数据源的信息

<settings>

用来开启或关闭mybatis的一些特性,比如可以用<setting name="lazyLoadingEnabled" value="true"/>来开启延迟加载,可以用<settings name="cacheEnabled" value="true"/>来开启二级缓存

<typeAliases>

给实体类起别名   resultType属性要写com.yogurt.po.Student,这太长了,所以可以用别名来简化书写

<plugins>

可以用来配置mybatis的插件,比如在开发中经常需要对查询结果进行分页,就需要用到pageHelper分页插件,这些插件就是通过这个标签进行配置的

<environments>

用来配置数据源

<mappers>

用来配置mapper.xml映射文件,这些xml文件里都是SQL语句

mapper.xml的SQL语句中的占位符${}#{}

一般会采用#{},#{}在mybatis中,最后会被解析为?,其实就是Jdbc的PreparedStatement中的?占位符,它有预编译的过程,会对输入参数进行类型解析(如果入参是String类型,设置参数时会自动加上引号),可以防止SQL注入,如果parameterType属性指定的入参类型是简单类型的话(简单类型指的是8种java原始类型再加一个String),#{}中的变量名可以任意,如果入参类型是pojo,比如是Student类那么#{name}表示取入参对象Student中的name属性,#{age}表示取age属性,这个过程是通过反射来做的,这不同于${}${}取对象的属性使用的是OGNL(Object Graph Navigation Language)表达式

${},一般会用在模糊查询的情景,比如SELECT * FROM student WHERE name like '%${name}%';


Mapper三种开发形式

  • sqlSession执行对应语句,就是我们上面测试的那种

  • 使用注解(简单sql)

  • 利用接口代理(常用)

我们上面的快速入门就是使用的第一种sqlSession

使用接口代理

只需要在同目录写一个mapper接口和一个mapper映射文件即可

记住:

  1. mapper接口的全限定名,要和mapper.xml的namespace属性一致
  2. mapper接口中的方法名要和mapper.xml中的SQL标签的id一致
  3. mapper接口中的方法入参类型,要和mapper.xml中SQL语句的入参类型一致
  4. mapper接口中的方法出参类型,要和mapper.xml中SQL语句的返回值类型一致

效果如图
同名同级

其他不变,即可测试

效果如图

使用注解

直接在方法上,使用注解定义sql

此时还需在配置文件中定义一个映射,如下图

映射指定上图中的包名,意思是映射dao包下的所有接口

其他不变,效果如图

小case

主键返回

通常我们会将数据库表的主键id设为自增。在插入一条记录时,我们不设置其主键id,而让数据库自动生成该条记录的主键id,那么在插入一条记录后,如何得到数据库自动生成的这条记录的主键id呢?有两种方式

1.使用useGeneratedKeyskeyProperty属性

<insert id="insert" parameterType="com.yogurt.po.Student" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO student (name,score,age,gender) VALUES (#{name},#{score},#{age},#{gender});
    </insert>

2.使用<selectKey>子标签

<insert id="insert" parameterType="com.yogurt.po.Student">
        INSERT INTO student (name,score,age,gender) VALUES (#{name},#{score},#{age},#{gender});
        <selectKey keyProperty="id" order="AFTER" resultType="int" >
            SELECT LAST_INSERT_ID();
        </selectKey>
    </insert>

如果使用的是mysql这样的支持自增主键的数据库,可以简单的使用第一种方式;

测试代码如下

public class MapperProxyTest {
	private SqlSessionFactory sqlSessionFactory;

	@Before
	public void init() throws IOException {
		InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
	}

	@Test
	public void test() {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
		Student student = new Student(-1, "Podman", 130, 15, 0);
		mapper.insert(student);
		sqlSession.commit();
		System.out.println(student.getId());
	}
}

批量处理

主要是动态SQL标签的使用,注意如果parameterTypeList的话,则在标签体内引用这个List,只能用变量名list,如果parameterType是数组,则只能用变量名array

<select id="batchFind" resultType="student" parameterType="java.util.List">
        SELECT * FROM student
        <where>
            <if test="list != null and list.size() > 0">
                AND id in
                <foreach collection="list" item="id" open="(" separator="," close=")">
                    #{id}
                </foreach>
            </if>
        </where>
</select>
	@Test
	public void testBatchQuery() {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
		List<Student> students = mapper.batchFind(Arrays.asList(1, 2, 3, 7, 9));
		students.forEach(System.out::println);
	}

结果

image-20200526210641300

 

resultMap

在声明返回值类型为实体类型之后,实体中的属性必须和查询语句中的属性对应上,但是我们在开发的过程中也难免会遇到无法对应的情况。比如说我们在进行数据库设计的时候,多个单词往往是用_连接,但是在实体类中的属性往往采用小驼峰的方式命名。这就导致字段名无法对应上,这个时候我们就需要配置resultMap来解决这个问题了

<resultMap id="userResult" type="User">
    <id column="id" property="id" />
    <result property="nickname" column="nickname" />
    <result property="schoolName" column="school_name" />
</resultMap>

动态SQL

if

<!-- 示例 -->
<select id="find" resultType="student" parameterType="student">
        SELECT * FROM student WHERE age >= 18
        <if test="name != null and name != ''">
            AND name like '%${name}%'
        </if>
</select>

choose

<!-- choose 和 when , otherwise 是配套标签 
类似于java中的switch,只会选中满足条件的一个
-->
<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>

where

<where>标签只会在至少有一个子元素返回了SQL语句时,才会向SQL语句中添加WHERE,并且如果WHERE之后是以AND或OR开头,会自动将其删掉

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

foreach

<select id="batchFind" resultType="student" parameterType="list">
        SELECT * FROM student WHERE id in
        <foreach collection="list" item="item" open="(" separator="," close=")">
          #{item}
        </foreach>
</select>

set

 <update id="updateNickname">
        update t_user
        <set>
            <if test="nickname != null and nickname != ''">
                nickname = #{nickname},
            </if>
            <if test="username != null and username != ''">
                username = #{username},
            </if>
        </set>
        where id = #{id}
    </update>

缓存

一级缓存

默认开启,同一个SqlSesion级别共享的缓存,在一个SqlSession的生命周期内,执行2次相同的SQL查询,则第二次SQL查询会直接取缓存的数据,而不走数据库,当然,若第一次和第二次相同的SQL查询之间,执行了DML(INSERT/UPDATE/DELETE),则一级缓存会被清空,第二次查询相同SQL仍然会走数据库
 

一级缓存在下面情况会被清除

  1. 在同一个SqlSession下执行增删改操作时(不必提交),会清除一级缓存
  2. SqlSession提交或关闭时(关闭时会自动提交),会清除一级缓存
  3. 对mapper.xml中的某个CRUD标签,设置属性flushCache=true,这样会导致该MappedStatement的一级缓存,二级缓存都失效(一个CRUD标签在mybatis中会被封装成一个MappedStatement)
  4. 在全局配置文件中设置 <setting name="localCacheScope" value="STATEMENT"/>,这样会使一级缓存失效,二级缓存不受影响
     

二级缓存

默认关闭,可通过全局配置文件中的<settings name="cacheEnabled" value="true"/>开启二级缓存总开关,然后在某个具体的mapper.xml中增加<cache />,即开启了该mapper.xml的二级缓存。二级缓存是mapper级别的缓存,粒度比一级缓存大,多个SqlSession可以共享同一个mapper的二级缓存。注意开启二级缓存后,SqlSession需要提交,查询的数据才会被刷新到二级缓存当中

总结

  • 在使用二级缓存的时候,需要注意配置mybatis-config.xml中 开启二级缓存

  • <setting name="cacheEnabled" value="true"/>

  • 然后再mapper映射文件中使用cache标签标注开启,并对需要换成的语句添加useCache=”true”

  • 在mapper的映射文件中使用<cache />,代表当前mapper是开启二级缓存的

  • 在需要二级缓存的查询上增加useCache = true,代表当前查询是需要缓存的

  • 并且对应封装数据的实体类需要实现Serializable 接口

  • 对待缓存的数据,实现Serialization接口,代表这个数据是可序列化

  • 只有当sqlSession close之后,二级缓存才能生效

  • 当执行增删改操作的时候,必须执行commit()才能持久化到数据库中,同时二级缓存清空

  • session.clearCache()无法清除二级缓存,如果需要清除二级缓存,可以通过sqlSessionFactory.getConfiguration().getCache("缓存id").clear();

  • 但是当我们查询语句中,执行commit() 或者是close()关闭session,都不会清空二级缓存

关联查询

1-1

在实现1对1映射的时候,可以通过association属性进行设置。在这里有三种方式

1.使用select

<resultMap id="address" type="Address">
        <id column="id" property="id" />
        <association property="user" column="user_id" javaType="User" select="com.tledu.erp.dao.IUser2Dao.selectById"/>
</resultMap>

2. 直接进行联查,在association中配置映射字段

    <resultMap id="address" type="Address" autoMapping="true">
        <id column="id" property="id" />
        <association property="user" column="user_id" javaType="User" >
              <id column="user_id" property="id" />
            <result column="school_name" property="schoolName" />
        </association>
    </resultMap>

    <select id="selectOne" resultMap="address">
        select * from t_address left join t_user tu on tu.id = t_address.user_id where t_address.id = #{id}
    </select>

autoMapping代表自动封装,如果不填写,则需要添加所有的对应关系。

这种方式的问题是,当association需要被多次引用的时候,就需要进行多次重复的配置,所以我们还有第三种方式,引用resultMap。 

3.嵌套的resultType

<resultMap id="addressMap" type="Address" autoMapping="true">
        <id column="id" property="id"/>
        <association property="user" column="user_id" resultMap="userMap">
        </association>
    </resultMap>

    <resultMap id="userMap" type="User" autoMapping="true">
        <id column="user_id" property="id" />
        <result column="school_name" property="schoolName"/>
    </resultMap>

    <select id="selectOne" resultMap="addressMap">
        select t_address.id,
               addr,
               phone,
               postcode,
               user_id,
               username,
               password,
               nickname,
               age,
               sex,
               school_name
        from t_address
                 left join t_user tu on tu.id = t_address.user_id
        where t_address.id = #{id}
    </select>

1-多

也是三种

 <resultMap id="userResult" type="User" autoMapping="true">
        <id column="id" property="id"/>
        <result property="nickname" column="nickname"/>
        <result property="schoolName" column="school_name"/>
        <collection property="addressList" column="phone" ofType="Address" autoMapping="true">
            <id column="address_id" property="id" />
        </collection>
    </resultMap>


    <select id="selectById" parameterType="int" resultMap="userResult">
        select tu.id,
               username,
               password,
               nickname,
               age,
               sex,
               school_name,
               ta.id as address_id,
               addr,
               phone,
               postcode,
               user_id
        from t_user tu
                 left join t_address ta on tu.id = ta.user_id
        where tu.id = #{id}
    </select>
<resultMap id="userResult" type="User" autoMapping="true">
        <!--        <id column="id" property="id"/>-->
        <result property="nickname" column="nickname"/>
        <result property="schoolName" column="school_name"/>
        <collection property="addressList" column="phone" ofType="Address" resultMap="addressResultMap" autoMapping="true">
        </collection>
    </resultMap>

    <resultMap id="addressResultMap" type="Address" autoMapping="true">
        <id column="address_id" property="id" />
    </resultMap>


    <select id="selectById" parameterType="int" resultMap="userResult">
        select tu.id,
               username,
               password,
               nickname,
               age,
               sex,
               school_name,
               ta.id as address_id,
               addr,
               phone,
               postcode,
               user_id
        from t_user tu
                 left join t_address ta on tu.id = ta.user_id
        where tu.id = #{id}
    </select>

       

延迟加载

延迟加载:

就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.

延迟加载是结合关联查询进行应用的。也就是说,只在<association><collection> 标签上起作用

好处:

先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

坏处:

因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。

配置

 <settings>
        <setting name="logImpl" value="LOG4J"/>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
<!-- StudentMapper.xml -->
<resultMap id="studentExt" type="com.yogurt.po.StudentExt">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="score" column="score"/>
        <result property="age" column="age"/>
        <result property="gender" column="gender"/>
		<!-- 当延迟加载总开关开启时,resultMap下的association和collection标签中,若通过select属性指定嵌套查询的SQL,则其fetchType默认是lazy的,当在延迟加载总开关开启时,需要对个别的关联查询禁用延迟加载时,才有必要配置fetchType = eager -->
    	<!--
 		column用于指定用于关联查询的列
		property用于指定要封装到StudentExt中的哪个属性
		javaType用于指定关联查询得到的对象
		select用于指定关联查询时,调用的是哪一个DQL
		-->
        <association property="clazz" javaType="com.yogurt.po.Clazz" column="class_id"
                     select="com.yogurt.mapper.ClassMapper.findById" fetchType="lazy"/>

    </resultMap>

    <select id="findLazy" parameterType="string" resultMap="studentExt">
        SELECT * FROM student WHERE name like '%${value}%';
    </select>

事务

事务的隔离级别

  • 脏读
  • 幻读
  • 不可重复读

脏读 

脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问 这个数据,然后使用了这个数据。

不可重复读

是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。

幻读

是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。 同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象 发生了幻觉一样。

事务隔离

脏读

不可重复读

幻读

说明

Read uncommitted

直译就是"读未提交",意思就是即使一个更新语句没有提交,但是别 的事务可以读到这个改变.这是很不安全的。允许任务读取数据库中未提交的数据更改,也称为脏读。

Read committed

×

直译就是"读提交",可防止脏读,意思就是语句提交以后即执行了COMMIT以后,别的事务才能读到这个改变. 只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 

Repeatable read

×

×

直译就是"可以重复读",这是说在同一个事务里面先后执行同一个查询语句的时候,得到的结果是一样的.在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读。

Serializable

×

×

×

直译就是"序列化",意思是说这个事务执行的时候不允许别的事务并发执行. 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞

分页

插件分页

1.添加依赖

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

2.配置文件配置

 <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <property name="helperDialect" value="mysql"/>
        </plugin>
    </plugins>

3.代码

	@Test
	public void test() {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
		PageHelper.startPage(1,3);
		List<Product> products = mapper.selectByExample(new ProductExample());
		products.forEach(System.out::println);
	}

4.可以通过pageInfo获取分页的相关信息

@Test
public void test() {
	SqlSession sqlSession = factory.openSession();
	PageHelper.startPage(1,3);
	ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
	List<Product> list = mapper.findAll();
	list.forEach(System.out::println);
	PageInfo<Product> pageInfo = new PageInfo<>(list);
	System.out.println(pageInfo.getTotal()); // 获得总数
	System.out.println(pageInfo.getPageSize());  // 获得总页数
}

这个pageInfo 里面有很多的属性

手动分页

配置同上

1.定义一个获取分页的实体类

package com.wzx.MybatisThree.dto;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageInfos {
    private int pageNums;

    private int start;

    private int pageSizes;

    public int getIndex(){
        return (this.pageNums - 1) * this.pageSizes;
    }
}

2.映射以及接口

3.测试

 @Test
    public void getUserSomePages(){
        PageInfos pageInfos = new PageInfos();

        pageInfos.setPageSizes(3);
        pageInfos.setPageNums(1);

        int index = pageInfos.getIndex();

        List<Users> userSomePages = sqlSession.getMapper(UserPage.class).getUserSomePages(index, pageInfos.getPageSizes());

        userSomePages.stream().forEach(System.out::println);

    }

获取前三条数据

 

 

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

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

相关文章

Ubuntu20.4安装QT6

前言&#xff1a; 本教程基于Ubuntu20.4&#xff0c;在Ubuntu22.4上也测试过。Ubuntu18.04由于GCC版本太低&#xff0c;无法正常工作。 1.下载QT安装程序&#xff1a; Open Source Development | Open Source License | Qt 2.安装libxcb-xinerama(必须在执行QT安装程序前执行…

多智能体(机器人)任务分配问题求解AssignmentProblem

问题提出&#xff1a; N个智能体&#xff0c;现在有个任务&#xff0c;就是让N个智能体要到N个目标位置&#xff0c;目标位置不能重复&#xff0c;目标位置与机器人一一对应&#xff0c;要使得期间所有所走的距离之和最短&#xff0c;求解最优任务分配。 问题抽象&#xff1a; …

关联分析——apprior算法

1.txt文件的打开与关闭 2.list的操作 3.字典的创建及保存 4.txt文件的创建与写入 输入&#xff1a; 结果&#xff1a; import os#input min_sup4 max_item[] data [] transaction[]curent_transaction,current_sup[],[] result_transaction,result_sup[],[]#Storage resul…

线索二叉树操作详解(详细图例+cpp实现+源码)

文章目录线索二叉树中序线索二叉树构造线索二叉树节点的线索化其他操作销毁二叉搜索树获取中序遍历的第一个节点获取中序遍历的最后一个节点输出中序遍历序列逆序输出中序遍历序列源码线索二叉树 线索二叉树又称为二叉树的线索化。 在一个具有n个节点的二叉树中&#xff0c;它…

Linux零基础入门(一)初识Linux

Linux零基础入门&#xff08;一&#xff09;初识Linux前言操作系统概述一 操作系统概述1 硬件和软件2 操作系统二 初识Linux1 Linux的诞生2 Linux内核3 Linux发行版三 虚拟机介绍1 虚拟机四 VMware WorkStation安装1 虚拟化软件五 在VMware上安装Linux1 下载CentOS操作系统六 远…

[附源码]计算机毕业设计springboot体育馆场地预约管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

SwiftUI 如何快速识别视图(View)界面的刷新是由哪个状态的改变导致的?

功能需求 在 SwiftUI 中,我们视图的界面可能在不经意间被意外刷新了。这时,我们希望知道是该视图中的哪个状态导致了刷新。在包含众多状态的复杂视图中,这往往很难实现。 如上图所示,当我们随机改变视图中的状态时,可以在调试控制台中轻松看到是哪个状态导致了视图的刷新…

什么样的跨网数据摆渡系统,能够减少数据泄密的风险?

企业在公司正常运行下难免会产生一些重要数据或者敏感数据&#xff0c;这些都是企业在发展过程中积累下来的重要数据资产&#xff0c;对企业的发展至关重要。这些数据资产往往关联着企业的核心数据&#xff0c;一旦面临泄露&#xff0c;不仅仅会影响企业发展&#xff0c;甚至会…

词法分析(编译原理不用慌)

目录 一.简单版 二.简单版&#xff08;文本保存&#xff09; c版 运行结果&#xff1a; Java版 运行结果&#xff1a; 三.第三版&#xff08;文本保存&#xff09; c版 运行结果&#xff1a; 一.简单版 #include<stdio.h> #include<iostream> using namesp…

独立站SaaS系统站群模式怎么玩

做独立站的人都知道“站群”这个游戏&#xff0c;意思是通过建站工具一次性建好几百个或者几千个独立站。各个独立站卖的品类比较垂直&#xff0c;不会有太多SKU。销量好的站会留着精细化运营&#xff0c;没流量的就放弃。 使用脸书或谷歌和其他广告渠道来测试产品。每个产品…

Unity3d bounds包围盒 和collider碰撞器区别

Bounds 外包围盒 Bounds 叫作外包围盒、边界框、外扩矩形.是struct 结构体。而我们获得Bounds的主要途径有三种&#xff1a;Render,Collider,Mesh。 Render.bounds 世界坐标 Collider.bounds 世界坐标 Mesh.bounds 本地坐标 var m GetComponent<MeshFilter>().bound…

抖音用户浏览行为数据分析与挖掘

下文部分代码省略&#xff0c;完整项目代码及数据集链接&#xff1a;抖音用户浏览行为数据分析与挖掘 目录1.特征指标构建0. 项目介绍与说明**数据集说明**浏览行为1. 数据简单处理2. 特征指标构建用户指标分析&#xff1a;作者指标分析&#xff1a;作品指标分析&#xff1a;3.…

5分钟快速上手Nmap指令(基于Kali系统)

前言正文1、修改Kali系统中网络配置2、Nmap简介2.1 用途2.2优势2.3 相关知识3、Nmap中最常用的命令3.1 单主机扫描3.2 多目标扫描3.3 检测目标主机漏洞3.3 时序选择3.4 保存4、kali系统中常见报错参考文献前言 本篇为理论篇&#xff0c;主要为CTF攻防做铺垫&#xff0c;围绕 基…

[附源码]SSM计算机毕业设计影院售票系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

mac m1 mysqlworkbench8 Unknown table ‘COLUMN_STATISTICS‘

原因&#xff1a;本地mysql版本是8&#xff0c;远程是mariaDb-10&#xff0c;版本不匹配导致报错。 仔细看mysqlworkbench8.0导出时的错误信息&#xff0c;有mysqldump的具体路径。 mac os (m1, ventura系统)&#xff0c;具体位置是这里&#xff1a; /Applications/MySQLWor…

【树莓派开发日记1】1.3k预算的树莓派+显示屏+键鼠的选型与拆箱物理安装

树莓派开发日记1 经过了漫长的上课与考试周期&#xff0c;终于有时间闲下来进行技术栈的开发与学习 作为立志成为优秀机器人开发者的青年工程师&#xff08;青春版&#xff09;&#xff0c;不可能不去了解微机处理系统和Ubuntu系统&#xff0c;所以在此又给自己开了一个大坑 …

OpManager 帮助排查网络延迟问题

什么是网络延迟 网络中的延迟是指数据通过网络传输到其预期目的地所需的时间。它通常表示为往返延迟&#xff0c;即数据从一个位置传输到另一个位置所需的时间。 什么原因导致网络延迟 有四个主要原因会影响网络延迟。其中包括&#xff1a; 传输介质&#xff0c;例如 WAN 或…

JUC并发编程第六篇,带你了解Java内存模型JMM

JUC并发编程第六篇&#xff0c;带你了解Java内存模型JMM一、Java Memory Model&#xff08;Java内存模型&#xff09;是什么&#xff1f;二、JMM规范三大特性1. 可见性2. 原子性3. 有序性三、JMM规范下多线程对变量的读写过程四、JMM规范下多线程先行发生原则&#xff08;happe…

Oracle面试题整理

目录 Oracle面试题整理 1.MySQL和Oracle的区别&#xff1a; 2.Oracle中function和procedure的区别&#xff1f; 3. 比较truncate和delete命令 &#xff1f; 4.oralce中 rowid, rownum的定义 5. 事务的特性&#xff08;ACID&#xff09;是指什么 6. 列举几种表连接方式…

[附源码]计算机毕业设计springboot天狗电子商城系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…