[MyBatis]狂神说Java视频笔记

Mybatis

1.简介

  1. 定义

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

    • MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

    • iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)

  2. 特点

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

    • 持久化:将程序数据在持久状态和瞬时状态间转换的机制
    • 持久层:完成持久化工作的代码块

2.第一个Mybatis程序

1.创建maven项目
2.引入依赖
<!--mybatis-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.2</version>
</dependency>
<!--mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>
3.编写MyBatis核心配置文件
  • mybatis-01\src\main\resources\mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <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=false&amp;useUnicode=true&amp;characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="ZC520"/>
            </dataSource>
        </environment>
    </environments>
</configuration>
4.编写mybatis工具类
  • mybatis-01\src\main\java\com\zc\utils\MybatisUtils.java
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //获取SqlSession连接
    public static SqlSession getSession(){
        return sqlSessionFactory.openSession();
    }
}
5.创建实体类
  • mybatis-01\src\main\java\com\zc\pojo\User.java
public class User {
    private int id;
    private String name;
    private String pwd;
}
6.编写mapper接口
  • mybatis-01\src\main\java\com\zc\mapper\UserMapper.java
public interface UserMapper {
    List<User> selectUsers();
}
7.编写实现mapper接口的xml文件
  • mybatis-01\src\main\java\com\zc\mapper\UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:sql语句映射的接口-->
<mapper namespace="com.zc.mapper.UserMapper">
    <!--id:接口中方法名称-->
    <!--resultType:返回值类型映射的类型-->
    <select id="selectUsers" resultType="com.zc.pojo.User">
        select * from USER
    </select>
</mapper>
8.在mybatis的核心配置文件中,配置UserMapper.xml的路径

mybatis-01\src\main\resources\mybatis-config.xml

<mappers>
    <mapper resource="com/zc/mapper/UserMapper.xml"/>
</mappers>
9.测试类
  • mybatis-01\src\test\java\com\zc\mapper\UserMapperTest.java
@Test
public void selectUsers(){
    //获取SqlSession对象
    SqlSession session = MybatisUtils.getSession();

    //方式一:
    //List<User> users = session.selectList("com.zc.mapper.UserMapper.selectUsers");

    //方式二:
    UserMapper mapper = session.getMapper(UserMapper.class);
    List<User> users = mapper.selectUsers();

    for (User user : users) {
        System.out.println(user);
    }

    session.close();
}
10.补充:
  • Maven静态资源过滤问题(maven会自动过滤一些路径下的资源文件)

  • 在pom.xml中,加上如下配置,即可解决

<build>
       <resources>
           <resource>
               <directory>src/main/java</directory>
               <includes>
                   <include>**/*.properties</include>
                   <include>**/*.xml</include>
               </includes>
               <filtering>false</filtering>
           </resource>
           <resource>
               <directory>src/main/resources</directory>
               <includes>
                   <include>**/*.properties</include>
                   <include>**/*.xml</include>
               </includes>
               <filtering>false</filtering>
           </resource>
       </resources>
</build>

3.增删改查实现

1.select
  1. UserMapper.java

    //根据id查询用户
    User selectUserById(int id);
    
  2. UserMapper.xml

    <!--根据id查询用户-->
    <select id="selectUserById" parameterType="int" resultType="com.zc.pojo.User">
        select * from user where id = #{id}
    </select>
    
  3. test

    @Test
    public void selectUserById(){
        SqlSession session = MybatisUtils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        User user = mapper.selectUserById(2);
        System.out.println(user);
        session.close();
    }
    
2.delete
  1. UserMapper.java

    //根据id删除用户
    void delUserById(int id);
    
  2. UserMapper.xml

    <!--根据id删除用户-->
    <delete id="delUserById" parameterType="int">
        DELETE FROM user WHERE id = #{id}
    </delete>
    
  3. test

    @Test
    public void delUserById(){
        SqlSession session = MybatisUtils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.delUserById(3);
        //提交事务
        session.commit();
        session.close();
    }
    
3.update
  1. UserMapper.java

    //根据id修改用户信息
    void updateUser(User user);
    
  2. UserMapper.xml

    <!--修改用户-->
    <update id="updateUser" parameterType="com.zc.pojo.User">
        UPDATE user set  name=#{name},pwd=#{pwd} where id = #{id}
    </update>
    
  3. test

    @Test
    public void updateUser(){
        SqlSession session = MybatisUtils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.updateUser(new User(4,"李白白白白","123456789"));
        session.commit();
        session.close();
    }
    
4.insert
  1. UserMapper.java

    //添加用户
    void addUser(User user);
    
  2. UserMapper.xml

    @Test
    public void addUser(){
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    mapper.addUser(new User(3,"张三三三三","123456"));
    mapper.addUser(new User(4,"李三三三三","123456"));
    session.commit();
    session.close();
    }
    
  3. test

    @Test
    public void addUser(){
        SqlSession session = MybatisUtils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.addUser(new User(3,"张三三三三","123456"));
        mapper.addUser(new User(4,"李三三三三","123456"));
        session.commit();
        session.close();
    }
    
5.补充
  • 所有的增删改操作都需要加事务
6.巧用map
  1. 使用Map传递参数,可以很随意,不需要像传递对象那样,字段一一对应

  2. UserMapper

    //根据id修改用户指定信息
    void updateUser2(Map map);
    
  3. UserMapper.xml

    <!--根据id修改用户指定信息-->
    <update id="updateUser2" parameterType="map">
        update user set pwd = #{password} where id = #{UserId}
    </update>
    
  4. Test

    @Test
    public void updateUser2(){
        SqlSession session = MybatisUtils.getSession();
    
        UserMapper mapper = session.getMapper(UserMapper.class);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("UserId",3);
        map.put("password","111111111");
        mapper.updateUser2(map);
        session.commit();
        session.close();
    }
    
7.模糊查询
  1. UserMapper

    //模糊查询
    List<User> selectUserLike(String value);
    
  2. UserMapper.xml

    <!--模糊查询-->
    <select id="selectUserLike" parameterType="java.lang.String" resultType="com.zc.pojo.User">
        SELECT * FROM user where name LIKE #{value}
    </select>
    
  3. Test

    @Test
    public void selectUserLike(){
        SqlSession session = MybatisUtils.getSession();
    
        UserMapper mapper = session.getMapper(UserMapper.class);
        List<User> userList = mapper.selectUserLike("三%");
        for (User user : userList) {
            System.out.println(user);
        }
    
        session.close();
    }
    

4.XML配置

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

在这里插入图片描述

1.环境配置(environments)
  1. MyBatis可以配置成适应多种环境,这种机制有助于将SQL映射应用于多种数据库中。

  2. 虽然可以配置多个环境,但每个SqlSessionFactory实例只能选择一种环境

  3. 实例:

    <environments default="development">
        <!--每个环境对应一个id-->
        <environment id="development">
            <!--配置事务管理器, type指定事务管理器的类型-->
            <!--type表示事务管理器的类型-->
            <transactionManager type="JDBC"/>
            <!--配置数据源, type指定数据源类型-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="ZC520"/>
            </dataSource>
        </environment>
    </environments>
    
  4. 有三种内嵌的数据源类型

    type="[UNPOOLED|POOLED|JNDI]"
    
    • unpooled:这个数据源的实现只是每次被请求时打开和关闭连接
    • pooled:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,这是一种使得并发Web应用快速响应请求的流行处理方式
    • jndi:这个数据源的实现是为了能在如 Spring 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用
    • 数据源也有很多第三方的实现,比如dbcp,c3p0,druid等等…
2.属性配置(properties)

数据库这些属性是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。

  1. 在Java属性文件中配置

    1. mybatis-02\src\main\resources\db.properties

      driver=com.mysql.jdbc.Driver
      url=jdbc:mysql://localhost:3306/mybatis
      username=root
      password=ZC520
      
    2. mybatis-02\src\main\resources\mybatis-config.xml

      <!--导入外部配置文件-->
      <properties resource="db.properties"/>
          <dataSource type="POOLED">
              <property name="driver" value="${driver}"/>
              <property name="url" value="${url}"/>
              <property name="username" value="${username}"/>
              <property name="password" value="${password}"/>
          </dataSource>
      </environments>
      
  2. 通过properties元素的子元素传递

    1. mybatis-02\src\main\resources\db.properties

      driver=com.mysql.jdbc.Driver
      url=jdbc:mysql://localhost:3306/mybatis
      
    2. mybatis-02\src\main\resources\mybatis-config.xml

      <configuration>
          <!--导入外部配置文件-->
          <properties resource="db.properties">
              <!--通过property标签传值-->
              <property name="username" value="root"></property>
              <property name="password" value="ZC520"></property>
          </properties>
          <dataSource type="POOLED">
              <property name="driver" value="${driver}"/>
              <property name="url" value="${url}"/>
              <property name="username" value="${username}"/>
              <property name="password" value="${password}"/>
          </dataSource>
      </configuration>
      
  3. 优先级:在Java属性文件中配置 > 通过properties元素的子元素传递

3.类型别名(typeAliases)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写

  1. 第一种:具体到某个类

    <!--类型别名-->
    <typeAliases>
        <typeAlias type="com.zc.pojo.User" alias="user"></typeAlias>
    </typeAliases>
    

    当这样配置时,user可以使用在任意需要使用 com.zc.pojo.User 的地方

  2. 第二种:具体到包

    <!--第二种方式-->
    <typeAliases>
        <package name="com.zc.pojo"></package>
    </typeAliases>
    
    • 当使用这种方式时,MyBatis会在包名下搜索需要的 Java Bean

    • 每一个在包 com.zc.pojo 中的 Java Bean,

    • 在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。

    • 例如:com.zc.pojo.User 的 别名为 user;

    • 如果有注解,则别名为其注解值

      @Alias("user")
      public class User {
          private int id;
          private String name;
          private String pwd;
      }
      
4.设置(settings)
  1. 常用

    • 懒加载

    • 日志实现

    • 缓存开启/关闭

  2. 一个配置完整的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>
    
5.类型处理器(typeHandlers)
  • 无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集取出一个值时,都会用类型处理器将获取的值以合适的方式转换成Java类型
  • 可以重写类型处理器或者创建自己的类型处理器来处理不支持的或非标准的类型
6.对象工厂(objectFactory)
  • Mybatis每次创建结果对象的新实例时,都会使用对象工厂实例来完成
  • 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过有参构造方法来实例化
  • 如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现
7.映射器(mapper)

​ MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件

  1. 第一种方式:相对于类路径的资源引用

    <mappers>
        <!--使用相对于类路径的而资源引用-->
        <mapper resource="com/zc/mapper/UserMapper.xml"/>
    </mappers>
    
    • 接口和实现接口的xml文件,名字可以不同
    • 接口和实现接口的xml文件,可以不在同一个包
  2. 第二种方式:使用映射器接口实现类的完全限定类名

    <mappers>
        <!--使用映射器接口实现类的完全限定类名-->
        <mapper class="com.zc.mapper.UserMapper"></mapper>
    </mappers>
    
    • 接口和实现接口的xml文件,名字必须相同
    • 接口和实现接口的xml文件,必须在同一个包
  3. 第三种方式:将包内的映射器接口实现全部注册为映射器

    <mappers>
        <!--将包内的映射器接口实现全部注册为映射器-->
        <package name="com.zc.mapper"></package>
    </mappers>
    
    • 接口和实现接口的xml文件,名字必须相同
    • 接口和实现接口的xml文件,必须在同一个包
8.作用域和生命周期
  1. mybatis执行流程

    在这里插入图片描述

  2. 作用域理解

    • SqlSessionFactoryBuilder的作用在于创建 SqlSessionFactory,创建成功后,SqlSessionFactoryBuilder就失去了作用,所以它只能存在于创建SqlSessionFactory的方法中,而不要让它长期存在,因此,SqlSessionFactoryBuilder实例的最佳作用域是方法作用域(也就是局部方法变量)

    • SqlSessionFactory可以被认为是一个数据库连接池,它的作用是创建 SqlSession接口对象。因为MyBatis的本质就是Java对数据库的操作,所以 SqlSessionFactory的生命周期存在于整个 Mybatis的应用之中,所以一旦创建了SqlSessionFactory,就要长期保存它,直至不再使用MyBatis应用 ,所以可以认为SqlSessionFactory的生命周期等同于MyBatis的应用周期

    • 由于SqlSessionFactory是一个对数据库的连接池,所以它占据着数据库的连接资源。如果创建多个SqlSessionFactory,那么就存在多个数据库连接池,这样不利于对数据库资源的控制,也会导致数据库连接资源被消耗光,出现系统宕机等情况,所以尽量避免发生这样的情况

    • 因此在一般的应用中,我们往往希望SqlSessionFactory作为一个单例,让它在应用中被共享。所以说 SqlSessionFactory的最佳作用域是应用作用域

    • 如果说SqlSessionFactory相当于数据库连接池,那么 SqlSession就相当于一个数据库连接(Connection对象),你可以在一个事务里面执行多条SQL,然后通过它的commit、rollback等方法,提交或者回滚事务。所以它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给 SqlSessionFactory,否则数据库资源就很快被耗费光,系统就会瘫痪,所以用 try…catch…finally…语句来保证其正确关闭。所以SqlSession的最佳作用域是请求或方法作用域

      在这里插入图片描述

9.ResultMap结果集映射:
  1. 自动映射

    • resultMap元素是Mybatis中最重要最强大的元素。它可以让你从90%的JDBC ResultSets数据提取代码中解放出来

    • 实际上,在为一些复杂语句编写映射代码时,一份resultMap能够代替实现同等功能的长达数千行的代码

    • ResultMap的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了

    • 你已经见过简单映射的语句的示例了,但并没有显式指定resultMap。比如:

      <select id="selectUserById" resultType="map">
      select id , name , pwd from user
      </select>
      
    • 上述语句只是简单地将所有的列映射到HashMap的键上,这由resultType属性指定。虽然在大部分情况下都够用,但是HashMap不是一个很好的模型。你的程序更可能会使用JavaBean或POJO(Plain Old Java Objects,普通老式Java对象)作为模型

  2. 手动映射

    1. 返回值类型为:resultMap

      <select id="selectUsers" resultMap="UserMap">
          select id,name,pwd  from USER
      </select>
      
    2. 编写resultMap,实现手动映射

      <!--id:与sql语句中的resultType对应-->
      <!--type:实体类类型-->
      <resultMap id="UserMap" type="user">
          <!-- id为主键 -->
          <id column="id" property="id"/>
          <!-- column是数据库表的列名 , property是对应实体类的属性名 -->
          <result column="name" property="name"/>
          <result column="pwd"  property="password" />
      </resultMap>
      
10.日志工厂

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

  • 如果一个 数据库相关的操作出现了问题,我们可以根据输出的SQL语句快速排查问题。

  • 对于以往的开发过程,我们会经常使用到debug模式来调节,跟踪我们的代码执行过程。但是现在使用Mybatis是基于接口,配置文件的源代码执行过程。因此,我们必须选择日志工具来作为我们开发,调节程序的工具。

  • Mybatis内置的日志工厂提供日志功能,具体的日志实现有以下几种工具:

    • SLF4J
    • Apache Commons Logging
    • Log4j 2
    • Log4j
    • JDK logging
  • 具体选择哪个日志实现工具由MyBatis的内置日志工厂确定。它会使用最先找到的(按上文列举的顺序查找)。如果一个都未找到,日志功能就会被禁用。

    1. 标准日志实现

      <settings>
          <!--标准的日志工厂实现-->
          <setting name="logImpl" value="STDOUT_LOGGING"/>
      </settings>
      
    2. Log4j

      1. 简介:

        • Log4j是Apache的一个开源项目
        • 通过使用Log4j,我们可以控制日志信息输送的目的地:控制台,文本,GUI组件…
        • 我们也可以控制每一条日志的输出格式
        • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码
      2. 使用步骤

        1. 导入log4j的包

          <dependency>
             <groupId>log4j</groupId>
             <artifactId>log4j</artifactId>
             <version>1.2.17</version>
          </dependency>
          
        2. 配置文件的编写

          #将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
          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=[%c]-%m%n
          
          #文件输出的相关设置
          log4j.appender.file = org.apache.log4j.RollingFileAppender
          log4j.appender.file.File=./log/zc.log
          log4j.appender.file.MaxFileSize=10mb
          log4j.appender.file.Threshold=DEBUG
          log4j.appender.file.layout=org.apache.log4j.PatternLayout
          log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
          
          #日志输出级别
          log4j.logger.org.mybatis=DEBUG
          log4j.logger.java.sql=DEBUG
          log4j.logger.java.sql.Statement=DEBUG
          log4j.logger.java.sql.ResultSet=DEBUG
          log4j.logger.java.sql.PreparedStatement=DEBUG
          
        3. setting设置日志实现

          <settings>
             <setting name="logImpl" value="LOG4J"/>
          </settings>
          
        4. 在程序中使用Log4j进行输出

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

5.分页查询

  1. mybatis-03\src\main\java\com\zc\mapper\UserMapper.java

    //分页查询
    List<User> selectUsersByLimit(Map<String,Integer> map);
    
  2. mybatis-03\src\main\java\com\zc\mapper\UserMapper.xml

    <!--id:与sql语句中的resultType对应-->
    <!--type:实体类类型-->
    <resultMap id="UserMap" type="user">
        <!-- id为主键 -->
        <id column="id" property="id"/>
        <!-- column是数据库表的列名 , property是对应实体类的属性名 -->
        <result column="name" property="name"/>
        <result column="pwd"  property="password" />
    </resultMap>
    
    <!--分页查询-->
    <select id="selectUsersByLimit" resultMap="UserMap" parameterType="map">
        SELECT * from user LIMIT #{startIndex},#{pageSize}
    </select>
    
  3. 测试

    @Test
    public void selectUsersByLimit(){
        SqlSession session = MybatisUtils.getSession();
    
        UserMapper mapper = session.getMapper(UserMapper.class);
        Map<String,Integer> map = new HashMap<String,Integer>();
        map.put("startIndex",2);
        map.put("pageSize",3);
        List<User> userList = mapper.selectUsersByLimit(map);
        for (User user : userList) {
            System.out.println(user);
        }
        session.close();
    }
    

6.使用注解开发

1.入门
  1. mybatis-04\src\main\resources\mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    
        <!--default:通过环境的id,指定默认使用的环境-->
        <environments default="development">
            <!--每个环境对应一个id-->
            <environment id="development">
                <!--配置事务管理器, type指定事务管理器的类型-->
                <transactionManager type="JDBC"/>
                <!--配置数据源, type指定数据源类型-->
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                    <property name="username" value="root"/>
                    <property name="password" value="ZC520"/>
                </dataSource>
            </environment>
        </environments>
    
        <mappers>
            <mapper class="com.zc.mapper.UserMapper"></mapper>
        </mappers>
    </configuration>
    
  2. mybatis-04\src\main\java\com\zc\pojo\User.java

    @Alias("user")
    public class User {
        private int id;
        private String name;
        private String pwd;
    }
    
  3. mybatis-04\src\main\java\com\zc\mapper\UserMapper.java

    public interface UserMapper {
        //查询所有用户
        @Select("select * from user")
        List<User> selectUsers();
    }
    
  4. mybatis-04\src\main\java\com\zc\utils\MybatisUtils.java

    public class MybatisUtils {
        private static SqlSessionFactory sqlSessionFactory;
        static {
            try {
                String resource = "mybatis-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //获取SqlSession连接
        public static SqlSession getSession(){
            return sqlSessionFactory.openSession(true);
        }
    }
    
  5. 测试

    public class UserMapperTest {
        @Test
        public void test(){
            SqlSession session = MybatisUtils.getSession();
    
            UserMapper mapper = session.getMapper(UserMapper.class);
            List<User> users = mapper.selectUsers();
            for (User user : users) {
                System.out.println(user);
            }
    
            session.close();
        }
    }
    
2.CRUD
  1. 通过id查询用户

    • UserMapper

      //通过id查询用户
      @Select("select * from user where id = #{uid}")
      User selectUserById(@Param("uid") int id);
      
  2. 增加一个用户

    • UserMapper

      //增加一个用户
      @Insert("insert into user(id,name,pwd) values (#{id},#{name},#{pwd})")
      int addUser(User user);
      
  3. 删除一个用户

    • UserMapper

      //删除一个用户
      @Delete("delete from user where id = #{id}")
      int delUserById(@Param("id") int id);
      
  4. 修改用户信息

    • UserMapper

      //修改用户信息
      @Update("update user set name = #{name},pwd=#{pwd} where id = #{id}")
      int updateUser(User user);
      
3.补充:关于@Parma()注解
  • 基本类型的参数或者String类型,建议加上
  • 引用类型不需要加
  • 如果只有一个基本类型的话,可以忽略
  • 在SQL中引用的是@Param()中设定的属性名

7.一对多

1.环境搭建
  1. 数据库

    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');
    
  2. mybatis-05\src\main\resources\mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    
        <!--default:通过环境的id,指定默认使用的环境-->
        <environments default="development">
            <!--每个环境对应一个id-->
            <environment id="development">
                <!--配置事务管理器, type指定事务管理器的类型-->
                <transactionManager type="JDBC"/>
                <!--配置数据源, type指定数据源类型-->
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                    <property name="username" value="root"/>
                    <property name="password" value="ZC520"/>
                </dataSource>
            </environment>
        </environments>
    
        <mappers>
            <mapper resource="./mapper/TeacherMapper.xml"></mapper>
            <mapper resource="./mapper/StudentMapper.xml"></mapper>
    
        </mappers>
    
    </configuration>
    
  3. mybatis-05\src\main\java\com\zc\utils\MyBatisUtils.java

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    
        <!--default:通过环境的id,指定默认使用的环境-->
        <environments default="development">
            <!--每个环境对应一个id-->
            <environment id="development">
                <!--配置事务管理器, type指定事务管理器的类型-->
                <transactionManager type="JDBC"/>
                <!--配置数据源, type指定数据源类型-->
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                    <property name="username" value="root"/>
                    <property name="password" value="ZC520"/>
                </dataSource>
            </environment>
        </environments>
    
        <mappers>
            <mapper resource="./mapper/TeacherMapper.xml"></mapper>
            <mapper resource="./mapper/StudentMapper.xml"></mapper>
    
        </mappers>
    
    </configuration>
    
  4. mybatis-05\src\main\java\com\zc\pojo\Teacher.java

    @Data
    public class Teacher {
        private int id;
        private String name;
    }
    
  5. mybatis-05\src\main\java\com\zc\pojo\Student.java

    @Data
    public class Student {
        private int id;
        private String name;
        //多个学生可以是一个老师,即多对一
        private Teacher teacher;
    }
    
  6. mybatis-05\src\main\java\com\zc\mapper\TeacherMapper.java

    public interface TeacherMapper {
    }
    
  7. mybatis-05\src\main\java\com\zc\mapper\StudentMapper.java

    public interface StudentMapper {
    }
    
  8. mybatis-05\src\main\resources\mapper\StudentMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <!--namespace:sql语句映射的接口-->
    <mapper namespace="com.zc.mapper.StudentMapper">
    
    </mapper>
    
  9. mybatis-05\src\main\resources\mapper\TeacherMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <!--namespace:sql语句映射的接口-->
    <mapper namespace="com.zc.mapper.TeacherMapper">
    
    </mapper>
    
2.查询学生数据,多对一查询
  • mybatis-05\src\main\java\com\zc\mapper\StudentMapper.java

    public interface StudentMapper {
    
        //获取所有学生
        public List<Student> getStudents();
    
        //获取所有学生2
        public List<Student> getStudents2();
    }
    
  1. 第一种:按查询嵌套

    mybatis-05\src\main\resources\mapper\StudentMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <!--namespace:sql语句映射的接口-->
    <mapper namespace="com.zc.mapper.StudentMapper">
    
        <!--
     需求:获取所有学生及对应老师的信息
     思路:
         1. 获取所有学生的信息
         2. 根据获取的学生信息的老师ID->获取该老师的信息
         3. 思考问题,这样学生的结果集中应该包含老师,该如何处理呢,数据库中我们一般使用关联查询?
             1. 做一个结果集映射:StudentTeacher
             2. StudentTeacher结果集的类型为 Student
             3. 学生中老师的属性为teacher,对应数据库中为tid。
                多个 [1,...)学生关联一个老师=> 一对一,一对多
             4. 查看官网找到:association – 一个复杂类型的关联;使用它来处理关联查询
     -->
        <select id="getStudents" resultMap="StudentTeacher">
            select * from student
        </select>
        <resultMap id="StudentTeacher" type="com.zc.pojo.Student">
            <!--association关联属性 property属性名 javaType属性类型 column在多的一方的表中的列名-->
            <association property="teacher"  column="tid" javaType="com.zc.pojo.Teacher" select="selectTeachers"/>
        </resultMap>
        <!--
        这里传递过来的id,只有一个属性的时候,下面可以写任何值
        association中column多参数配置:
            column="{key=value,key=value}"
            其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的字段名。
        -->
        <select id="selectTeachers" resultType="com.zc.pojo.Teacher">
            select * from teacher where id = #{id}
        </select>
    </mapper>
    
  2. 第二种:按结果嵌套

    mybatis-05\src\main\resources\mapper\StudentMapper.xml

    <mapper namespace="com.zc.mapper.StudentMapper">
        <select id="getStudents2" resultMap="StudentTeacher2">
            select s.id sid,s.name sname , t.name tname,t.id tid
            from student s, teacher t
            WHERE s.tid = t.id
        </select>
    
        <resultMap id="StudentTeacher2" type="com.zc.pojo.Student">
            <id property="id" column="sid"/>
            <result property="name" column="sname"/>
            <association property="teacher" javaType="com.zc.pojo.Teacher">
                <result property="id" column="tid"/>
                <result property="name" column="tname"/>
            </association>
        </resultMap>
    </mapper>
    

8.多对一

1.实体类修改
  • mybatis-06\src\main\java\com\zc\pojo\Teacher.java

    @Data
    public class Teacher {
        private int id;
        private String name;
    
        private List<Student> students;
    }
    
  • mybatis-06\src\main\java\com\zc\pojo\Student.java

    @Data
    public class Student {
        private int id;
        private String name;
        //多个学生可以是一个老师,即多对一
        private int tid;
    }
    
2.查询老师数据,一对多查询
  • mybatis-06\src\main\java\com\zc\mapper\TeacherMapper.java

    public interface TeacherMapper {
    
        List<Teacher> getTeachers();
    
        List<Teacher> getTeachers2();
    }
    
  1. 按结果嵌套处理

    mybatis-06\src\main\resources\mapper\TeacherMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <!--namespace:sql语句映射的接口-->
    <mapper namespace="com.zc.mapper.TeacherMapper">
        <select id="getTeachers" resultMap="TeacherStudent">
            SELECT
                t.id   tid,
                t.name tname,
                s.id   sid,
                s.name sname
            FROM teacher t, student s
            WHERE t.id = s.tid
        </select>
    
        <resultMap id="TeacherStudent" type="com.zc.pojo.Teacher">
            <result property="id" column="tid"/>
            <result property="name" column="tname"/>
            <collection property="students" ofType="com.zc.pojo.Student">
                <result property="id" column="sid"/>
                <result property="name" column="sname"/>
                <result property="tid" column="tid"/>
            </collection>
        </resultMap>
    </mapper>
    
  2. 按查询嵌套处理

    mybatis-06\src\main\resources\mapper\TeacherMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!--namespace:sql语句映射的接口-->
    <mapper namespace="com.zc.mapper.TeacherMapper">
        <!--按查询嵌套-->
        <select id="getTeachers2" resultMap="TeacherStudent2">
            SELECT * from teacher
        </select>
    
        <resultMap id="TeacherStudent2" type="com.zc.pojo.Teacher">
            <result property="id" column="id"/>
            <collection property="students" javaType="ArrayList" ofType="com.zc.pojo.Student" select="getStudentByTeacherId" column="id"/>
        </resultMap>
    
        <select id="getStudentByTeacherId" resultType="com.zc.pojo.Student">
            SELECT * from student WHERE tid = #{tid}
        </select>
    </mapper>
    
  3. 小结

    1. 关联-association:用于一对一和多对一
    2. 集合-collection:用于一对多
    3. JavaType和ofType用来指定对象类型
      • JavaType用来指定pojo中属性的类型
      • ofType指定的是映射到list集合属性中pojo类型

9.动态SQL

1.定义
  • 我们之前写的 SQL 语句都比较简单,如果有比较复杂的业务,我们需要写复杂的 SQL 语句,往往需要拼接,而拼接 SQL ,稍微不注意,由于引号,空格等缺失可能都会导致错误。
  • 那么怎么去解决这个问题呢?这就要使用 mybatis 动态SQL,通过 if, choose, when, otherwise, trim, where, set, foreach等标签,可组合成非常灵活的SQL语句,从而在提高 SQL 语句的准确性的同时,也大大提高了开发人员的效率。
2.环境搭建
  1. mybatis-07\src\main\resources\mybatis-config.xml

    <settings>
        <!--数据库命名A_B和Java驼峰命名aB的自动映射-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    
    <typeAliases>
        <!--起别名-->
        <typeAlias type="com.zc.pojo.Blog" alias="blog"></typeAlias>
    </typeAliases>
    
  2. mybatis-07\src\main\java\com\zc\pojo\Blog.java

    @Data
    public class Blog {
        private String id;
        private String title;
        private String author;
        private Date createTime;
        private int views;
    }
    
  3. mybatis-07\src\main\java\com\zc\utils\IDUtil.java

    public class IDUtil {
        //获取随机id
        public static String getId(){
            return UUID.randomUUID().toString().replaceAll("-","");
        }
    }
    
  4. mybatis-07\src\main\java\com\zc\utils\MyBatisUtils.java

  5. mybatis-07\src\main\java\com\zc\mapper\BlogMapper.java

    public interface BlogMapper {
    }
    
  6. mybatis-07\src\main\resources\mapper\BlogMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <!--namespace:sql语句映射的接口-->
    <mapper namespace="com.zc.mapper.BlogMapper">
    </mapper>
    
3.IF
  1. mybatis-07\src\main\java\com\zc\mapper\BlogMapper.java

    public interface BlogMapper {
    
        //查询博客信息
        List<Blog> queryBlogIF(Map map);
    }
    
  2. mybatis-07\src\main\resources\mapper\BlogMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <!--namespace:sql语句映射的接口-->
    <mapper namespace="com.zc.mapper.BlogMapper">
    
        <select id="queryBlogIF" parameterType="map" resultType="blog">
            select *
            from mybatis.blog
            WHERE 1=1
            <if test="title != null">
                AND title = #{title}
            </if>
            <if test="author != null">
                AND author = #{author}
            </if>
        </select>
    </mapper>
    
4.Where
  1. where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除

  2. mybatis-07\src\main\resources\mapper\BlogMapper.xml

    <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>
    

5.set

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

  2. mybatis-07\src\main\resources\mapper\BlogMapper.xml

    <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>
    

6.Choose

  1. 有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

  2. mybatis-07\src\main\resources\mapper\BlogMapper.xm

    <select id="queryBlogChoose" parameterType="map" resultType="blog">
        SELECT * FROM mybatis.blog
        <where>
            <choose>
                <when test="title != null">
                    title = #{title}
                </when>
                <when test="author != null">
                    and author = #{author}
                </when>
                <when test="views != null">
                    and views = #{views}
                </when>
                <otherwise>
                </otherwise>
            </choose>
        </where>
    </select>
    
5.SQL片段
  1. 有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们可以将这些代码抽取出来,然后使用时直接调用。

  2. 提取SQL片段

    <!--id 用于标识此sql片段-->
    <sql id="if-title-author">
        <if test="title != null">
            title = #{title}
        </if>
        <if test="author != null">
            AND author = #{author}
        </if>
    </sql>
    
  3. 引用SQL片段

    <select id="queryBlogIF" parameterType="map" resultType="blog">
        select *
        from mybatis.blog
        <where>
             <!--引用sql片段,如果refid指定的不在本文件中,那么需要在前面加上namespace-->
            <include refid="if-title-author"></include>
        </where>
    </select>
    
6.Foreach
  1. foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!

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

  3. mybatis-07\src\main\resources\mapper\BlogMapper.xm

    <select id="queryBlogForeach" parameterType="map" resultType="blog">
        SELECT * FROM blog
        <where>
            <!--
                collection:指定输入对象中的集合属性
                item:每次遍历生成的对象
                open:开始遍历时的拼接字符串
                close:结束时的拼接字符串
                separator:遍历对象之间需要拼接的字符串
                -->
            <foreach collection="ids" item="id" open="(" close=")" separator="or">
                id=#{id}
            </foreach>
        </where>
    </select>
    

10.缓存

1.什么是缓存
  • 存在内存中的临时数据。
  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询。从缓存中查询,可以提高查询效率,解决了高并发系统的性能问题。
2.为什么使用缓存
  • 减少和数据库的交互次数,减少系统开销,提高系统效率。
3.什么样的数据能使用缓存
  • 经常查询并且不经常改变的数据
4.MyBatis缓存
  • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。

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

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

一级缓存也叫本地缓存:

  • 与数据库同一次会话期间查询到的数据会放在本地缓存中。
  • 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;
6.二级缓存
  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存

  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;

  • 工作机制

  • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;

    • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
    • 新的会话查询信息,就可以从二级缓存中获取内容;
    • 不同的mapper查出的数据会放在自己对应的缓存(map)中;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小张加加加油!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值