springboot第15集:MyBatis分页

2023-10-08 18:20:20 浏览数 (1)

我们在测试SQL的时候,要是能够在控制台输出 SQL 的话,是不是就能够有更快的排错效率?

是的,输出 SQL 可以帮助我们更好地理解代码的执行流程和结果。在控制台输出 SQL 可以让我们看到实际执行的 SQL 语句,这样就能够更轻松地检查 SQL 查询、插入或更新语句是否正确。此外,通过输出 SQL,还可以查看实际执行过程中的参数和变量的值,从而更好地调试代码问题。因此,在测试 SQL 的时候,输出 SQL 可以帮助我们提高排错效率,并提高代码质量。

为了方便开发者进行日志记录,Mybatis内置了日志工厂。该日志工厂支持多种具体的日志实现,包括以下几种工具:

  1. SLF4J
  2. Apache Commons Logging
  3. Log4j 2
  4. Log4j
  5. JDK logging
代码语言:javascript复制
<settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

介绍一下Log4j:

Log4j是Apache开源项目之一,它提供了灵活的日志功能,可以控制日志信息的输出目的地,如控制台、文本、GUI组件等。同时,我们也可以定义每条日志信息的输出格式,并通过定义不同级别的日志来更加精细地控制日志的生成过程。最为方便的是,这些设置都可以通过一个配置文件进行灵活配置,而无需修改应用程序的代码。

代码语言:javascript复制
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

<settings>
    <setting name="logImpl" value="LOG4J"/>
</settings>

//注意导包:org.apache.log4j.Logger
static Logger logger = Logger.getLogger(MyTest.class);
@Test
public void selectUser() {
    logger.info("info:进入selectUser方法");
    logger.debug("debug:进入selectUser方法");
    logger.error("error: 进入selectUser方法");
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    List<User> users = mapper.selectUser();
    for (User user: users){
        System.out.println(user);
    }
    session.close();
}

为什么需要使用分页?

在使用持久层框架(如Mybatis)进行数据访问操作时,最常用的就是数据库的查询操作。当需要查询大量数据时,我们往往会采取分页的方式进行查询,即每次只查询一小部分数据。这样做的好处在于可以有效地减轻数据库的负担,保证系统的可靠性和稳定性。同时,通过分页操作还可以使查询结果更加清晰明了,方便用户查看相关数据。

代码语言:javascript复制
#语法
SELECT * FROM table LIMIT stratIndex,pageSize
SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15   
#为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:    
SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last.   
#如果只给定一个参数,它表示返回最大的记录行数目:    
SELECT * FROM table LIMIT 5; //检索前 5 个记录行   
#换句话说,LIMIT n 等价于 LIMIT 0,n。
代码语言:javascript复制
<select id="selectUser" parameterType="map" resultType="user">
    select * from user limit #{startIndex},#{pageSize}
</select>
代码语言:javascript复制
//选择全部用户实现分页
List<User> selectUser(Map<String,Integer> map);
代码语言:javascript复制
//分页查询 , 两个参数startIndex , pageSize
@Test
public void testSelectUser() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    int currentPage = 1;  //第几页
    int pageSize = 2;  //每页显示几个
    Map<String,Integer> map = new HashMap<String,Integer>();
    map.put("startIndex",(currentPage-1)*pageSize);
    map.put("pageSize",pageSize);
    List<User> users = mapper.selectUser(map);
    for (User user: users){
        System.out.println(user);
    }
    session.close();
}
代码语言:javascript复制
//选择全部用户RowBounds实现分页
List<User> getUserByRowBounds();
代码语言:javascript复制
<select id="getUserByRowBounds" resultType="user">
  select * from user
</select>
代码语言:javascript复制
@Test
public void testUserByRowBounds() {
   SqlSession session = MybatisUtils.getSession();
   int currentPage = 2;  //第几页
   int pageSize = 2;  //每页显示几个
   RowBounds rowBounds = new RowBounds((currentPage-1)*pageSize,pageSize);
   //通过session.**方法进行传递rowBounds,[此种方式现在已经不推荐使用了]
   List<User> users = session.selectList("com.kuang.mapper.UserMapper.getUserByRowBounds", null, rowBounds);
   for (User user: users){
       System.out.println(user);
   }
   session.close();
}

面向接口编程

  • 解耦(Decoupling):将系统各个模块之间的依赖关系降到最小,使得修改一个模块不会对其他模块产生影响。这样可以提高系统的可维护性和扩展性。
  • 可拓展(Scalable):系统应该能够支持未来的扩展和增长,而不需要进行大规模的重构。这通常需要采用标准化的技术和接口,并保持系统的松散耦合。
  • 提高复用(Reusable):将通用的模块或功能封装成可复用的组件,可以节省开发时间和成本,并且使得整个系统更易于维护。
  • 分层开发(Layered Architecture):将系统按照不同的层次分解,每个层次都有特定的职责和功能,层与层之间通过标准化的接口进行通讯。这样可以降低系统的复杂度,提高可维护性和可扩展性。
  • 上层不用管具体的实现(Abstraction):将具体的实现细节隐藏在抽象的接口后面,上层只需要知道接口的使用方法和结果,不需要了解底层的实现。这可以提高系统的灵活性和可维护性,并且降低对实现的依赖。
  • 面向对象(Object-oriented):这种开发方式将系统中的对象作为基本的构建模块,每个对象具有特定的属性和方法,并且可以相互交互。这种开发方式更加注重对象之间的关系和交互,强调封装、继承和多态等概念。
  • 面向过程(Procedure-oriented):这种开发方式以一个从头到尾的流程或者事务为单元,考虑它们的实现细节。这种开发方式更加注重任务的执行步骤和流程控制,强调顺序结构、分支结构和循环结构等概念。
  • 接口设计与非接口设计:这是针对复用技术而言的,与面向对象(过程)不是一个问题。接口设计提供了标准化的接口来实现模块之间的通讯,从而提高了代码的复用性和可维护性。而非接口设计则通过直接调用其他模块的函数或方法来实现代码的复用,但这种方式会增加模块之间的依赖性,降低系统的灵活性和可维护性。

总的来说,这些概念都是软件开发中的基础概念,对于系统的整体架构和开发方式都有很大的影响。

sql 类型主要分成 : @select () @update () @Insert () @delete ()

这是 SQL 语言中常用的四个操作类型:

  • SELECT:用于查询数据库中的数据,可以指定需要查询的表、字段、条件等信息,并返回符合要求的数据结果集。
  • UPDATE:用于更新数据库中的数据,可以修改已有记录或新增记录,并返回被更新的记录数。
  • INSERT:用于向数据库中插入新的记录,可以同时插入多条记录,并返回被插入记录的 ID 或者新增成功的记录数。
  • DELETE:用于删除数据库中的数据,可以根据指定的条件删除单条记录或多条记录,并返回被影响的记录数。

这些操作类型是 SQL 语言中最基础的操作,用于对数据库进行增删改查等操作。在实际应用中,我们可以通过组合使用这些操作类型来完成更加复杂的操作,例如多表联合查询、批量更新等。掌握这些操作类型对于开发 SQL 数据库和进行数据处理非常重要。

代码语言:javascript复制
//查询全部用户
@Select("select id,name,pwd password from user")
public List<User> getAllUser();
代码语言:javascript复制
<!--使用class绑定接口-->
<mappers>
    <mapper class="com.kuang.mapper.UserMapper"/>
</mappers>
代码语言:javascript复制
@Test
public void testGetAllUser() {
    SqlSession session = MybatisUtils.getSession();
    //本质上利用了jvm的动态代理机制
    UserMapper mapper = session.getMapper(UserMapper.class);
    List<User> users = mapper.getAllUser();
    for (User user : users){
        System.out.println(user);
    }
    session.close();
}

image.png

代码语言:javascript复制
//获取SqlSession连接
public static SqlSession getSession(){
   return getSession(true); //事务自动提交
}
public static SqlSession getSession(boolean flag){
   return sqlSessionFactory.openSession(flag);
}
代码语言:javascript复制
//根据id查询用户
@Select("select * from user where id = #{id}")
User selectUserById(@Param("id") int id);
代码语言:javascript复制
@Test
public void testSelectUserById() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    User user = mapper.selectUserById(1);
    System.out.println(user);
    session.close();
}
代码语言:javascript复制
//添加一个用户
@Insert("insert into user (id,name,pwd) values (#{id},#{name},#{pwd})")
int addUser(User user);
代码语言:javascript复制
@Test
public void testAddUser() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    User user = new User(6, "xx", "123456");
    mapper.addUser(user);
    session.close();
}
代码语言:javascript复制
//修改一个用户
@Update("update user set name=#{name},pwd=#{pwd} where id = #{id}")
int updateUser(User user);
代码语言:javascript复制
@Test
public void testUpdateUser() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    User user = new User(6, "xxxx", "3456");
    mapper.updateUser(user);
    session.close();
}
代码语言:javascript复制
//根据id删除用
@Delete("delete from user where id = #{id}")
int deleteUser(@Param("id")int id);
代码语言:javascript复制
@Test
public void testDeleteUser() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    mapper.deleteUser(6);
    session.close();
}

关于 @Param 注解的用法,主要是为方法中的参数指定一个名称,以便在 SQL 语句中引用。以下是一些使用原则:

  • 在方法只接受一个参数时,可以不使用 @Param 注解。此时,MyBatis 会将参数作为"param1"来处理。
  • 在方法接受多个参数的情况下,建议一定要使用 @Param 注解给参数命名,以避免出现混淆或错误的情况。同时,在 SQL 语句中引用参数时,也需要使用相应的名称。
  • 如果参数是 JavaBean,那么不能使用 @Param 注解进行命名。MyBatis 会自动将 JavaBean 的属性名作为参数名,并且可以通过 #{} 来引用属性值。
  • 如果不使用 @Param 注解,那么方法中只能有一个参数,并且这个参数必须是 JavaBean 类型。

总之,使用 @Param 注解可以提高代码的可读性和可维护性,特别是在方法接收多个参数的情况下。而对于 JavaBean,则不需要使用 @Param 注解,因为 MyBatis 能够自动处理 JavaBean 属性名和参数名的映射关系。

代码语言:javascript复制
public interface UserMapper {
    /**
     * 根据用户id查询用户信息
     *
     * @param userId 用户id
     * @return 查询结果
     */
    @Select("SELECT * FROM users WHERE id = #{userId}")
    User getUserById(@Param("userId") Long userId);

    /**
     * 根据用户名和密码查询用户信息
     *
     * @param username 用户名
     * @param password 密码
     * @return 查询结果
     */
    @Select("SELECT * FROM users WHERE username = #{username} AND password = #{password}")
    User getUserByUsernameAndPassword(@Param("username") String username, @Param("password") String password);

    /**
     * 插入新的用户记录
     *
     * @param user 用户对象
     * @return 影响的行数
     */
    @Insert("INSERT INTO users(username, password) VALUES(#{user.username}, #{user.password})")
    int insertUser(@Param("user") User user);

    /**
     * 更新用户信息
     *
     * @param user 用户对象
     * @return 影响的行数
     */
    @Update("UPDATE users SET password = #{user.password} WHERE id = #{user.id}")
    int updateUser(@Param("user") User user);

    /**
     * 删除用户记录
     *
     * @param userId 用户id
     * @return 影响的行数
     */
    @Delete("DELETE FROM users WHERE id = #{userId}")
    int deleteUserById(@Param("userId") Long userId);
}

在 MyBatis 中,#{}${} 是用于 SQL 语句中参数占位的两种方式。

代码语言:javascript复制
public interface UserMapper {
    /**
     * 根据用户名和密码查询用户信息
     *
     * @param username 用户名
     * @param password 密码
     * @return 查询结果
     */
    @Select("SELECT * FROM users WHERE username = #{username} AND password = #{password}")
    User getUserByUsernameAndPassword(@Param("username") String username, @Param("password") String password);

    /**
     * 动态查询用户记录
     *
     * @param condition 查询条件
     * @param orderField 排序字段
     * @param orderType 排序方式
     * @param limitStart 分页起始位置
     * @param limitSize 分页大小
     * @return 查询结果
     */
    @Select("<script>"
              "SELECT * FROM users"
              "<where>"
              "<if test='condition != null'>"
              "<![CDATA[AND (username LIKE CONCAT('%',#{condition},'%') OR email LIKE CONCAT('%',#{condition},'%'))]]>"
              "</if>"
              "</where>"
              "<if test='orderField != null and orderType != null'>"
              "<![CDATA[ORDER BY ${orderField} ${orderType}]]>"
              "</if>"
              "<if test='limitStart != null and limitSize != null'>"
              "<![CDATA[LIMIT #{limitStart},#{limitSize}]]>"
              "</if>"
              "</script>")
    List<User> listUsers(@Param("condition") String condition, @Param("orderField") String orderField, @Param("orderType") String orderType, @Param("limitStart") Integer limitStart, @Param("limitSize") Integer limitSize);
}

仓库地址:https://github.com/webVueBlog/JavaGuideInterview

0 人点赞