第一个MyBatis程序、MyBatis增删改查与配置文档、resultMap映射、log4j日志、RowBounds分页

文章目录

  • 一、MyBatis
    • 1、Mybatis阶段学习概述
      • 1、SSM---企业级开发框架
      • 2、Spring与SpringBoot联系
      • 3、前后端分离开发
    • 2、第一个MyBatis程序
      • 1、MyBatis是什么
      • 2、第一个HelloWorld程序
    • 3、CURD(增删改查)
    • 4、配置文档配置
      • 1、db.properties配置文档,不写死
      • 2、包的别名设置
      • 3、setting 配置输出日志
      • 4、用户映射配置
    • 5、映射
      • 1、结果集映射
    • 6、log4j日志使用
    • 7、分页(一定要会)
      • 1、Limit分页(SQL层面)
      • 2、RowBounds分页(Java层面)
      • 3、分页插件 - PageHelper

一、MyBatis

1、Mybatis阶段学习概述

Mybatis作用:和数据库打交道,简化数据库的操作

javaSE—>前端—>数据库—>javaWeb(已经可以独立完成项目,但是太繁琐,所以需要一些框架来简化操作,提高开发效率)

1、SSM—企业级开发框架

学习框架之后开发方式会发生变化,越来越简单

  1. MyBatis

    简化数据库操作的,帮助我们获取数据库连接、数据处理等

  2. Spring

    用来黏合框架,整合框架(Structs、MyBatis、SpringMVC等)的,可以简单的理解为一个粘合剂的作用。

    使用Spring就不需要再自己创建对象了,直接从Spring的IOC容器中取对象

  3. SpringMVC

    Web开发的三层结构,分别为实体类(一个实体类对应数据库中的一张表)、视图、控制层(类似于Servlet/Service等)

2、Spring与SpringBoot联系

Spring出现很久了,随着发展,Spring的配置越来越复杂,所以就有了SpringBoot,相较于Spring,SpringBoot中约定优于配置,简化了配置流程,可以简化开发者的使用。

3、前后端分离开发

  1. 什么是前后端分离开发

    后端仅返回前端所需的数据,前端负责渲染HTML页面,后端不再控制前端的效果,用户看到什么样的效果,从后端请求的数据如何加载到前端中,都由前端自己决定,后端仅仅需要提供一套逻辑对外提供数据即可,并且前端与后端的耦合度相对较低,在这种模式中,我们通常将后端开发的每个视图都成为一个接口,或者API,前端通过访问接口来对数据进行增删改查。

    总结一句话,后台负责提供数据,前端负责数据展示

  2. 前后端分离开发的优点

    1. 分工明确,提升效率

    2. 降低服务器负载,提升性能

      页面数及进行按需加载,前端页面也不再由服务器解析

    3. 增加代码的可维护性

      降低代码间的耦合度,有利于后期维护

前端、数据库、业务逻辑

2、第一个MyBatis程序

1、MyBatis是什么

前身:iBatis,所以在后期编写代码的时候,很多时候导的就是iBatis包

下载:在Github上进行下载,/

MyBatis优点:可以解耦、在程序运行时也可以进行管理(在配置文件里进行管理),自由切换数据库等作用

MyBatis特性

  1. 基于Java持久层(JDBC)的框架

  2. 支持定制化的SQL

  3. 支持映射

  4. 几乎避免了所有的JDBC代码和手动设置参数及获取结果集

  5. 可以使用简单的XML或注解进行配置和映射原生类型、接口和Java的POJO作为数据库对象

2、第一个HelloWorld程序

  1. 数据库准备

    创建mybatis数据库,在数据库中创建表user,键分别为id、name、pwd,将id设置为主键,设置编码集为INNODB

    /*
    创建数据库和表
    */
    CREATE DATABASE `mybatis`;USE `mybatis`;CREATE TABLE `user`(`id` INT(20) NOT NULL,`name` VARCHAR(30) DEFAULT NULL,`pwd` VARCHAR(30) DEFAULT NULL,PRIMARY KEY(`id`)
    )ENGINE=INNODB DEFAULT CHARSET=utf8;/*
    给表中填充数据
    */
    INSERT INTO `user`(`id`,`name`,`pwd`)
    VALUES (1,'张三','123456'),(2,'李四','123456'),(3,'王五','123456');
  2. 导入MyBatis和mysql依赖

    <!-- .mybatis/mybatis -->
    <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.3</version>
    </dependency>
    

    操作数据库的依赖

    <!--  -->
    <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version>
    </dependency>
    
  3. 编辑核心配置文件Mybatis.config.xml

    在resource目录下,创建Mybatis.config.xml配置文件,并进行编辑

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN"".dtd">
    <!--configuration核心配置文件-->
    <configuration><!--一个environments里面可以有多个environment标签,通过id值进行切换--><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--固定写法,驱动和URL--><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/><!--MySQL数据库账号--><property name="username" value="root"/><!--MySQL数据库密码--><property name="password" value="123456"/></dataSource></environment></environments></configuration>
  4. 编写工具类

    1. 创建utils包,在utils包下创建工具类MyBatisUtil
    2. 公开静态方法获取sqlSession的连接
    package org.westos.utils;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 java.io.IOException;
    import java.io.InputStream;//MyBatis工具类
    public class MyBatisUtil {private static SqlSessionFactory sqlSessionFactory;static {try {//因为mybatis-config.xml配置文件在resource根目录下,所以可以直接写文件名String resource = "mybatis-config.xml";//固定的写法InputStream inputStream = Resources.getResourceAsStream(resource);sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}// 获取sqlSession的连接// sqlSession中包括了面向数据库执行的SQL命令的所有方法public static SqlSession getSession() {return sqlSessionFactory.openSession();}
    }
  5. 创建实体类User,对应数据库中的表user

    实体类与数据库中的表一一对应,使用Lombok创建User类(Lombok简化开发步骤)

    导入Lombok的Maven依赖

    <!-- lombok依赖 -->
    <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version>
    </dependency>

    创建User类

    package org.westos.pojo;import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;//lombok的注解
    @Data
    //这个注解加有参构造
    @AllArgsConstructor
    //这个注解加默认无参构造
    @NoArgsConstructor
    public class User {private int id;private String name;private String pwd;
    }
  6. dao层接口编写

    创建mapper包,在mapper包中创建包含用户操作的接口类UserMapper (不用编写接口的实现类UserMapperImpl)

    package org.westos.mapper;import org.westos.pojo.User;
    import java.util.List;public interface UserMapper {//得到数据库表中的所有用户List<User> getUserList();
    }
  7. 编写UserMapper.xml文档

    UserMapper.xml文档代替原有接口的实现类UserMapperImpl,在resource目录下创建与UserMapper 接口所在包名相一致的包,在该包中创建一个和接口对应的UserMapper.xml文档。

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"".dtd"><!--一个namespace绑定一个对应的接口-->
    <mapper namespace="org.westos.mapper.UserMapper"><!--一个select标签对应原有UserMapper接口实现类的方法id属性与UserMapper接口的方法名一致resultType属性与UserMapper接口的方法返回值类型一致在select标签中写要执行的查询语句--><select id="getUserList" resultType="org.westos.pojo.User">select * from mybatis.user</select></mapper>

    使用UserMapper.xml配置文档代替原有的接口实现类的优点

    1. 可以在程序运行起来之后仍然修改程序的代码

    2. 修改的时候只需要修改配置文档即可,不用改动原有程序

  8. 将自定义的UserMapper.xml注册到配置文档Mybatis.config.xml中,进行绑定

    在UserMapper.xml中进行设置之后还需要在Mybatis.config.xml中进行映射的设置

        <!--添加用户映射配置--><mappers><mapper resource="org\westos\mapper\UserMapper.xml"/></mappers>
  9. 添加junit依赖

    <!--  -->
    <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13</version><scope>test</scope>
    </dependency>
  10. 编写测试类,测试运行

    package org.westos.test;import org.apache.ibatis.session.SqlSession;
    import org.westos.mapper.UserMapper;
    import org.westos.pojo.User;
    import org.westos.utils.MyBatisUtil;import java.util.List;public class MyBatisTest {public static void main(String[] args) {//1、使用工具类获取SqlSession(执行sql使用)SqlSession session = MyBatisUtil.getSession();//2、通过session获得接口对象,可以调用接口的方法UserMapper mapper = session.getMapper(UserMapper.class);//3、调用接口的getUserList()方法,得到数据库表中的所有user记录List<User> userList = mapper.getUserList();//4、循环打印for (User user : userList) {System.out.println(user);}}
    }

3、CURD(增删改查)

所有的增删改操作都要提交事务,session.commit();

完成MyBatis配置后,新增接口的固定操作

  1. 编写接口
  2. 在接口对应的接口名.xml中进行配置
  3. 保证id与接口方法名一致
  4. 进行测试

练习:

  1. select

    通过ID查询user表中记录

    通过用户名和密码查询user表中记录

    当接口中的方法有多个参数时,要在每个参数前加注解@Param(“变量名”)

  2. insert

    给表中插入一条记录

    如果参数是对象,可以在配置文档中使用#{属性}的方式直接获得对象的属性

    所有的增删改操作都要使用事务

  3. update

    根据id更新用户的账号和密码

  4. delete

    根据id删除用户记录

UserMapper接口及测试类

//UserMapper接口
package org.westos.mapper;import org.apache.ibatis.annotations.Param;
import org.westos.pojo.User;
import java.util.List;public interface UserMapper {List<User> getUserList();//使用ID得到用户User getUserById(int id);//使用账号密码得到用户信息User getUserByUnamePwd(@Param("username") String username, @Param("password") String password);//添加用户int  addUser(User user);//修改用户int updateUser(User user);//删除用户int  deleteUserById(int id);
}//测试类
package org.westos.test;import org.apache.ibatis.session.SqlSession;
import org.westos.mapper.UserMapper;
import org.westos.pojo.User;
import org.westos.utils.MyBatisUtil;public class MyBatisExercise {public static void main(String[] args) {SqlSession session = MyBatisUtil.getSession();UserMapper mapper = session.getMapper(UserMapper.class);/*根据ID获得对象User user = mapper.getUserById(1);System.out.println(user);*//*根据账号密码得到对象System.out.println(mapper.getUserByUnamePwd("张三", "123456"));*//*添加用户mapper.addUser(new User(5, "李四", "123456"));session.commit();*//*根据ID删除用户mapper.deleteUserById(2);session.commit();*//*更新记录mapper.updateUser(new User(3, "张三", "123456"));session.commit();*/}
}

UserMapper.xml配置文档

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"".dtd"><mapper namespace="org.westos.mapper.UserMapper"><!--查询数据库user表中所有的记录--><select id="getUserList" resultType="org.westos.pojo.User">select * from user;</select><!--根据ID查询表中记录,resultType是设置返回值类型的--><select id="getUserById" resultType="org.westos.pojo.User">select * from user where `id`=#{id}</select><!--根据账号和密码查询表中记录--><select id="getUserByUnamePwd" resultType="org.westos.pojo.User">select * from user where `name`=#{username}and `pwd`=#{password}</select><!--插入记录,parameterType是设置参数类型的--><insert id="addUser" parameterType="org.westos.pojo.User">INSERT INTO `user`(`id`,`name`,`pwd`) VALUES (#{id},#{name},#{pwd})</insert><!--根据ID更新记录--><update id="updateUser" parameterType="org.westos.pojo.User">UPDATE `user` SET `name` = #{name},`pwd`=#{pwd} WHERE `id` = #{id}</update><!--根据ID删除记录--><delete id="deleteUserById" parameterType="int">DELETE FROM `user` WHERE `id` = #{id}</delete></mapper>
  1. 注意事项

    1. 多个参数使用注解@Param("参数名称")
    2. 增删改要增加事务session.commit();
    3. 增删改放的xml标签中参数类型parameterType一定要写
    4. 增删改不用写返回值,查询要写返回值,

4、配置文档配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BvaTKxc4-1582124870348)(assets/1582094567251.png)]

  1. environments标签

    内部可以有多个environment子元素,多套配置,只需要更换default属性的值就行

  2. transactionManager

    事务管理器,默认是JDBC

  3. dataSource

    数据源配置,默认使用池化技术POOLED

  4. mappers

    映射器,有三种配置方法

    1. class:接口对应的类的路径,前提是配置文档和接口的包名称相同

    2. package:可以扫描具体的包中所有的接口,开发中多使用

    3. resource:对应的资源路径

  5. 配置文件中标签不可以乱放,元素的位置是有顺序要求的

1、db.properties配置文档,不写死

  1. 在resource目录下创建db.properties文件

    将数据库的配置信息放在里面

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mybatis? useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8
    username=root
    password=123
    
  2. 使用properties标签引入db.properties文件,<property name="" value=""/>标签的value值可以使用${属性名}来引用db.properties文件。

    <!--配置db.properties文件,资源从db.properties文件中获得,更灵活-->
    <properties resource="db.properties"/><!--使用${}符号动态取出数据库的配置参数-->
    <property name="driver" value="${driver}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>

2、包的别名设置

设置了以后在接口名r.xml文档中进行配置就不用再写类的全路径了,可以直接使用别名

    <!--别名设置,简化开发--><typeAliases><!-- type指的是原来的包名,而alias指的是新的别名--><typeAlias type="org.westos.pojo.User" alias="User"/></typeAliases>

3、setting 配置输出日志

可以看到具体的SQL执行信息,检查错误

<!--日志输出,可以显示执行的日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

4、用户映射配置

可以修改扫描设置为一个包下的所有接口配置文件,就不用一一导入了

<!--添加用户映射配置-->
<mappers><!--<mapper resource="org\westos\mapper\UserMapper.xml"/>--><!--修改扫描设置为包的设置,扫描mapper包下的所有的配置文件--><package name="org.westos.mapper"/>
</mappers>

5、映射

1、结果集映射

resultMap:做结果映射,对数据库字段和实体类属性进行映射

有时候我们会遇到数据库中表的字段名和对应实体类的属性名不一致的情况,这样子就会导致数据库中的某些字段查询不出来

解决方案

  1. 手动将SQL补全,使用as起别名

    <select id="getUserList" resultType="User"><!--select * from user;-->select id,name,pwd as password from user<!--完整的将SQL的字段写出来,将名称不一样的字段使用AS起别名不推荐使用,比较繁琐,每次查询都要写一遍-->
    </select>
  2. 使用resultMap,一劳永逸

    <!--
    当调用getUserList方法的时候,就会先去找别名为UserMap的标签,然后使用该标签中修改过后的属性去查找
    数据库和实体表名称一样的属性可以删掉不写,只写不一样的映射
    -->    
    <select id="getUserList" resultMap="UserMap">select * from user
    </select><resultMap id="UserMap" type="User"><result column="pwd" property="password"/><result column="id" property="id"/><result column="name" property="name"/>
    </resultMap>

6、log4j日志使用

为什么使用日志

为了便于排查错误,日志会将程序的运行过程都打印在控制台,也可以生成在日志文件中

MyBatis默认日志
默认是STDOUT_LOGGING,但在实际的开发中更多的使用Log4j

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

Log4j日志配置步骤

  1. Log4j依赖导入
<!--  -->
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
  1. 在resource目录下导入Log4j.properties配置文件

    ### 设置###
    log4j.rootLogger = debug,stdout,D,E### 输出信息到控制抬 ###
    log4j.appender.stdout = org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target = System.out
    log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n### 输出DEBUG 级别以上的日志到=./log/logs/error.log ###
    log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
    log4j.appender.D.File = ./log/log.log
    log4j.appender.D.Append = true
    log4j.appender.D.Threshold = DEBUG
    log4j.appender.D.layout = org.apache.log4j.PatternLayout
    log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n### 输出ERROR 级别以上的日志到=./log/logs/error.log ###
    log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
    log4j.appender.E.File =./log/error.log
    log4j.appender.E.Append = true
    log4j.appender.E.Threshold = ERROR
    log4j.appender.E.layout = org.apache.log4j.PatternLayout
    
  2. 将默认的配置日志换成Log4j,注意必须是全部大写,没有空格

    <!--日志输出设置为Log4j-->
    <settings><setting name="logImpl" value="LOG4J"/>
    </settings>
  3. Log4j使用

    获得Logger对象logger,用来输出

    1. logger.error();错误信息

    2. logger.info();提示信息

    3. logger.debug();调试信息

    可以将日志实现细粒度的控制,将错误信息输出到log日志中

练习:使用Log4j打印错误信息到log日志中

package org.westos.test;import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.westos.mapper.UserMapper;
import org.westos.utils.MyBatisUtil;public class Log4jTest {static Logger logger = Logger.getLogger(Log4jTest.class);public static void main(String[] args) {SqlSession session = MyBatisUtil.getSession();UserMapper mapper = session.getMapper(UserMapper.class);logger.error("错误信息");logger.info("提示信息");logger.debug("调试信息");System.out.println(mapper.getUserList());}
}

7、分页(一定要会)

为什么使用分页

提高服务器性能,网站响应的时候不希望一次性将所有的数据都刷新出去,而是一部分一部分刷新。分页有利于服务器资源的节约

当参数过多的时候,可以使用Map集合进行传递参数,使用键值对得到值

接口名.xml配置文档中配置非基本类型参数时,需要使用parameterType属性来显示的定义

1、Limit分页(SQL层面)

在ResultMapper中创建带分页操作的方法

  1. 在接口中定义方法getUsersByLimit()

  2. 在xml配置文档中配置

        <select resultType="User" parameterType="Map" id="getUsersByLimit">select * from user limit #{startIndex},#{pageSize}</select>
  3. 测试类

    package org.westos.test;import org.apache.ibatis.session.SqlSession;
    import org.westos.mapper.ResultMapper;
    import org.westos.pojo.User;
    import org.westos.utils.MyBatisUtil;import java.util.HashMap;
    import java.util.List;public class ResultMapTest {public static void main(String[] args) {SqlSession session = MyBatisUtil.getSession();ResultMapper mapper = session.getMapper(ResultMapper.class);int currentPage = 2; //当前页面int pageSize = 3;    //每页显示几条记录//创建HashMap,存放页面信息HashMap<String, Integer> map = new HashMap<String, Integer>();//计算开始索引map.put("startIndex",(currentPage-1)*pageSize);//页面大小map.put("pageSize",pageSize);//调用方法得到分页查询得到的用户记录List<User> users = mapper.getUsersByLimit(map);//打印System.out.println(users);}
    }

2、RowBounds分页(Java层面)

其实底层也是使用limit实现的

  1. 接口中定义方法

    List<User> selectUserByLimit();
  2. xml配置

    <!-- 非基本类型之外的数据类型,List,Map,需要显示的定义 -->
    <select id="selectUserByLimit" parameterType="map" resultMap="UserMap">select * from user;
    </select>
  3. 测试类

    package org.westos.test;import org.apache.ibatis.session.RowBounds;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.log4j.Logger;
    import org.westos.pojo.User;
    import org.westos.utils.MyBatisUtil;import java.util.List;public class RowBoundsTest {//导入org.apache.log4j.Logger包static Logger logger = Logger.getLogger(RowBoundsTest.class);public static void main(String[] args) {SqlSession session = MyBatisUtil.getSession();int currentPage = 1; //当前页int pageSize = 3;    //每页显示几个//展示的页面信息RowBounds rowBounds = new RowBounds((currentPage-1)*pageSize,pageSize);// selectList(方法的路径)//不使用对象,直接调用方法List<User> users = session.selectList("org.westos.mapper.ResultMapper.selectUserByLimit", null, rowBounds);for (User user : users) {System.out.println(user);}}
    }
  4. 可以使用selectXXX执行具体的某个方法,得到结果,通过这个方法,实现Java分页

3、分页插件 - PageHelper

使用分页插件PageHelper也可以通过插件实现分页,但是底层也是通过limit实现的