Loading

Mybatis学习

Mybatis学习

1. 简介

1.1 什么是Mybatis

  • MyBatis 是一款优秀的持久层框架
  • 它支持自定义 SQL、存储过程以及高级映射
  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集
  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
  • 现迁移到GitHub

1.2 如何获取Mybatis

1.3 持久化

1.3.1 数据持久化

  • 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
  • 内存:断电即失
  • 数据库(jdbc),io文件持久化
  • 生活结合:冰箱冷藏

1.3.2 为什么需要持久化?

  • 有一些对象,不能让他丢掉
  • 内存太贵

1.4 持久层

Dao层,Service层,Controller层…

  • 完成持久化工作的代码块
  • 层是界限十分明显的

1.5 为什么需要MyBatis

  • 帮助程序员将数据存入到数据库中
  • 方便
  • 传统的jdbc代码太复杂了,简化代码,形成框架。----自动化
  • 不使用MyBatis也可以,更容易上手
  • 优点:
    • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件。易于学习,易于使用。通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
    • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
    • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
    • 提供映射标签,支持对象与数据库的orm字段关系映射。
    • 提供对象关系映射标签,支持对象关系组建维护。
    • 提供xml标签,支持编写动态sql。

2. 第一个Mybatis程序

思路:搭建环境—>导入Mybatis—>编写代码---->测试

2.1 搭建环境

  • 搭建数据库

    create table if not exists `user`(
    	`id` int(20) not null auto_increment comment '编号',
    	`name` varchar(30) default null comment '用户名',
    	`pwd` varchar(30) default null comment '密码',
    	primary key(`id`)
    )engine=innodb default charset='utf8'
    
    insert into `user`(`id`,`name`,`pwd`)
    values (1,'leez','123456'),
    (2,'小白','123123'),
    (2,'张三','123123')
    
  • 新建项目

    mybatis-1

  • 删除src目录

  • 导入maven依赖

    <!--导入依赖-->
    <dependencies>
        <!--MySQL驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!--Mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    

2.2 创建子模块

  • 编写Mybatis核心配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-config.dtd">
    <!--configuration核心配置文件-->
    <configuration>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <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&amp;serverTimezone=GMT"/>
                    <property name="username" value="root"/>
                    <property name="password" value=""/>
                </dataSource>
            </environment>
        </environments>
        <!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-->
        <mappers>
            <mapper resource="com/LEEZ/dao/UserMapper.xml"/>
        </mappers>
    </configuration>
    
  • 编写Mybatis工具类

    public class MybatisUtil {
    
        private static SqlSessionFactory sqlSessionFactory;
    
        static{
            //获取Mybatis第一步
            //获取SqlSessionFactory
            try {
                String resource = "mybatis-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static SqlSession getSqlSession() {
            return sqlSessionFactory.openSession();
        }
    }
    

2.3 编写代码

  • 实体类

    package com.LEEZ.pojo;
    
    public class User {
        private int id;
        private String name;
        private String pwd;
    
        public User() {
        }
    
        public User(int id, String name, String pwd) {
            this.id = id;
            this.name = name;
            this.pwd = pwd;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPwd() {
            return pwd;
        }
    
        public void setPwd(String pwd) {
            this.pwd = pwd;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", pwd='" + pwd + '\'' +
                    '}';
        }
    }
    
  • Dao接口

    public interface UserDao {
        public List<User> getUserList();
    }
    
  • 接口实现类,由原来的UserDaoImpl转换为Mapper.xml文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!--namespace绑定一个对应的dao/mapper接口-->
    <mapper namespace="com.LEEZ.dao.UserDao">
        <!--id对应方法名字-->
        <select id="getUserList" resultType="com.LEEZ.pojo.User">
            select * from mybatis.user where id = #{id}
        </select>
    </mapper>
    

2.4 测试

注意点:

org.apache.ibatis.binding.BindingException: Type interface com.LEEZ.dao.UserMapper is not known to the MapperRegistry.

  • 核心配置文件中注册UserMapper.xml

    <!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-->
    <mappers>
        <mapper resource="com/LEEZ/dao/UserMapper.xml"/>
    </mappers>
    
  • Junit测试,测试代码

    @Test
    public void test() {
        SqlSession sqlSession = null;
        try {
            //获取sqlSession对象
            sqlSession = MybatisUtil.getSqlSession();
            //执行sql
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List<User> userList = userMapper.getUserList();
            for (User user: userList) {
                System.out.println(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }
    

3. CRUD

增删改查

3.1 namespace

namespace中的包名要和接口中的包名一致—uesrDao–>userMapper

3.2 select

选择查询语句:

  • id就是对应的namespace中的方法名
  • resultType就是Sql语句执行的返回值
  • parameterType就是参数类型

3.3 Insert

3.4 update

3.5 delete

  1. 编写接口

    public interface UserMapper {
        //获取全部用户
        List<User> getUserList();
    
        //根据用户id查询用户
        User getUserById(int id);
    
        //增加一个用户
        int addUser(User user);
    
        //修改一个用户
        int updateUser(User user);
    
        //删除一个用户
        int deleteUser(int id);
    }
    
  2. 编写对应Mapper中的sql语句

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!--namespace绑定一个对应的dao/mapper接口-->
    <mapper namespace="com.LEEZ.dao.UserMapper">
        <!--id对应方法名字-->
        <select id="getUserList" resultType="com.LEEZ.pojo.User">
            select * from mybatis.user
        </select>
    
        <select id="getUserById" parameterType="int" resultType="com.LEEZ.pojo.User">
            select * from user where id = #{id}
        </select>
    
        <insert id="addUser" parameterType="com.LEEZ.pojo.User">
            insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
        </insert>
    
        <update id="updateUser" parameterType="com.LEEZ.pojo.User">
            update user set name = #{name},pwd = #{pwd} where id = #{id}
        </update>
    
        <delete id="deleteUser" parameterType="int">
            delete from user where id = #{id}
        </delete>
    </mapper>
    
  3. 测试

    @Test
    public void test() {
        SqlSession sqlSession = null;
        try {
            //获取sqlSession对象
            sqlSession = MybatisUtil.getSqlSession();
            //执行sql
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List<User> userList = userMapper.getUserList();
            for (User user : userList) {
                System.out.println(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }
    
    @Test
    public void testGetUserById() {
        SqlSession sqlSession = null;
        try {
            //获取sqlSession对象
            sqlSession = MybatisUtil.getSqlSession();
            //执行sql
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            User userById = userMapper.getUserById(1);
            System.out.println(userById);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }
    
    @Test
    public void testAddUser() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        int i = userMapper.addUser(new User(3, "李四", "111111"));
        System.out.println(i);
        //增删改需要提交事务
        sqlSession.commit();
        sqlSession.close();
    }
    
    @Test
    public void testUpdateUser(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.updateUser(new User(3, "张三", "111111"));
        System.out.println(i);
        sqlSession.commit();
        sqlSession.close();
    }
    
    @Test
    public void testDeleteUser() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.deleteUser(3);
        System.out.println(i);
        sqlSession.commit();
        sqlSession.close();
    }
    

    注意:增删改查需要提交事务

3.6 万能的map方法

假设我们的实体类,或者数据库中的表,字段或者参数过多,我们应当考虑使用Map!

//万能的map
int  addUser2(Map<String,Object> map);

<!--传递map的key-->
    <insert id="addUser" parameterType="map" >
    insert into mybatis.user(id,name,pwd) values (#{userid},#{userName},#{passWord});
</insert>

@Test
public  void addUser2(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    HashMap<String, Object> map = new HashMap<>();
    map.put("userid",5);
    map.put("userName","hello");
    map.put("passWord","976543");

    mapper.addUser2(map);

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

}
  • Map传递参数,直接在sql中取出key即可!
  • 对象传递参数,直接在sql中去对象的属性即可!
  • 只有一个基本类型参数的情况下,可以直接在sql中取到!
  • 多个参数用Map,或者注解

3.7 模糊查询

  1. java代码执行的时候,传递通配符%%

    List<User> userList = mapper.getUserLike("%李%");
    
  2. 在sql拼接中使用通配符

    select * from user where name like "%"#{value}"%"
    

4. 配置解析

4.1 核心配置文件

mybatis-config.xml

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

4.2、环境配置(environments)

  • MyBatis 可以配置成适应多种环境

  • 不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

  • 数据源的配置(比如:type=“POOLED”)

  • 学会配置多套运行环境-----更改id

    <environments default="id">
    
  • Mybatis默认的事务管理器就是JDBC,连接池:POOLED

4.3、属性(properties)

我们可以通过properties属性来实现引用配置文件

这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置【db.properties】

mybatis-2

编写一个配置文件db.properties:

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

在核心配置文件中引入

<!--引入外部配置文件-->
<properties resource="db.properties"/>

4.4 类型别名(typeAliases)

  • 类型别名可为 Java 类型设置一个缩写名字

  • 用于 XML 配置,意在降低冗余的全限定类名书写

    <!--可以给实体类起别名-->
    <typeAliases>
        <typeAlias type="com.LEEZ.pojo.User" alias="User"/>
    </typeAliases>
    
  • 也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:

    扫描实体类的包,它的默认别名就为这个类的类名,首字母小写

    <!--可以给实体类器别名-->
    <typeAliases>
        <package name="com.LEEZ.pojo"/>
    </typeAliases>
    
  • 在实体类比较少的时候,使用第一种方式;如果实体类十分多,建议使用第二种(在实体类中使用注解可以起别名)

4.5 设置

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。

mybatis-3

mybatis-4

一个配置完整的 settings 元素的示例如下:

<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

4.6 其他配置

4.7 映射器(mappers)

MapperRegistry:注册绑定我们的Mapper文件,每写一个dao层就要写一个Mapper文件

  1. 方式一:建议使用

    <!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-->
    <mappers>
        <mapper resource="com/LEEZ/dao/UserMapper.xml"/>
    </mappers>
    
  2. 方式二:使用class文件绑定注册

    <!-- 使用映射器接口实现类的完全限定类名 -->
    <mappers>
    	<mapper class="com.LEEZ.dao.UserMapper"/>
    </mappers>
    

    注意:

    • 接口和他的Mapper配置文件必须同名
    • 接口和他的Mapper配置文件必须在同一个包下
  3. 方式三:使用扫描包进行绑定注册

    <mappers>
    	<package name="com.LEEZ.dao"/>
    </mappers>
    

    注意:

    • 接口和他的Mapper配置文件必须同名
    • 接口和他的Mapper配置文件必须在同一个包下

4.8 生命周期和作用域

生命周期和作用域是至关重要的,因为错误的使用会导致非常严重的并发问题

mybatis-5

SqlSessionFactoryBuilder

  • 一旦创建了 SqlSessionFactory,就不再需要SqlSessionFactoryBuilder了
  • 局部变量

SqlSessionFactory:

  • 可以理解为数据库连接池
  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例
  • SqlSessionFactory 的最佳作用域是应用作用域,最简单的就是使用单例模式或者静态单例模式

SqlSession:

  • 连接到连接池的一个请求
  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域
  • 用完之后需要赶紧关闭,否则资源被占用

mybatis-6

这里每一个Mapper就代表一个具体的业务

5. 解决属性名和字段名不一致的问题

5.1 问题

数据库中的字段

mybatis-7

新建一个项目,拷贝之前的,测试实体类字段不一样的情况

public class User {
    private int id;
    private String name;
    private String password;
}

测试出现问题

mybatis-8

问题原因

select * from mybatis.user where id =#{id}
select id,name,pwd from mybatis.user where id =#{id}
//此时已经没有pwd

解决方法

  • 起别名

    <select id="getUserById" parameterType="int" resultType="User">
        select id,name,pwd as password from mybatis.user where id =#{id}
    </select>
    

5.2 resultMap

结果集映射

id name pwd
id name password

<!--结果集映射-->
<resultMap id="UserMap" type="User">
    <!--column对应数据库的列,property对应实体类的属性-->
    <result column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="pwd" property="password"/>
</resultMap>

<select id="getUserById" parameterType="int" resultMap="UserMap">
    select * from user where id =#{id}
</select>
  • resultMap 元素是 MyBatis 中最重要最强大的元素
  • ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了

6. 日志

6.1 日志工厂

如果一个数据库操作出现了异常,我们需要排错,日志就是最好的助手

之前: sout,debug

现在:日志工厂

mybatis-9

  • SLF4J
  • LOG4J(3.5.9 起废弃) ----- 掌握
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING ----- 掌握
  • NO_LOGGING

在Mybatis中具体使用哪一个日志实现,在设置中设定

STDOUT_LOGGING — 标准日志输出

在mybatis核心配置文件中,配置我们的日志

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

mybatis-10

6.2 LOG4J

什么是log4j

  • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
  • 我们也可以控制每一条日志的输出格式
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程
  • 通过一个配置文件来灵活地进行配置,而不需要修改应用的代码
  1. 先导入log4j的包

    <!-- https://mvnrepository.com/artifact/log4j/log4j -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    
  2. log4j.properties

    ### 配置根 ###
    log4j.rootLogger = debug,console,file
    
    ### 配置输出到控制台 ###
    log4j.appender.console = org.apache.log4j.ConsoleAppender
    log4j.appender.console.Target = System.out
    log4j.appender.console.Threshold = debug 
    log4j.appender.console.layout = org.apache.log4j.PatternLayout
    log4j.appender.console.layout.ConversionPattern =  %d{ABSOLUTE} %5p %c{1}:%L - %m%n
    
    ### 配置输出到文件 ###
    log4j.appender.file = org.apache.log4j.FileAppender
    log4j.appender.file.File = ./log/qjd.log
    
    log4j.appender.file.Append = true
    log4j.appender.file.Threshold = debug
    
    log4j.appender.file.layout = org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
    
    ### 配置输出到文件,并且每天都创建一个文件 ###
    log4j.appender.dailyRollingFile = org.apache.log4j.DailyRollingFileAppender
    log4j.appender.dailyRollingFile.File = logs/log.log
    log4j.appender.dailyRollingFile.Append = true
    log4j.appender.dailyRollingFile.Threshold = debug
    log4j.appender.dailyRollingFile.layout = org.apache.log4j.PatternLayout
    log4j.appender.dailyRollingFile.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
    
    ### 设置输出sql的级别,其中logger后面的内容全部为jar包中所包含的包名 ###
    log4j.logger.org.mybatis=debug
    log4j.logger.java.sql=debug
    log4j.logger.java.sql.Connection=debug
    log4j.logger.java.sql.Statement=debug
    log4j.logger.java.sql.PreparedStatement=debug
    log4j.logger.java.sql.ResultSet=debug
    

3.配置log4j为日志的实现

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

4.Log4j的使用,直接运行刚才的测试

mybatis-11

简单使用

  1. 在要使用Log4j的类中,导入包import org.apache.log4j.Logger;

  2. 日志对象,参数为当前类的class

    static  Logger logger = Logger.getLogger(UserMapperTest.class);
    1
    
  3. 日志级别

    logger.info("info:进入了testLog4j");
    logger.debug("debug:进入了testLog4j");
    logger.error("error:进入了testLog4j");
    

7. 分页

思考:为什么要分页?

  • 减少数据的处理量

7.1 使用Limit分页

SELECT * FROM user limit startIndex,pageSize;
SELECT * FROM user limit 0,2;
SELECT * FROM user limit 3;#[0,n]

使用Mybatis实现分页,核心就是sql

  1. 接口

    //分页
    List<User> getUserListByLimit(Map<String, Integer> map);
    
  2. UserMapper.xml

    <!--分页-->
    <select id="getUserListByLimit" parameterType="map" resultMap="UserMap">
        select * from user limit #{startPage},#{pageSize}
    </select>
    
  3. 测试

    @Test
    public void testLimit() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
        Map<String, Integer> map = new HashMap<>();
        map.put("startPage", 2);
        map.put("pageSize", 3);
    
        List<User> userList = mapper.getUserListByLimit(map);
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }
    

7.2 RowBounds分页(不建议使用)

RowBounds分页了解,不建议使用

不再使用sql实现分页

  1. 接口

    //分页2
    List<User> getUserByRowBounds();
    
  2. Mapper.xml

    <!--    分页2-->
    <select id="getUserByRowBounds"  resultMap="UserMap">
        select * from mybatis.user
    </select>
    
  3. 测试

    @Test
    public void getUserByRowBounds(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //RowBounds实现
        RowBounds rowBounds = new RowBounds(1, 2);
    
    
        //通过java代码层面实现分页
        List<User> userList = sqlSession.selectList("com.qjd.dao.UserMapper.getUserByRowBounds",null,rowBounds);
        for (User user : userList) {
            System.out.println(user);
        }
    
        sqlSession.close();
    }
    

7.3 分页插件

MyBatis 分页插件 PageHelper

如何使用----https://pagehelper.github.io/docs/howtouse/

8. 使用注解开发

8.1 面向接口编程

一、概念

  1. 什么是面向接口编程

    ​ 面向接口编程就是先把客户的业务逻辑线提取出来,作为接口,业务具体实现通过该接口的实现类来完成。当客户需求变化时,只需编写该业务逻辑的新的实现类,通过更改配置文件(例如Spring框架)中该接口的实现类就可以完成需求,不需要改写现有代码,减少对系统的影响。

  2. 面向接口编程的优点

    1. 降低程序的耦合性。其能够最大限度的解耦,所谓解耦既是解耦合的意思,它和耦合相对。耦合就是联系,耦合越强,联系越紧密。在程序中紧密的联系并不是一件好的事情,因为两种事物之间联系越紧密,你更换其中之一的难度就越大,扩展功能debug的难度也就越大。
    2. 易于程序的扩展;
    3. 有利于程序的维护;
  3. 接口编程在设计模式中的体现:开闭原则
    其遵循的思想是:

    ​ 对扩展开放,对修改关闭。其恰恰就是遵循的是使用接口来实现。在使用面向接口的编程过程中,将具体逻辑与实现分开,减少了各个类之间的相互依赖,当各个类变化时,不需要对已经编写的系统进行改动,添加新的实现类就可以了,不在担心新改动的类对系统的其他模块造成影响。

二、设计模式

面向过程编程

面向对象编程

面向接口编程

  1. 面向过程编程

    ​ 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。面向过程是一种以过程为中心的编程思想。面向过程是一种最为实际的思考方式,就算是面向对象的方法也有面向过程的思想。可以说面向过程是一种基础的方法。它考虑的是实际的实现。一般面向过程是从上往下步步求精,所以面向过程最重要的是模块化的思想方法。

  2. 面向对象编程

    ​ 面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

    • 对象:对象是要研究的任何事物。比如人类就是一个对象,然而对象是有属性和方法的,那么身高、体重、年龄、性别等等,这些是每个人都有的特征可以概括为属性。
    • 类:类是对象的模板。即类是对一组有相同属性和相同操作的对象的定义,一个类所包含的方法和数据描述一组对象的共同属性和行为。类是在对象之上的抽象,对象则是类的具体化,是类的实例。
    • 面向对象的基本特征 封装、继承、多态
      • 封装:就是把属性私有化,提供公共方法访问私有对象。
      • 继承:当多个类具有相同的特征(属性)和行为(方法)时,可以将相同的部分抽取出来放到一个类中作为父类,其他类继承于这个父类。继承后的子类自动拥有了父类的属性和方法,比如猫、狗、猪他们共同的特征都是动物、都会跑会叫等特征。但是需要注意的是,父类的私有属性(private)和构造方法不能被继承。另外子类可以写自己特有的属性和方法,目的是实现功能的扩展,子类也可以重写父类的方法。
      • 多态:简单来说就是“一种定义,多种实现”。同一类事物表现出多种形态。JAVA语言中有方法重载和对象多态两种形式的多态。
        • 方法重载:在一个类中,允许多个方法使用同一个名字,但是方法的参数不同,完成的功能也不同
        • 对象多态:子类对象可以与父类对象进行相互转换,而且根据其使用的子类的不同,完成的功能也不同
  3. 面向接口编程

    • 什么叫面向接口编程
      • 在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。
    • 关于接口的理解
      • 接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。
      • 接口的本身反映了系统设计人员对系统的抽象理解。
      • 接口应有两类:
        • 第一类是对一个体的抽象,它可对应为一个抽象体(abstract class);
        • 第二类是对一个体某一方面的抽象,即形成一个抽象面(interface);
        • 一个体有可能有多个抽象面。抽象体与抽象面是有区别的。

面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法
面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现
接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题

8.2 使用注解开发

  1. 注解在接口上实现

    public interface UserMapper {
        //使用注解
        @Select("select * from user")
        List<User> getUsers();
    }
    
  2. 需要在核心配置文件中绑定接口

    <!--绑定接口-->
    <mappers>
        <mapper class="com.LEEZ.dao.UserMapper"/>
    </mappers>
    
  3. 测试

    @Test
    public void test() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.getUsers();
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }
    

本质:反射机制实现

底层:动态代理

mybatis-12

8.3 Mybatis详细执行流程

具体实现:

mybatis-13

8.4 注解CRUD

我们可以在工具类中设置事务自动提交

public static SqlSession getSqlSession() {
    //return sqlSessionFactory.openSession();
    //openSession()有重载,可以设置自动提交事务
    return sqlSessionFactory.openSession(true);
}

CRUD接口

//基本数据类型(框架中Spring也属于基本数据类型)必须有@Param,若有多个参数则写多个@Param,其他数据类型不用写
@Select("select * from user where id = #{id}")
User getUserById(@Param("id") int id);

@Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password})")
int addUser(User user);

@Update("update user set name = #{name},pwd = #{password} where id = #{id}")
int updateUser(User user);

@Delete("delete from user where id = #{id}")
int deleteUser(@Param("id") int id);

测试类

@Test
public void testGetUserById() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    mapper.getUserById(1);
    sqlSession.close();
}

@Test
public void testAddUser() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = new User(7, "小蜜蜂", "123123");

    mapper.addUser(user);
    sqlSession.close();
}

@Test
public void testUpdateUser() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = new User(7, "捞蜂", "123123");

    mapper.updateUser(user);
    sqlSession.close();
}

@Test
public void testDeleteUser() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    mapper.deleteUser(7);
    sqlSession.close();
}

注意:我们必须要将接口注册绑定到我们的核心配置文件中

8.5 关于 @Param(“”) 注解

  • 基本类型的参数或者String需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型的话,可以忽略,但是建议大家都加上
  • 我们在sql中引用的就是我们这里的@Param(“”)中设定的属性名

8.6 #{} 和 ${}

1、#{}是预编译处理,${}是字符串替换

2、mybatis在处理两个字符时,处理的方式也是不同的:

(1)处理#{}时,会将sql中的#{}整体替换为占位符(即:?),调用PreparedStatement的set方法来赋值;
​ (2)在处理 ${ } 时,就是把 ${ } 替换成变量的值。

3、假如用${}来编写SQL会出现:恶意SQL注入,对于数据库的数据安全性就没办法保证了

4、使用 #{} 可以有效的防止SQL注入,提高系统安全性:

预编译的机制。预编译是提前对SQL语句进行预编译,而后再调用SQL,注入的参数就不会再进行SQL编译。而SQL注入是发生在编译的过程中,因为恶意注入了某些特殊字符,最后被编译时SQL时轻而易举的通过,从而导致数据泄露。而预编译机制则可以很好的防止SQL注入。

9. Lombok

Lombok项目是一个Java库,他是一个插件,它会自动插入编辑器和构建工具中,Lombok提供了一组有用的注释,用来消除Java类中的大量样板代码。仅五个字符(@Data)就可以替换数百行代码从而产生干净,简洁且易于维护的Java类。

使用步骤:

  1. 在IDEA中安装Lombok插件

  2. 在项目中导入Lombok的jar包

    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>
    
  3. 在实体类上加注解即可

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private int id;
        private String name;
        private String password;
    }
    

Lombok所有注解

@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass

说明:

@Data:无参构造,get,set,toString,hashcode,equals
@AllArgsConstructor
@NoArgsConstructor
@Getter and @Setter
@ToString

10. 多对一处理

多对一:

  • 多个学生对应一个老师
  • 对于学生而言,关联···多个学生关联一个老师【多对一】
  • 对于老师而言,集合···一个老师有很多学生【一对多】

结果映射(resultMap)

association

– 一个复杂类型的关联;许多结果将包装成这种类型

嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用

collection

– 一个复杂类型的集合

嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用

SQL

新建学生表和教师表

CREATE TABLE `teacher` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师'); 

CREATE TABLE `student` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  `tid` INT(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fktid` (`tid`),
  CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

10.1 测试环境搭建

  1. 在pom.xml导入lombok(不需要自己添加构造方法等-----用@Data)

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
    </dependencies>
    
  2. 在pojo包下新建实体类Teacher,Student

    @Data
    public class Teacher {
        private int id;
        private String name;
    }
    
    @Data
    public class Student {
        private int id;
        private String name;
        //学生需要关联一个老师
        private Teacher teacher;
    }
    
  3. 建立Mapper接口

    public interface TeacherMapper {
        @Select("select *from teacher where id=#{tid}")
        Teacher getTeacher(@Param("tid") int id);
    }
    
    public interface StudentMapper {
    
    }
    
  4. 建立Mapper.xml文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!--configuration核心配置文件-->
    <mapper namespace="com.LEEZ.dao.TeacherMapper">
    </mapper>
    
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!--configuration核心配置文件-->
    <mapper namespace="com.LEEZ.dao.StudentMapper">
    </mapper>
    
  5. 在核心配置文件中绑定注册我们的Mapper接口或者文件【有很多方式】

    <!--绑定接口-->
    <mappers>
        <mapper class="com.LEEZ.dao.StudentMapper"/>
        <mapper class="com.LEEZ.dao.TeacherMapper"/>
    </mappers>
    
  6. 测试查询是否能够成功

    @Test
    public void testGetTeacher() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher(1);
        System.out.println(teacher);
        sqlSession.close();
    }
    

10.2 按照查询嵌套处理

实现以下sql语句

select  s.id ,s.name ,t.name from student s,teacher t  where s.tid=t.id
<!--思路-->
<!--首先先获取所有的学生信息-->
<!--然后通过tid获取到对应的老师信息-->
<!--获取到的学生信息中,teacher为null,因此要用结果集映射-->
<select id="getStudentList" resultMap="StudentTeacher">
    select * from student
</select>

<resultMap id="StudentTeacher" type="Student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <!--复杂的属性我们需要单独处理-->
	<!--对象:association-->
	<!--集合:collection -->
    <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>

<select id="getTeacher" resultType="Teacher">
    select * from teacher where id = #{tid}
</select>

结果

mybatis-14

10.3 按照结果嵌套处理

<!--方式二-->
<!--按照结果嵌套处理-->
<select id="getStudentList2" resultMap="StudentTeacher2">
    select s.id sid,s.name sname,t.id tid, t.name tname
    from student s,teacher t
    where s.tid=t.id
</select>

<resultMap id="StudentTeacher2" type="Student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="teacher" javaType="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
    </association>
</resultMap>

11. 一对多处理

比如:一个老师教多个学生,对于老师而言,就是一对多的关系

11.1 环境搭建,大体同10.1

实体类:

@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}
@Data
public class Teacher {
    private int id;
    private String name;
    //一个老师拥有多个学生
    private List<Student> studentList;
}

11.2、按照结果嵌套处理

<!--按结果嵌套查询-->
<select id="getTeacherById" resultMap="TeacherStudents">
    select t.id tid,t.name tname,s.id sid,s.name sname
    from teacher t, student s
    where t.id = s.tid and t.id = #{tid}
</select>
<resultMap id="TeacherStudents" type="Teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <!--复杂的属性我们需要单独处理-->
    <!--对象:association-->
    <!-- 集合:collection -->
    <!--javaType=""指定属性的类型 集合中的泛型信息,我们使用ofType获取-->
    <collection property="studentList" ofType="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>

11.3、按照查询嵌套处理

<select id="getTeacherById2" resultMap="TeacherStudents2">
    select * from teacher where id = #{tid}
</select>

<resultMap id="TeacherStudents2" type="Teacher">
    <collection property="studentList" column="id" ofType="Student" select="getStudentsByTeacherId"/>
</resultMap>

<select id="getStudentsByTeacherId" resultType="Student">
    select * from student where tid = #{tid}
</select>

11.4 小结

  1. 关联-association 【多对一】

  2. 集合-collection 【一对多】

  3. javaType & ofType

    1. 1javaType用来指定实体类中属性的类型

      3.2ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

注意点:

  • 保证SQL的可读性,尽量保证通俗易懂
  • 注意一对多和多对一中,属性名和字段的问题
  • 如果问题不好排查错误,可以使用日志,建议使用log4j

12. 动态SQL

什么是动态SQL:动态SQL就是根据不同的条件生成不同的SQL语句

使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

12.1 搭建环境

CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8

创建一个基础工程

  1. 导包

  2. 编写配置文件

  3. 编写实体类

    @Data
    public class Blog {
        private int id;
        private String title;
        private String author;
        private Date create_Time;
        private int views;
    }
    
  4. 编写实体类对应的Mapper接口和Mapper.xml文件

    public interface BlogMapper {
        int addBook(Blog blog);
    }
    
    <insert id="addBook" parameterType="Blog">
        insert into blog(id,title,author,create_time,views) values(#{id},#{title},#{author},#{create_time},#{views})
    </insert>
    
  5. 测试

    @Test
    public void test() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    
        Blog blog = new Blog();
        blog.setId(IdUtil.getUUid());
        blog.setTitle("mybatis学习");
        blog.setAuthor("LEEZ");
        blog.setCreate_time(new Date());
        blog.setViews(9999);
        mapper.addBook(blog);
    
        blog.setId(IdUtil.getUUid());
        blog.setTitle("javaweb学习");
        mapper.addBook(blog);
    
        blog.setId(IdUtil.getUUid());
        blog.setTitle("javase学习");
        mapper.addBook(blog);
    
        blog.setId(IdUtil.getUUid());
        blog.setTitle("mysql学习");
        mapper.addBook(blog);
        sqlSession.close();
    }
    

12.2 IF

<select id="queryBlogByIf" parameterType="map" resultType="Blog">
    select * from blog
    <where>
        <if test="title != null">
            title like "%"#{title}"%"
        </if>
        <if test="author != null">
            and author like "%"#{author}"%"
        </if>
    </where>
</select>

12.3 choose、when、otherwise

<select id="queryBlogByChoose" parameterType="map" resultType="Blog">
    select * from blog
    <where>
        <choose>
            <when test="title != null">
                title like "%"#{title}"%"
            </when>
            <when test="author != null">
                author like "%"#{author}"%"
            </when>
            <otherwise>
                views = #{views}
            </otherwise>
        </choose>
    </where>
</select>

12.4 trim、where、set

where:where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除

<select id="queryBlogIF" parameterType="map" resultType="blog">
    select *from mybatis.blog 
    <where>
        <if test="title != null">
            title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </where>
</select>

set:set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)

<update id="updateBlog" parameterType="map">
    update blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author},
        </if>
    </set>
    where id = #{id}
</update>

trim:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容

这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。

或者,你可以通过使用trim元素来达到同样的效果:

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

注意,我们覆盖了后缀值设置,并且自定义了前缀值

所谓动态SQL,本质还是SQL语句,只是我们可以在SQL层面去执行一个逻辑代码

12.5 SQL片段

有的时候,我们可能会将一些功能的部分抽取出来,方便复用

  1. 使用sql标签抽取公共部分

    <sql id="if-title-author">
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author},
        </if>
    </sql>
    
  2. 在需要使用的地方使用include标签引用即可

    <update id="updateBlog" parameterType="map">
        update blog
        <set>
            <include refid="if-title-author"></include>
        </set>
        where id = #{id}
    </update>
    

注意事项:

  • 最好基于单表来定义sql片段
  • 不要在1中存在where标签

12.6 foreach

​ 动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  <where>
    <foreach item="item" index="index" collection="list"
        open="ID in (" separator="," close=")" nullable="true">
          #{item}
    </foreach>
  </where>
</select>

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!

提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

具体实现:

mybatis-15

<select id="queryBlogin123" resultType="Blog">
    select * from blog
    <where>
        <foreach collection="list" item="ids"
                 open="id in (" separator="," close=")">
            #{ids}
        </foreach>
    </where>
</select>
@Test
public void testForEach() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

    ArrayList ids = new ArrayList();
    ids.add("1");
    ids.add("2");
    ids.add("3");

    List<Blog> blogs = mapper.queryBlogin123(ids);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }
    sqlSession.close();
}

mybatis-16

小结:

动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了

建议:

  • 先在Mysql中写出完整的SQL再对应去修改成为我们的动态SQL实现通用即可
  • Mysql重点掌握的知识
    • Mysql引擎
    • InnoDB底层原理
    • 索引
    • 索引优化

13. 缓存

13.1 简介

13.1.1 什么是缓存【Cache】

  • 存在内存中的临时数据
  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用了从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题

13.1.2 为什么使用缓存?

  • 减少和数据库的交互次数,较少系统开销,提高系统效率

13.1.3 什么样的数据能使用缓存?

  • 经常查询而且不经常改变的数据

13.2 Mybatis缓存

  • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。

  • MyBatis系统中默认定义了两级缓存:

    一级缓存

    二级缓存

    • 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
    • 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

13.3 一级缓存

  • 一级缓存也叫本地缓存:
  • 与数据库同一次会话期间查询到的数据会放在本地缓存中。
  • 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;

测试步骤

  1. 开启日志

  2. 测试在Session中查询两次相同的记录

    @Test
    public void test() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user1 = mapper.getUserById(1);
        System.out.println(user1);
    
        System.out.println("===========================");
    
        User user2 = mapper.getUserById(1);
        System.out.println(user2);
    
        System.out.println("user1 == user2?  ---> "+ (user1 == user2));
        sqlSession.close();
    }
    
  3. 查看日志输出

    mybatis-17

    • 虽然调用了两次mapper.getUserById(),但sql语句只执行了一次,并且两次得到的对象是同一个对象。说明查询一次之后得到的结果放进了缓存中,第二次查询时,直接从缓存中提取结果,因此两次的对象是同一个。

  • 缓存失效
    1. 查询不同的东西
    2. 增删改操作,可能会改变原来的数据,所以必定会刷新缓存!
    3. 查询不同的Mapper.xml
    4. 手动清理缓存!

小结:一级缓存默认是开启的,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段(相当于一个用户不断查询相同的数据,比如不断刷新),一级缓存就是一个map

13.4、二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存:
  • 工作机制
    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中:
    • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
    • 新的会话查询信息,就可以从二级缓存中获取内容:
    • 不同的mapper查出的数据会放在自己对应的缓存(map)中;

步骤

  1. 核心配置文件中开启全局缓存(settings)

    <!--显式的开启全局缓存-->
    <setting name="cacheEnable" value="true"/>
    
  2. 在要使用二级缓存的Mapper中开启

    • 可以不加参数

      <cache/>
      
    • 也可以自定义参数

      <!--在当前Mapper.xml中使用二级缓存-->
      <cache  eviction="FIFO"
             flushInterval="60000"
             size="512"
             readOnly="true"/>
      
  3. 测试

    @Test
    public void test() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user1 = mapper.getUserById(1);
        System.out.println(user1);
        System.out.println("===========================");
        sqlSession.close();
    
        SqlSession sqlSession2 = MybatisUtil.getSqlSession();
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        User user2 = mapper2.getUserById(1);
        System.out.println(user2);
        System.out.println("user1 == user2?  ---> "+ (user1 == user2));
        sqlSession2.close();
    }
    
  4. 结果

    mybatis-18

    • 可以看到只执行了一次sql,第二次查询时直接从二级缓存中得到查询结果,但两次结果的对象不一致,原因是:返回的是一个缓存对象的拷贝,一级缓存内容存到了二级缓存中所以内存地址变化,对比为false。序列化是深拷贝,所以反序列化后的对像和原对象不是同一个对象,故哈希值不同

问题:

  1. 我们需要将实体类序列化(实现Serializable接口),否则就会报错

    Cause: java.io.NotSerializableException: com.LEEZ.pojo.User
    

小结

  • 只要开启了二级缓存,在同一个Mapper下就有效

  • 所有的数据都会先放在一级缓存中

  • 只有当会话提交,或者关闭的时候才会提交到二级缓存中

13.5 缓存原理

缓存顺序:

  1. 先看二级缓存中有没有
  2. 再看一级缓存中有没有
  3. 查询数据库

注:一二级缓存都没有,查询数据库,查询后将数据放入一级缓存

mybatis-19

13.6 自定义缓存—ehcache

介绍:

  • EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider
  • Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存

要在程序中使用ehcache,先要导包

<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.1.0</version>
</dependency>
12345

在mapper中指定使用我们的ehcache缓存实现

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
1

这部分关于缓存的内容了解就可以,以后开发我们会用Redis数据库来做缓存!

14. 练习:29到练习题实战!

14.1 环境搭建

  • 实体类

    • Bill

      @Data
      public class Bill {
          private Integer id;                 //id
          private String billCode;            //账单编码
          private String productName;         //商品名称
          private String productDesc;         //商品描述
          private String productUnit;         //商品单位
          private BigDecimal productCount;    //商品数量
          private BigDecimal totalPrice;      //商品总额
          private Integer isPayment;          //是否支付(1:未支付 2:已支付)
          private Integer createdBy;          //创建者(userId)
          private Date creationDate;          //创建时间
          private Integer modifyBy;           //更新者(userId)
          private Date modifyDate;            //更新时间
          private Integer providerId;         //供应商ID
          private String providerName;        //供应商名称
      }
      
    • Provider

      @Data
      public class Provider {
          private Integer id;         //id
          private String proCode;     //供应商编码
          private String proName;     //供应商名称
          private String proDesc;     //供应商详细描述
          private String proContact;  //供应商联系人
          private String proPhone;    //联系电话
          private String proAddress;  //地址
          private String proFax;      //传真
          private Integer createdBy;  //创建者(userId)
          private Date creationDate;  //创建时间
          private Date modifyDate;    //更新时间
          private Integer modifyBy;   //更新者(userId)
      }
      
    • Role

      @Data
      public class Role {
          private Integer id;         //id
          private String roleCode;    //角色编码
          private String roleName;    //角色名称
          private Integer createdBy;  //创建者
          private Date creationDate;  //创建时间
          private Integer modifyBy;   //修改者
          private Date modifyDate;    //修改时间
      }
      
    • User

      public class User {
          private Integer id;             //id
          private String userCode;        //用户编码
          private String userName;        //用户名称
          private String userPassword;    //用户密码
          private Integer gender;         //性别(1:女、 2:男)
          private Date birthday;          //出生日期
          private String phone;           //手机
          private String address;         //地址
          private Integer userRole;       //用户角色(取自角色表-角色id)
          private Integer createdBy;      //创建者(userId)
          private Date creationDate;      //创建时间
          private Integer modifyBy;       //更新者(userId)
          private Date modifyDate;        //更新时间
      
          private Integer age;            //年龄
          private String userRoleName;    //用户角色名称
      
          public User(String userCode, String userName, String userPassword, Integer gender, Date birthday, String phone, String address, Integer userRole, Integer createdBy, Date creationDate) {
              this.userCode = userCode;
              this.userName = userName;
              this.userPassword = userPassword;
              this.gender = gender;
              this.birthday = birthday;
              this.phone = phone;
              this.address = address;
              this.userRole = userRole;
              this.createdBy = createdBy;
              this.creationDate = creationDate;
          }
      
          public User() {
          }
      
          public Integer getId() {
              return id;
          }
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getUserCode() {
              return userCode;
          }
          public void setUserCode(String userCode) {
              this.userCode = userCode;
          }
      
          public String getUserName() {
              return userName;
          }
          public void setUserName(String userName) {
              this.userName = userName;
          }
      
          public String getUserPassword() {
              return userPassword;
          }
          public void setUserPassword(String userPassword) {
              this.userPassword = userPassword;
          }
      
          public Integer getGender() {
              return gender;
          }
          public void setGender(Integer gender) {
              this.gender = gender;
          }
      
          public Date getBirthday() {
              return birthday;
          }
          public void setBirthday(Date birthday) {
              this.birthday = birthday;
          }
      
          public String getPhone() {
              return phone;
          }
          public void setPhone(String phone) {
              this.phone = phone;
          }
      
          public String getAddress() {
              return address;
          }
          public void setAddress(String address) {
              this.address = address;
          }
      
          public Integer getUserRole() {
              return userRole;
          }
          public void setUserRole(Integer userRole) {
              this.userRole = userRole;
          }
      
          public Integer getCreatedBy() {
              return createdBy;
          }
          public void setCreatedBy(Integer createdBy) {
              this.createdBy = createdBy;
          }
      
          public Date getCreationDate() {
              return creationDate;
          }
          public void setCreationDate(Date creationDate) {
              this.creationDate = creationDate;
          }
      
          public Integer getModifyBy() {
              return modifyBy;
          }
          public void setModifyBy(Integer modifyBy) {
              this.modifyBy = modifyBy;
          }
      
          public Date getModifyDate() {
              return modifyDate;
          }
          public void setModifyDate(Date modifyDate) {
              this.modifyDate = modifyDate;
          }
      
          public String getUserRoleName() {
              return userRoleName;
          }
          public void setUserRoleName(String userRoleName) {
              this.userRoleName = userRoleName;
          }
      
          public Integer getAge() {
              return this.age;
          }
      
          public User(Integer id, String userName, Integer gender, Date birthday, String phone, String address, Integer userRole, Integer modifyBy, Date modifyDate) {
              this.id = id;
              this.userName = userName;
              this.gender = gender;
              this.birthday = birthday;
              this.phone = phone;
              this.address = address;
              this.userRole = userRole;
              this.modifyBy = modifyBy;
              this.modifyDate = modifyDate;
          }
      
          public void setAge() {
              Date date = new Date();
              this.age = date.getYear() - birthday.getYear();
          }
      }
      
  • Dao接口

    • BillMapper

      public interface BillMapper {
          //根据供应商ID查询订单数量
          public int getBillCountByProviderId(@Param("providerId") Integer providerId) throws Exception;
      
          //增加订单
          public int add(Bill bill) throws Exception;
      
          //通过查询条件获取供应商列表-getBillList
          public List<Bill> getBillList(@Param("productName") String productName, @Param("providerId") Integer providerId, @Param("isPayment") Integer isPayment,
                                        @Param("from") Integer currentPageNo, @Param("pageSize") Integer pageSize) throws Exception;
      
          //通过条件查询-订单表记录数
          public int getBillCount(@Param("productName") String productName, @Param("providerId") Integer providerId, @Param("isPayment") Integer isPayment) throws Exception;
      
          //通过delId删除Bill
          public int deleteBillById(@Param("id") Integer delId) throws Exception;
      
          //通过billId获取Bill
          public Bill getBillById(@Param("id") Integer id) throws Exception;
      
          //修改订单信息
          public int modify(Bill bill) throws Exception;
      
          //根据供应商ID删除订单信息
          public int deleteBillByProviderId(@Param("providerId") Integer providerId) throws Exception;
      }
      
    • ProviderMapper

      public interface ProviderMapper {
          //增加用户信息
          public int add(Provider provider) throws Exception;
      
          //通过条件查询-providerList
          public List<Provider> getProviderList(@Param("proName") String proName, @Param("proCode") String proCode,
                                                @Param("from") Integer currentPageNo, @Param("pageSize") Integer pageSize) throws Exception;
      
          //获取供应商列表
          public List<Provider> getProList() throws Exception;
      
          //通过条件查询-供应商表记录数
          public int getProviderCount(@Param("proName") String proName, @Param("proCode") String proCode) throws Exception;
      
          //通过供应商id删除供应商信息
          public int deleteProviderById(@Param("id") Integer delId) throws Exception;
      
          //根据provider id 获取供应商信息
          public Provider getProviderById(@Param("id") Integer id) throws Exception;
      
          //修改供应商
          public int modify(Provider provider) throws Exception;
      }
      
    • RoleMapper

      public interface RoleMapper {
          //获取角色列表
          public List<Role> getRoleList() throws Exception;
      
          //增加角色信息
          public int add(Role role) throws Exception;
      
          //通过Id删除role
          public int deleteRoleById(@Param("id") Integer delId) throws Exception;
      
          //修改角色信息
          public int modify(Role role) throws Exception;
      
          //通过id获取role
          public Role getRoleById(@Param("id") Integer id) throws Exception;
      
          //根据roleCode,进行角色编码的唯一性验证
          public int roleCodeIsExist(@Param("roleCode") String roleCode) throws Exception;
      }
      
    • UserMapper

      public interface UserMapper {
          //通过userCode获取User
          public User getLoginUser(@Param("userCode") String userCode) throws Exception;
      
          //增加用户信息
          public int add(User user) throws Exception;
      
          //通过条件查询-userList
          public List<User> getUserList(@Param("userName") String userName, @Param("userRole") Integer userRole,
                                        @Param("from") Integer currentPageNo, @Param("pageSize") Integer pageSize) throws Exception;
      
          //通过条件查询-用户表记录数
          public int getUserCount(@Param("userName") String userName, @Param("userRole") Integer userRole) throws Exception;
      
          //通过userId删除user
          public int deleteUserById(@Param("id") Integer delId) throws Exception;
      
          //通过userId获取user
          public User getUserById(@Param("id") Integer id) throws Exception;
      
          //修改用户信息
          public int modify(User user) throws Exception;
      
          //修改当前用户密码
          public int updatePwd(@Param("id") Integer id, @Param("userPassword") String pwd) throws Exception;
      }
      
  • Mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-config.dtd">
    <!--configuration核心配置文件-->
    <configuration>
        <!--引入外部配置文件-->
        <properties resource="db.properties"/>
    
        <settings>
            <setting name="logImpl" value="STDOUT_LOGGING"/>
            <setting name="cacheEnabled" value="true"/>
        </settings>
    
        <!--可以给实体类起别名-->
        <typeAliases>
            <typeAlias type="com.LEEZ.pojo.User" alias="User"/>
            <typeAlias type="com.LEEZ.pojo.Role" alias="Role"/>
            <typeAlias type="com.LEEZ.pojo.Provider" alias="Provider"/>
            <typeAlias type="com.LEEZ.pojo.Bill" alias="Bill"/>
        </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 class="com.LEEZ.dao.UserMapper"/>
            <mapper class="com.LEEZ.dao.ProviderMapper"/>
            <mapper class="com.LEEZ.dao.RoleMapper"/>
            <mapper class="com.LEEZ.dao.BillMapper"/>
        </mappers>
    </configuration>
    
  • db.properties

    driver = com.mysql.jdbc.Driver
    url = jdbc:mysql://localhost:3306/smbms?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT
    username = root
    password =
    
  • smbms数据库初始化

    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for smbms_address
    -- ----------------------------
    DROP TABLE IF EXISTS `smbms_address`;
    CREATE TABLE `smbms_address` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
      `contact` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '联系人姓名',
      `addressDesc` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '收货地址明细',
      `postCode` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '邮编',
      `tel` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '联系人电话',
      `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者',
      `creationDate` datetime DEFAULT NULL COMMENT '创建时间',
      `modifyBy` bigint(20) DEFAULT NULL COMMENT '修改者',
      `modifyDate` datetime DEFAULT NULL COMMENT '修改时间',
      `userId` bigint(20) DEFAULT NULL COMMENT '用户ID',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    
    -- ----------------------------
    -- Records of smbms_address
    -- ----------------------------
    INSERT INTO `smbms_address` VALUES ('1', '王丽', '北京市东城区东交民巷44号', '100010', '13678789999', '1', '2016-04-13 00:00:00', null, null, '1');
    INSERT INTO `smbms_address` VALUES ('2', '张红丽', '北京市海淀区丹棱街3号', '100000', '18567672312', '1', '2016-04-13 00:00:00', null, null, '1');
    INSERT INTO `smbms_address` VALUES ('3', '任志强', '北京市东城区美术馆后街23号', '100021', '13387906742', '1', '2016-04-13 00:00:00', null, null, '1');
    INSERT INTO `smbms_address` VALUES ('4', '曹颖', '北京市朝阳区朝阳门南大街14号', '100053', '13568902323', '1', '2016-04-13 00:00:00', null, null, '2');
    INSERT INTO `smbms_address` VALUES ('5', '李慧', '北京市西城区三里河路南三巷3号', '100032', '18032356666', '1', '2016-04-13 00:00:00', null, null, '3');
    INSERT INTO `smbms_address` VALUES ('6', '王国强', '北京市顺义区高丽营镇金马工业区18号', '100061', '13787882222', '1', '2016-04-13 00:00:00', null, null, '3');
    
    -- ----------------------------
    -- Table structure for smbms_bill
    -- ----------------------------
    DROP TABLE IF EXISTS `smbms_bill`;
    CREATE TABLE `smbms_bill` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
      `billCode` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '账单编码',
      `productName` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '商品名称',
      `productDesc` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '商品描述',
      `productUnit` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '商品单位',
      `productCount` decimal(20,2) DEFAULT NULL COMMENT '商品数量',
      `totalPrice` decimal(20,2) DEFAULT NULL COMMENT '商品总额',
      `isPayment` int(10) DEFAULT NULL COMMENT '是否支付(1:未支付 2:已支付)',
      `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者(userId)',
      `creationDate` datetime DEFAULT NULL COMMENT '创建时间',
      `modifyBy` bigint(20) DEFAULT NULL COMMENT '更新者(userId)',
      `modifyDate` datetime DEFAULT NULL COMMENT '更新时间',
      `providerId` int(20) DEFAULT NULL COMMENT '供应商ID',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    
    -- ----------------------------
    -- Records of smbms_bill
    -- ----------------------------
    INSERT INTO `smbms_bill` VALUES ('1', 'BILL2016_001', '洗发水、护发素', '日用品-洗发、护发', '瓶', '500.00', '25000.00', '2', '1', '2014-12-14 13:02:03', '15', '2019-04-16 21:43:12', '13');
    INSERT INTO `smbms_bill` VALUES ('2', 'BILL2016_002', '香皂、肥皂、药皂', '日用品-皂类', '块', '1000.00', '10000.00', '2', '1', '2016-03-23 04:20:40', null, null, '13');
    INSERT INTO `smbms_bill` VALUES ('3', 'BILL2016_003', '大豆油', '食品-食用油', '斤', '300.00', '5890.00', '2', '1', '2014-12-14 13:02:03', null, null, '6');
    INSERT INTO `smbms_bill` VALUES ('4', 'BILL2016_004', '橄榄油', '食品-进口食用油', '斤', '200.00', '9800.00', '2', '1', '2013-10-10 03:12:13', null, null, '7');
    INSERT INTO `smbms_bill` VALUES ('5', 'BILL2016_005', '洗洁精', '日用品-厨房清洁', '瓶', '500.00', '7000.00', '2', '1', '2014-12-14 13:02:03', null, null, '9');
    INSERT INTO `smbms_bill` VALUES ('6', 'BILL2016_006', '美国大杏仁', '食品-坚果', '袋', '300.00', '5000.00', '2', '1', '2016-04-14 06:08:09', null, null, '4');
    INSERT INTO `smbms_bill` VALUES ('7', 'BILL2016_007', '沐浴液、精油', '日用品-沐浴类', '瓶', '500.00', '23000.00', '1', '1', '2016-07-22 10:10:22', null, null, '14');
    INSERT INTO `smbms_bill` VALUES ('8', 'BILL2016_008', '不锈钢盘碗', '日用品-厨房用具', '个', '600.00', '6000.00', '2', '1', '2016-04-14 05:12:13', null, null, '14');
    INSERT INTO `smbms_bill` VALUES ('9', 'BILL2016_009', '塑料杯', '日用品-杯子', '个', '350.00', '1750.00', '2', '1', '2016-02-04 11:40:20', null, null, '14');
    INSERT INTO `smbms_bill` VALUES ('10', 'BILL2016_010', '豆瓣酱', '食品-调料', '瓶', '200.00', '2000.00', '2', '1', '2013-10-29 05:07:03', null, null, '8');
    INSERT INTO `smbms_bill` VALUES ('11', 'BILL2016_011', '海之蓝', '饮料-国酒', '瓶', '50.00', '10000.00', '1', '1', '2016-04-14 16:16:00', null, null, '1');
    INSERT INTO `smbms_bill` VALUES ('12', 'BILL2016_012', '芝华士', '饮料-洋酒', '瓶', '20.00', '6000.00', '1', '1', '2016-09-09 17:00:00', null, null, '1');
    INSERT INTO `smbms_bill` VALUES ('13', 'BILL2016_013', '长城红葡萄酒', '饮料-红酒', '瓶', '60.00', '800.00', '2', '1', '2016-11-14 15:23:00', null, null, '1');
    INSERT INTO `smbms_bill` VALUES ('14', 'BILL2016_014', '泰国香米', '食品-大米', '斤', '400.00', '5000.00', '2', '1', '2016-10-09 15:20:00', null, null, '3');
    INSERT INTO `smbms_bill` VALUES ('15', 'BILL2016_015', '东北大米', '食品-大米', '斤', '600.00', '4000.00', '2', '1', '2016-11-14 14:00:00', null, null, '3');
    INSERT INTO `smbms_bill` VALUES ('16', 'BILL2016_016', '可口可乐', '饮料', '瓶', '2000.00', '6000.00', '2', '1', '2012-03-27 13:03:01', null, null, '2');
    INSERT INTO `smbms_bill` VALUES ('17', 'BILL2016_017', '脉动', '饮料', '瓶', '1500.00', '4500.00', '2', '1', '2016-05-10 12:00:00', null, null, '2');
    
    -- ----------------------------
    -- Table structure for smbms_provider
    -- ----------------------------
    DROP TABLE IF EXISTS `smbms_provider`;
    CREATE TABLE `smbms_provider` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
      `proCode` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '供应商编码',
      `proName` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '供应商名称',
      `proDesc` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '供应商详细描述',
      `proContact` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '供应商联系人',
      `proPhone` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '联系电话',
      `proAddress` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '地址',
      `proFax` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '传真',
      `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者(userId)',
      `creationDate` datetime DEFAULT NULL COMMENT '创建时间',
      `modifyDate` datetime DEFAULT NULL COMMENT '更新时间',
      `modifyBy` bigint(20) DEFAULT NULL COMMENT '更新者(userId)',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    
    -- ----------------------------
    -- Records of smbms_provider
    -- ----------------------------
    INSERT INTO `smbms_provider` VALUES ('1', 'BJ_GYS001', '北京三木堂商贸有限公司', '长期合作伙伴,主营产品:茅台、五粮液、郎酒、酒鬼酒、泸州老窖、赖茅酒、法国红酒等', '张国强', '13566669999', '北京市丰台区育芳园北路', '010-58858787', '1', '2013-03-21 16:52:07', '2019-04-12 16:44:03', '10');
    INSERT INTO `smbms_provider` VALUES ('2', 'HB_GYS001', '石家庄帅益食品贸易有限公司', '长期合作伙伴,主营产品:饮料、水饮料、植物蛋白饮料、休闲食品、果汁饮料、功能饮料等', '王军', '13309094212', '河北省石家庄新华区', '0311-67738876', '1', '2016-04-13 04:20:40', null, null);
    INSERT INTO `smbms_provider` VALUES ('3', 'GZ_GYS001', '深圳市泰香米业有限公司', '初次合作伙伴,主营产品:良记金轮米,龙轮香米等', '郑程瀚', '13402013312', '广东省深圳市福田区深南大道6006华丰大厦', '0755-67776212', '1', '2014-03-21 16:56:07', null, null);
    INSERT INTO `smbms_provider` VALUES ('4', 'GZ_GYS002', '深圳市喜来客商贸有限公司', '长期合作伙伴,主营产品:坚果炒货.果脯蜜饯.天然花茶.营养豆豆.特色美食.进口食品.海味零食.肉脯肉', '林妮', '18599897645', '广东省深圳市福龙工业区B2栋3楼西', '0755-67772341', '1', '2013-03-22 16:52:07', null, null);
    INSERT INTO `smbms_provider` VALUES ('5', 'JS_GYS001', '兴化佳美调味品厂', '长期合作伙伴,主营产品:天然香辛料、鸡精、复合调味料', '徐国洋', '13754444221', '江苏省兴化市林湖工业区', '0523-21299098', '1', '2015-11-22 16:52:07', null, null);
    INSERT INTO `smbms_provider` VALUES ('6', 'BJ_GYS002', '北京纳福尔食用油有限公司', '长期合作伙伴,主营产品:山茶油、大豆油、花生油、橄榄油等', '马莺', '13422235678', '北京市朝阳区珠江帝景1号楼', '010-588634233', '1', '2012-03-21 17:52:07', null, null);
    INSERT INTO `smbms_provider` VALUES ('7', 'BJ_GYS003', '北京国粮食用油有限公司', '初次合作伙伴,主营产品:花生油、大豆油、小磨油等', '王驰', '13344441135', '北京大兴青云店开发区', '010-588134111', '1', '2016-04-13 00:00:00', null, null);
    INSERT INTO `smbms_provider` VALUES ('8', 'ZJ_GYS001', '慈溪市广和绿色食品厂', '长期合作伙伴,主营产品:豆瓣酱、黄豆酱、甜面酱,辣椒,大蒜等农产品', '薛圣丹', '18099953223', '浙江省宁波市慈溪周巷小安村', '0574-34449090', '1', '2013-11-21 06:02:07', null, null);
    INSERT INTO `smbms_provider` VALUES ('9', 'GX_GYS001', '优百商贸有限公司', '长期合作伙伴,主营产品:日化产品', '李立国', '13323566543', '广西南宁市秀厢大道42-1号', '0771-98861134', '1', '2013-03-21 19:52:07', null, null);
    INSERT INTO `smbms_provider` VALUES ('10', 'JS_GYS002', '南京火头军信息技术有限公司', '长期合作伙伴,主营产品:不锈钢厨具等', '陈女士', '13098992113', '江苏省南京市浦口区浦口大道1号新城总部大厦A座903室', '025-86223345', '1', '2013-03-25 16:52:07', null, null);
    INSERT INTO `smbms_provider` VALUES ('11', 'GZ_GYS003', '广州市白云区美星五金制品厂', '长期合作伙伴,主营产品:海绵床垫、坐垫、靠垫、海绵枕头、头枕等', '梁天', '13562276775', '广州市白云区钟落潭镇福龙路20号', '020-85542231', '1', '2016-12-21 06:12:17', null, null);
    INSERT INTO `smbms_provider` VALUES ('12', 'BJ_GYS004', '北京隆盛日化科技', '长期合作伙伴,主营产品:日化环保清洗剂,家居洗涤专卖、洗涤用品网、墙体除霉剂、墙面霉菌清除剂等', '孙欣', '13689865678', '北京市大兴区旧宫', '010-35576786', '1', '2014-11-21 12:51:11', null, null);
    INSERT INTO `smbms_provider` VALUES ('13', 'SD_GYS001', '山东豪克华光联合发展有限公司', '长期合作伙伴,主营产品:洗衣皂、洗衣粉、洗衣液、洗洁精、消杀类、香皂等', '吴洪转', '13245468787', '山东济阳济北工业区仁和街21号', '0531-53362445', '1', '2015-01-28 10:52:07', null, null);
    
    -- ----------------------------
    -- Table structure for smbms_role
    -- ----------------------------
    DROP TABLE IF EXISTS `smbms_role`;
    CREATE TABLE `smbms_role` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
      `roleCode` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '角色编码',
      `roleName` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '角色名称',
      `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者',
      `creationDate` datetime DEFAULT NULL COMMENT '创建时间',
      `modifyBy` bigint(20) DEFAULT NULL COMMENT '修改者',
      `modifyDate` datetime DEFAULT NULL COMMENT '修改时间',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    
    -- ----------------------------
    -- Records of smbms_role
    -- ----------------------------
    INSERT INTO `smbms_role` VALUES ('1', 'SMBMS_ADMIN', '系统管理员', '1', '2016-04-13 00:00:00', null, null);
    INSERT INTO `smbms_role` VALUES ('2', 'SMBMS_MANAGER', '经理', '1', '2016-04-13 00:00:00', null, null);
    INSERT INTO `smbms_role` VALUES ('3', 'SMBMS_EMPLOYEE', '普通员工', '1', '2016-04-13 00:00:00', null, null);
    
    -- ----------------------------
    -- Table structure for smbms_user
    -- ----------------------------
    DROP TABLE IF EXISTS `smbms_user`;
    CREATE TABLE `smbms_user` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
      `userCode` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '用户编码',
      `userName` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '用户名称',
      `userPassword` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '用户密码',
      `gender` int(10) DEFAULT NULL COMMENT '性别(1:女、 2:男)',
      `birthday` date DEFAULT NULL COMMENT '出生日期',
      `phone` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '手机',
      `address` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '地址',
      `userRole` int(10) DEFAULT NULL COMMENT '用户角色(取自角色表-角色id)',
      `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者(userId)',
      `creationDate` datetime DEFAULT NULL COMMENT '创建时间',
      `modifyBy` bigint(20) DEFAULT NULL COMMENT '更新者(userId)',
      `modifyDate` datetime DEFAULT NULL COMMENT '更新时间',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    
    -- ----------------------------
    -- Records of smbms_user
    -- ----------------------------
    INSERT INTO `smbms_user` VALUES ('1', 'wen', '系统管理员', '123', '1', '1997-01-01', '15200981234', '湖南省衡阳市蒸湘区南华大学', '1', '1', '2019-04-07 10:15:55', null, null);
    INSERT INTO `smbms_user` VALUES ('5', 'hanlubiao', '韩路彪', '0000000', '2', '1984-06-05', '18567542321', '北京市朝阳区北辰中心12号', '2', '1', '2014-12-31 19:52:09', null, null);
    INSERT INTO `smbms_user` VALUES ('6', 'zhanghua', '张华', '0000000', '1', '1983-06-15', '13544561111', '北京市海淀区学院路61号', '3', '1', '2013-02-11 10:51:17', null, null);
    INSERT INTO `smbms_user` VALUES ('7', 'wangyang', '王洋', '0000000', '2', '1982-12-31', '13444561124', '北京市海淀区西二旗辉煌国际16层', '3', '1', '2014-06-11 19:09:07', null, null);
    INSERT INTO `smbms_user` VALUES ('8', 'zhaoyan', '赵燕', '0000000', '1', '1986-03-07', '18098764545', '北京市海淀区回龙观小区10号楼', '3', '1', '2016-04-21 13:54:07', null, null);
    INSERT INTO `smbms_user` VALUES ('10', 'sunlei', '孙磊', '0000000', '2', '1981-01-04', '13387676765', '北京市朝阳区管庄新月小区12楼', '3', '1', '2015-05-06 10:52:07', null, null);
    INSERT INTO `smbms_user` VALUES ('11', 'sunxing', '孙兴', '0000000', '2', '1978-03-12', '13367890900', '北京市朝阳区建国门南大街10号', '3', '1', '2016-11-09 16:51:17', null, null);
    INSERT INTO `smbms_user` VALUES ('12', 'zhangchen', '张晨', '0000000', '1', '1986-03-28', '18098765434', '朝阳区管庄路口北柏林爱乐三期13号楼', '3', '1', '2016-08-09 05:52:37', '1', '2016-04-14 14:15:36');
    INSERT INTO `smbms_user` VALUES ('13', 'dengchao', '邓超', '0000000', '2', '1981-11-04', '13689674534', '北京市海淀区北航家属院10号楼', '3', '1', '2016-07-11 08:02:47', null, null);
    INSERT INTO `smbms_user` VALUES ('14', 'yangguo', '杨过', '0000000', '2', '1980-01-01', '13388886623', '北京市朝阳区北苑家园茉莉园20号楼', '3', '1', '2015-02-01 03:52:07', null, null);
    INSERT INTO `smbms_user` VALUES ('15', 'test', 'test', '111', '1', '2019-04-16', '123456789', '南华大学', '1', '1', '2019-04-16 19:52:37', null, null);
    

14.2 UserMapper.xml(8道题)

  1. UserMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.LEEZ.dao.UserMapper">
        <select id="getLoginUser" resultType="User">
            select * from smbms_user
            <where>
                <if test="userCode != null">
                    userCode = #{userCode}
                </if>
            </where>
        </select>
    
        <insert id="add" parameterType="User">
            insert into smbms_user(id,userCode,userName,userPassword,gender,birthday,phone,address,userRole)
            values(#{id},#{userCode},#{userName},#{userPassword},#{gender},#{birthday},#{phone},#{address},#{userRole})
        </insert>
    
        <!--将多次重复的sql语句提取出来-->
        <sql id="if-userName-userRole">
            <if test="userName != null">
                userName like "%"#{userName}"%"
            </if>
            <if test="userRole != null">
                and userRole = #{userRole}
            </if>
        </sql>
    
        <select id="getUserList" resultType="User">
            select u.*,r.roleName from smbms_user u,smbms_role r
            <where>
                u.userRole = r.id
                <include refid="if-userName-userRole"/>
            </where>
            limit #{from},#{pageSize}
        </select>
    
        <select id="getUserCount" resultType="int">
            select count(1) from smbms_user
            <where>
                <include refid="if-userName-userRole"/>
            </where>
        </select>
    
        <!--将多次重复的sql语句提取出来-->
        <sql id="if-id">
            <if test="id != null">
                id = #{id}
            </if>
        </sql>
    
        <delete id="deleteUserById" parameterType="int">
            delete from smbms_user
            <where>
                <include refid="if-id"/>
            </where>
        </delete>
    
        <select id="getUserById" resultType="User">
            select * from smbms_user
            <where>
                <include refid="if-id"/>
            </where>
        </select>
    
        <update id="modify" parameterType="User">
            update smbms_user
            <set>
                <if test="userCode != null">
                    userCode = #{userCode},
                </if>
                <if test="userName != null">
                    userName = #{userName},
                </if>
                <if test="userPassword != null">
                    userPassword = #{userPassword},
                </if>
                <if test="gender != null">
                    gender = #{gender},
                </if>
                <if test="birthday != null">
                    birthday = #{birthday},
                </if>
                <if test="phone != null">
                    phone = #{phone},
                </if>
                <if test="address != null">
                    address = #{address},
                </if>
                <if test="userRole != null">
                    userRole = #{userRole}
                </if>
            </set>
            <where>
                <include refid="if-id"/>
            </where>
        </update>
    
        <update id="updatePwd">
            update smbms_user
            <set>
                <if test="userPassword != null">
                    userPassword = #{userPassword}
                </if>
            </set>
            <where>
                <include refid="if-id"/>
            </where>
        </update>
    </mapper>
    
  2. 测试

    1. @Test
      public void testGetLoginUser() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          UserMapper mapper = sqlSession.getMapper(UserMapper.class);
          User admin = mapper.getLoginUser("admin");
          System.out.println(admin);
          sqlSession.close();
      }
      
    2. @Test
      public void testAdd() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          UserMapper mapper = sqlSession.getMapper(UserMapper.class);
          int add = mapper.add(new User(27, "LEEZ", "CV攻城狮", "111111", 1, new Date(), "13411111111", "清华大学", 1));
          sqlSession.close();
      }
      
    3. @Test
      public void testGetUserList() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          UserMapper mapper = sqlSession.getMapper(UserMapper.class);
          List<User> userList = mapper.getUserList("张", 3, 0, 5);
          for (User user : userList) {
              System.out.println(user);
          }
          sqlSession.close();
      }
      
    4. @Test
      public void testGetUserCount() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          UserMapper mapper = sqlSession.getMapper(UserMapper.class);
          int userCount = mapper.getUserCount("张", 3);
          System.out.println(userCount);
          sqlSession.close();
      }
      
    5. @Test
      public void testDeleteUserById() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          UserMapper mapper = sqlSession.getMapper(UserMapper.class);
          int i = mapper.deleteUserById(27);
          System.out.println(i);
          sqlSession.close();
      }
      
    6. @Test
      public void testGetUserById() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          UserMapper mapper = sqlSession.getMapper(UserMapper.class);
          User userById = mapper.getUserById(1);
          System.out.println(userById);
          sqlSession.close();
      }
      
    7. @Test
      public void testModify() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          UserMapper mapper = sqlSession.getMapper(UserMapper.class);
          int modify = mapper.modify(new User(26, "LEEZ", "CV攻城狮", "111111", 1, new Date(), "13411111111", "清华大学", 1));
          System.out.println(modify);
          sqlSession.close();
      }
      
    8. @Test
      public void testUpdatePwd() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          UserMapper mapper = sqlSession.getMapper(UserMapper.class);
          int updatePwd = mapper.updatePwd(26, "222222");
          System.out.println(updatePwd);
          sqlSession.close();
      }
      
  3. 结果

    1. mybatis-20
    2. mybatis-21
    3. mybatis-22
    4. mybatis-23
    5. mybatis-24
    6. mybatis-25
    7. mybatis-26
    8. mybatis-27

14.3 RoleMapper.xml(6道题)

  1. RoleMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.LEEZ.dao.RoleMapper">
        <select id="getRoleList" resultType="Role">
            select * from smbms_role
        </select>
    
        <insert id="add" parameterType="Role">
            insert into smbms_role(id,roleCode,roleName,createdBy,creationDate,modifyBy,modifyDate)
            values(#{id},#{roleCode},#{roleName},#{createdBy},#{creationDate},#{modifyBy},#{modifyDate})
        </insert>
    
        <!--多次使用到的sql片段提取出来,方便复用-->
        <sql id="if-id">
            <if test="id != null">
                id = #{id}
            </if>
        </sql>
    
        <delete id="deleteRoleById">
            delete from smbms_role
            <where>
                <include refid="if-id"/>
            </where>
        </delete>
    
        <update id="modify">
            update smbms_role
            <set>
                <if test="roleCode != null">
                    roleCode = #{roleCode},
                </if>
                <if test="roleName != null">
                    roleName = #{roleName},
                </if>
                <if test="createdBy != null">
                    createdBy = #{createdBy},
                </if>
                <if test="creationDate != null">
                    creationDate = #{creationDate},
                </if>
            </set>
            <where>
                <include refid="if-id"/>
            </where>
        </update>
    
        <select id="getRoleById" resultType="Role">
            select * from smbms_role
            <where>
                <include refid="if-id"/>
            </where>
        </select>
    
        <select id="roleCodeIsExist" resultType="int">
            select count(*) from smbms_role
            <where>
                <if test="roleCode != null">
                    roleCode = #{roleCode}
                </if>
            </where>
        </select>
    </mapper>
    
  2. 测试

    1. @Test
      public void testGetRoleList() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          RoleMapper mapper = sqlSession.getMapper(RoleMapper.class);
          List<Role> roleList = mapper.getRoleList();
          for (Role role : roleList) {
              System.out.println(role);
          }
          sqlSession.close();
      }
      
    2. @Test
      public void testAdd() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          RoleMapper mapper = sqlSession.getMapper(RoleMapper.class);
          int add = mapper.add(new Role(4, "SMBMS_STUDENT", "实习生", 1, new Date(), null, null));
          System.out.println(add);
          sqlSession.close();
      }
      
    3. @Test
      public void testDeleteRoleById() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          RoleMapper mapper = sqlSession.getMapper(RoleMapper.class);
          int i = mapper.deleteRoleById(4);
          System.out.println(i);
          sqlSession.close();
      }
      
    4. @Test
      public void testModify() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          RoleMapper mapper = sqlSession.getMapper(RoleMapper.class);
          int modify = mapper.modify(new Role(4, "SMBMS_STUDENT", "实习生1", 1, new Date(), null, null));
          System.out.println(modify);
          sqlSession.close();
      }
      
    5. @Test
      public void testGetRoleById() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          RoleMapper mapper = sqlSession.getMapper(RoleMapper.class);
          Role roleById = mapper.getRoleById(4);
          System.out.println(roleById);
          sqlSession.close();
      }
      
    6. @Test
      public void testRoleCodeIsExist() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          RoleMapper mapper = sqlSession.getMapper(RoleMapper.class);
          int i = mapper.roleCodeIsExist("SMBMS_SUPADMIN");
          System.out.println(i);
          sqlSession.close();
      }
      
  3. 结果

    1. mybatis-28
    2. mybatis-29
    3. mybatis-30
    4. mybatis-31
    5. mybatis-32
    6. mybatis-33

14.4 BillMapper.xml(8道题)

  1. BillMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.LEEZ.dao.BillMapper">
        <select id="getBillCountByProviderId" resultType="int">
            select count(1) from smbms_bill
            <where>
                <if test="providerId != null">
                    providerId = #{providerId}
                </if>
            </where>
        </select>
    
        <insert id="add">
            insert into
            smbms_bill(id,billCode,productName,productDesc,productUnit,productCount,totalPrice,isPayment,createdBy,creationDate,providerId)
            values(#{id},#{billCode},#{productName},#{productDesc},#{productUnit},#{productCount},#{totalPrice},#{isPayment},#{createdBy},#{creationDate},#{providerId})
        </insert>
    
        <select id="getBillList" resultType="Bill">
            select b.*,proName from smbms_bill b,smbms_provider p
            <where>
                b.providerId = p.id
                <if test="productName != null">
                    and productName like "%"#{productName}"%"
                </if>
                <if test="providerId != null">
                    and providerId = #{providerId}
                </if>
                <if test="isPayment != null">
                    and isPayment = #{isPayment}
                </if>
            </where>
            limit #{from},#{pageSize}
        </select>
    
        <select id="getBillCount" resultType="int">
            select count(1) from smbms_bill
            <where>
                <if test="productName != null">
                    productName like "%"#{productName}"%"
                </if>
                <if test="providerId != null">
                    and providerId = #{providerId}
                </if>
                <if test="isPayment != null">
                    and isPayment = #{isPayment}
                </if>
            </where>
        </select>
    
        <delete id="deleteBillById">
            delete from smbms_bill
            <where>
                <include refid="if-id"/>
            </where>
        </delete>
    
        <select id="getBillById" resultType="Bill">
            select * from smbms_bill
            <where>
                <include refid="if-id"/>
            </where>
        </select>
    
        <!--多次使用到的sql片段提取出来,方便复用-->
        <sql id="if-id">
            <if test="id != null">
                id = #{id}
            </if>
        </sql>
    
        <update id="modify">
            update smbms_bill
            <set>
                <if test="billCode != null">
                    billCode = #{billCode},
                </if>
                <if test="productName != null">
                    productName = #{productName},
                </if>
                <if test="productDesc != null">
                    productDesc = #{productDesc},
                </if>
                <if test="productUnit != null">
                    productUnit = #{productUnit},
                </if>
                <if test="productCount != null">
                    productCount = #{productCount},
                </if>
                <if test="totalPrice != null">
                    totalPrice = #{totalPrice},
                </if>
                <if test="isPayment != null">
                    isPayment = #{isPayment},
                </if>
                <if test="createdBy != null">
                    createdBy = #{createdBy},
                </if>
                <if test="creationDate != null">
                    creationDate = #{creationDate},
                </if>
                <if test="providerId != null">
                    providerId = #{providerId}
                </if>
            </set>
            <where>
                <include refid="if-id"/>
            </where>
        </update>
        
        <delete id="deleteBillByProviderId">
            delete from smbms_bill
            <where>
                <if test="providerId != null">
                    providerId = #{providerId}
                </if>
            </where>
        </delete>
    </mapper>
    
  2. 测试

    1. @Test
      public void testGetBillCountByProviderId() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          BillMapper mapper = sqlSession.getMapper(BillMapper.class);
          int billCountByProviderId = mapper.getBillCountByProviderId(13);
          System.out.println(billCountByProviderId);
          sqlSession.close();
      }
      
    2. @Test
      public void testAdd() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          BillMapper mapper = sqlSession.getMapper(BillMapper.class);
          int add = mapper.add(new Bill(18, "BILL2022_018", "百事可乐", "饮料", "瓶", new BigDecimal(200.00), new BigDecimal(600.00), 2, 1, new Date(), 15));
          System.out.println(add);
          sqlSession.close();
      }
      
    3. @Test
      public void testGetBillList() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          BillMapper mapper = sqlSession.getMapper(BillMapper.class);
          List<Bill> billList = mapper.getBillList("", 2, 2, 0, 5);
          for (Bill bill : billList) {
              System.out.println(bill);
          }
          sqlSession.close();
      }
      
    4. @Test
      public void testGetBillCount() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          BillMapper mapper = sqlSession.getMapper(BillMapper.class);
          int count = mapper.getBillCount("可乐", 2, 2);
          System.out.println(count);
          sqlSession.close();
      }
      
    5. @Test
      public void testDeleteBillById() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          BillMapper mapper = sqlSession.getMapper(BillMapper.class);
          int i = mapper.deleteBillById(18);
          System.out.println(i);
          sqlSession.close();
      }
      
    6. @Test
      public void testGetBillById() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          BillMapper mapper = sqlSession.getMapper(BillMapper.class);
          Bill billById = mapper.getBillById(17);
          System.out.println(billById);
          sqlSession.close();
      }
      
    7. @Test
      public void testModify() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          BillMapper mapper = sqlSession.getMapper(BillMapper.class);
          mapper.modify(new Bill(18, "BILL2022_018", "百事可乐", "饮料", "瓶", new BigDecimal(300.00), new BigDecimal(900.00), 2, 1, new Date(), 15));
          sqlSession.close();
      }
      
    8. @Test
      public void testDeleteBillByProviderId() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          BillMapper mapper = sqlSession.getMapper(BillMapper.class);
          int i = mapper.deleteBillByProviderId(15);
          System.out.println(i);
          sqlSession.close();
      }
      
  3. 结果

    1. mybatis-34
    2. mybatis-35
    3. mybatis-36
    4. mybatis-37
    5. mybatis-38
    6. mybatis-39
    7. mybatis-40
    8. mybatis-41

14.3 ProviderMapper.xml(7道题)

  1. RoleMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.LEEZ.dao.ProviderMapper">
        <insert id="add">
            insert into smbms_provider(id,proCode,proName,proDesc,proContact,proPhone,proAddress,proFax,createdBy,creationDate)
            values(#{id},#{proCode},#{proName},#{proDesc},#{proContact},#{proPhone},#{proAddress},#{proFax},#{createdBy},#{creationDate})
        </insert>
    
        <select id="getProviderList" resultType="Provider">
            select * from smbms_provider
            <where>
                <include refid="if-proName-proCode"/>
            </where>
            limit #{from},#{pageSize}
        </select>
    
        <select id="getProList" resultType="Provider">
            select * from smbms_provider
        </select>
    
        <!--将多次使用的sql语句提取出来-->
        <sql id="if-proName-proCode">
            <if test="proName != null">
                proName like "%"#{proName}"%"
            </if>
            <if test="proCode != null">
                and proCode like "%"#{proCode}"%"
            </if>
        </sql>
    
        <select id="getProviderCount" resultType="int">
            select count(1) from smbms_provider
            <where>
                <include refid="if-proName-proCode"/>
            </where>
        </select>
    
        <delete id="deleteProviderById">
            delete from smbms_provider
            <where>
                <include refid="if-id"/>
            </where>
        </delete>
    
        <!--提取出多次使用的sql语句-->
        <sql id="if-id">
            <if test="id != null">
                id = #{id}
            </if>
        </sql>
    
        <select id="getProviderById" resultType="Provider">
            select * from smbms_provider
            <where>
                <include refid="if-id"/>
            </where>
        </select>
    
        <update id="modify">
            update smbms_provider
            <set>
                <if test="proCode != null">
                    proCode = #{proCode},
                </if>
                <if test="proName != null">
                    proName = #{proName},
                </if>
                <if test="proDesc != null">
                    proDesc = #{proDesc},
                </if>
                <if test="proContact != null">
                    proContact = #{proContact},
                </if>
                <if test="proPhone != null">
                    proPhone = #{proPhone},
                </if>
                <if test="proAddress != null">
                    proAddress = #{proAddress},
                </if>
                <if test="proFax != null">
                    proFax = #{proFax},
                </if>
                <if test="createdBy != null">
                    createdBy = #{createdBy},
                </if>
                <if test="creationDate != null">
                    creationDate = #{creationDate}
                </if>
            </set>
            <where>
                <include refid="if-id"/>
            </where>
        </update>
    </mapper>
    
  2. 测试

    1. @Test
      public void testAdd() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          ProviderMapper mapper = sqlSession.getMapper(ProviderMapper.class);
          int add = mapper.add(new Provider(14, "JM_LES009", "江门市云云科技有限公司", "初次合作伙伴", "LEEZ", "13411111111", "江门市蓬江区", "010-11111111", 1, new Date()));
          System.out.println(add);
          sqlSession.close();
      }
      
    2. @Test
      public void testGetProviderList() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          ProviderMapper mapper = sqlSession.getMapper(ProviderMapper.class);
          List<Provider> providerList = mapper.getProviderList("北京", "00", 0, 5);
          for (Provider provider : providerList) {
              System.out.println(provider);
          }
          sqlSession.close();
      }
      
    3. @Test
      public void testGetProList() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          ProviderMapper mapper = sqlSession.getMapper(ProviderMapper.class);
          List<Provider> proList = mapper.getProList();
          for (Provider provider : proList) {
              System.out.println(proList);
          }
          sqlSession.close();
      }
      
    4. @Test
      public void testGetProviderCount() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          ProviderMapper mapper = sqlSession.getMapper(ProviderMapper.class);
          int providerCount = mapper.getProviderCount("北京", "00");
          System.out.println(providerCount);
          sqlSession.close();
      }
      
    5. @Test
      public void testDeleteProviderById() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          ProviderMapper mapper = sqlSession.getMapper(ProviderMapper.class);
          int i = mapper.deleteProviderById(14);
          System.out.println(i);
          sqlSession.close();
      }
      
    6. @Test
      public void testGetProviderById() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          ProviderMapper mapper = sqlSession.getMapper(ProviderMapper.class);
          Provider providerById = mapper.getProviderById(13);
          System.out.println(providerById);
          sqlSession.close();
      }
      
    7. @Test
      public void testModify() throws Exception {
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          ProviderMapper mapper = sqlSession.getMapper(ProviderMapper.class);
          int modify = mapper.modify(new Provider(14, "JM_LES009", "江门市磊磊科技有限公司", "初次合作伙伴", "LEEZ", "13411111111", "江门市蓬江区", "010-11111111", 1, new Date()));
          System.out.println(modify);
          sqlSession.close();
      }
      
  3. 结果

    1. mybatis-42
    2. mybatis-43
    3. mybatis-44
    4. mybatis-45
    5. mybatis-46
    6. mybatis-47
    7. mybatis-48
posted @ 2022-11-25 15:45  CV攻城狮~  阅读(15)  评论(0编辑  收藏  举报