本文已参与「新人创造礼」活动,一同敞开创造之路。

Mybatis

环境

  • JDK1.8
  • Mysql5.7
  • maven3.6.1
  • IDEA

回忆

  • JDBC
  • Mysql
  • Java根底
  • Maven
  • Junit

ssm结构:装备文件的,最好的办法:看官网文档

1.简介

1.1什么是Mybatis

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

怎么取得Mabatis?

  • maven库房

    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.10</version>
    </dependency>
  • Github:Releases mybatis/mybatis-3 (github.com)

  • 中文文档:MyBatis中文网

1.2耐久层

数据耐久化

  • 耐久化便是将程序的数据在耐久状况和瞬时状况转化的进程

  • 内存:断电即失

  • 数据库(jdbc) io文件耐久化

  • 生活:冷藏 罐头

    为什么需求耐久化?

    • 有一些目标,不能让他丢掉
    • 内存太贵了

1.3耐久层

Dao层 Service层 Controller层

  • 完成耐久化作业的代码块
  • 层边界十分明显

1.4为什么需求Mybaits

  • 协助程序员将数据存入到数据库中

  • 便利

  • 传统的JDBC代码太杂乱了,简化,结构,主动化

  • 长处:

    • 简略易学:自身就很小且简略。没有任何第三方依靠,最简略装置只需两个jar文件+装备几个sql映射文件。易于学习,易于运用。经过文档和源代码,能够比较完全的把握它的规划思路和完成。
    • 灵活:mybatis不会对应用程序或许数据库的现有规划强加任何影响。 sql写在xml里,便于统一管理和优化。经过sql句子能够满足操作数据库的一切需求。
    • 免除sql与程序代码的耦合:经过提供DAO层,将事务逻辑和数据访问逻辑分离,使体系的规划更明晰,更易保护,更易单元测验。sql和代码的分离,进步了可保护性。
    • 提供映射标签,支撑目标与数据库的orm字段联系映射。
    • 提供目标联系映射标签,支撑目标联系组建保护。
    • 提供xml标签,支撑编写动态sql。

2.第一个Mybatis程序

思路:建立环境–>导入Mybatis–>编写代码–>测验

2.1建立环境

建立数据库

CREATE DATABASE mybatis;
​
USE ‘mybatis‘;
​
CREATE TABLEuser‘(
    ‘id‘ INT(20) NOT NULL PRIMARY KEY,
    ‘name‘ VARCHAR(30) DEFAULT NULL,
    ‘pwd‘ VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;
​
INSERT INTOuser‘(‘id‘ ,‘name‘,‘pwd‘) VALUES
(1,'饼干1号','123456'),
(2,'饼干3号','123456'),
(3,'饼干3号','123456')

新建项目

1.新建一个一般的maven项目

2.删去src目录

3.导入maven依靠

<!--导入依靠-->
  <dependencies>
    <!--mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.47</version>
    </dependency><!--mybatis-->
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.10</version>
    </dependency><!--junit-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
    </dependency>
  </dependencies>

2.2创立一个模块

  • 编写mybatis的中心装备文件

    <?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中心装备文件-->
    <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"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
          </dataSource>
        </environment>
      </environments>
    </configuration>
    
  • 编写mybatis的东西类

    //SqlSessionFactory SqlSession
    public class MybatisUtils {
      private static SqlSessionFactory sqlSessionFactory;
      static {
        try {
          //运用Mybatis 第一步:获取SqlSessionFactory目标
          String resource = "mybatis-config.xml";
          InputStream inputStream = Resources.getResourceAsStream(resource);
          SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
         } catch (IOException e) {
          e.printStackTrace();
         }
       }
    ​
    //   既然有了 SqlSessionFactory,望文生义,咱们能够从中取得 SqlSession 的实例。
    //   SqlSession 提供了在数据库履行 SQL 命令所需的一切办法
      public static SqlSession getSqlSession(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        return sqlSession;
       }
    }
    

2.3编写代码

  • 实体类

    package com.he.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 {
      List<User> getUserList();
    }
    
  • 接口完成类由本来的UserDaoImpl转变成一个Mapper装备文件

    <?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=绑定一个对应的Dao/Mapper接口-->
    <mapper namespace="com.he.Dao.UserDao">
      <select id="getUserList" resultType="com.he.pojo.User">
      select * from mybatis.user
     </select>
    </mapper>
    

2.4测验

MapperRegister是什么?

中心装备文件中注册mappers

  • junit测验

    public class UserDaoTest {
      @Test
      public void test(){
    //    第一步:取得sqkSession目标
        SqlSession sqlSession = MybatisUtils.getSqlSession();
    //     第二步:履行sql
    //     办法一:getMapper
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> userList = userDao.getUserList();
        for (User user : userList) {
          System.out.println(user);
         }
    ​
    //     封闭sqlSession
        sqlSession.close();
       }
    }
    ​
    

问题:

  1. 装备文件没有注册
  2. 绑定接口过错
  3. 办法名过错
  4. 回来类型不对
  5. Maven导出资源问题

在之前版本的 MyBatis 中, 命名空间(Namespaces)的效果并不大,是可选的。 但现在,跟着命名空间越发重要,你有必要指定命名空间。

  • 全限定名(比方 “com.mypackage.MyMapper.selectAllThings)将被直接用于查找及运用。
  • 短称号(比方 “selectAllThings”)假如大局仅有也能够作为一个独自的引证。 假如不仅有,有两个或两个以上的相同称号(比方 “com.foo.selectAllThings” 和 “com.bar.selectAllThings”),那么运用时就会产生“短称号不仅有”的过错,这种状况下就有必要运用全限定名。

SqlSessionFactoryBuilder

这个类能够被实例化、运用和丢掉,一旦创立了 SqlSessionFactory,就不再需求它了。 因此 SqlSessionFactoryBuilder 实例的最佳效果域是办法效果域(也便是局部办法变量)。 你能够重用 SqlSessionFactoryBuilder 来创立多个 SqlSessionFactory 实例,但最好仍是不要一向保留着它,以确保一切的 XML 解析资源能够被释放给更重要的工作。

SqlSessionFactory

SqlSessionFactory 一旦被创立就应该在应用的运转期间一向存在,没有任何理由丢掉它或重新创立另一个实例。 运用 SqlSessionFactory 的最佳实践是在应用运转期间不要重复创立多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳效果域是应用效果域。 有许多办法能够做到,最简略的便是运用单例形式或许静态单例形式。

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的效果域是恳求或办法效果域。 绝对不能将 SqlSession 实例的引证放在一个类的静态域,乃至一个类的实例变量也不可。 也绝不能将 SqlSession 实例的引证放在任何类型的托管效果域中,比方 Servlet 结构中的 HttpSession。 假如你现在正在运用一种 Web 结构,考虑将 SqlSession 放在一个和 HTTP 恳求类似的效果域中。 换句话说,每次收到 HTTP 恳求,就能够打开一个 SqlSession,回来一个响应后,就封闭它。 这个封闭操作很重要,为了确保每次都能履行封闭操作,你应该把这个封闭操作放到 finally 块中。下面的示例便是一个确保 SqlSession 封闭的标准形式:

try (SqlSession session = sqlSessionFactory.openSession()) {
 // 你的应用逻辑代码
}

3.CRUD

1.命名空间

namespace中的包名要和Dao/mapper接口中的包名一致

2.select

选择 查询句子

  • id:便是对应的namespace中的办法名
  • resultType:sql句子履行的回来值
  • parameterType:参数类型

1.编写接口

//   查询悉数用户
  List<User> getUserList();

2.编写对应的sql句子

 <!--select查询句子-->
  <select id="getUserList" resultType="com.he.pojo.User">
     select * from mybatis.user
 </select>

3.测验

 @Test
  public void getUserById(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);
    User user = mapper.getUserById(1);
    System.out.println(user);
    sqlSession.close();
   }

3.insert

 <!--目标中的特点,能够直接取出来-->
  <insert id="addUser" parameterType="com.he.pojo.User" >
     insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd})
  </insert>
//   insert一个用户
  int addUser(User user);
 public void addUser(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);
    int res = mapper.addUser(new User(4,"饼干4号","123456"));
    if(res>0){
      System.out.println("插入成功!");
     }
​
//     提交事务
    sqlSession.commit();
    sqlSession.close();
   }

4.update

 <update id="updateUser" parameterType="com.he.pojo.User">
        update mybatis.user set name=#{name} ,pwd=#{pwd}   where id=#{id}
    </update>
//    修正用户
    int updateUser(User user);
    @Test
public  void updateUser(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);
    mapper.updateUser(new User(4,"石头1号","123456"));
    sqlSession.commit();
    sqlSession.close();
}

5.delete

<delete id="deleteUser" parameterType="int" >
        delete from mybatis.user where id = #{id}
    </delete>
//    删去一个事务
    int deleteUser(int id);
}
  @Test
    public void deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        mapper.deleteUser(4);
        sqlSession.commit();
        sqlSession.close();
    }

留意:增修改需求提交事务

6.标签不要匹配错

  • 标签不要写错
  • resource绑定mapper,需求运用路径
  • 程序装备文件有必要符合规范
  • 空指针反常,没有注册到资源
  • maven资源没有导出问题

7.全能的Map

假定,咱们的实体类,或许数据库中的表,字段或许参数过多,咱们应当考虑运用Map

    int addUser2(Map<String, Object> map);
   <insert id="addUser2" parameterType="map" >
        insert into mybatis.user (id, name, pwd) values (#{userid},#{username},#{passWord})
    </insert>
  @Test
    public void addUser2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("userid",5);
        map.put("username","饼干5号");
        map.put("passWord","123456");
        mapper.addUser2(map);
        sqlSession.commit();
        sqlSession.close();
    }

Map传递参数,直接在sql中取出key即可

目标传递参数,直接在sql中取目标的特点即可

只需一个根本类型参数的状况下,能够直接在sql中取到

多个参数用Map,或许注解

8.思考题:

含糊查询怎么写?

  1. java代码履行的时分,传递通配符% %

    List<User> userList = userDao.getUserLike("%饼干%");
    
  2. 在sql拼接中运用通配符

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

4.装备解析

1.中心装备文件

  • mybatis-congfig.xml

  • MyBatis 的装备文件包含了会深深影响 MyBatis 行为的设置和特点信息。

  • configuration(装备)

    • properties(特点)

    • settings(设置)

    • typeAliases(类型别号)

    • typeHandlers(类型处理器)

    • objectFactory(目标工厂)

    • plugins(插件)

    • environments(环境装备)

      • environment(环境变量)

        • transactionManager(事务管理器)
        • dataSource(数据源)
    • databaseIdProvider(数据库厂商标识)

    • mappers(映射器)

2.环境变量(environments)

MyBatis 能够装备成习惯多种环境

不过要记住:尽管能够装备多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

学会运用多套运转环境

Mybatis默许的事务管理器便是JDBC,连接池:POOLED

3.特点(properties)

咱们能够经过properties特点来完成引证装备文件

这些特点能够在外部进行装备,并能够进行动态替换。你既能够在典型的 Java 特点文件中装备这些特点,也能够在 properties 元素的子元素中设置

编写一个装备文件

db.properties

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

在中心装备文件中映入

   <!--引入外部装备文件-->
    <properties resource="db.properties">
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </properties>
  • 能够直接引入外部文件
  • 能够在其间添加一些特点装备
  • 假如两个文件有同一个字段,优先运用外部装备文件的

4.类型别号([typeAliases)

  • 类型别号可为 Java 类型设置一个缩写姓名
  • 它仅用于 XML 装备,意在降低冗余的全限定类名书写。
<!--能够给实体类起别号-->
<typeAliases>
    <typeAlias type="com.he.pojo.User" alias="User"/>
</typeAliases>

也能够指定一个包名,MyBatis 会在包名下面查找需求的 Java Bean

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

  <typeAliases>
        <package name="com.he.pojo"/>
    </typeAliases>

在实体类比较少的时分,运用第一种办法

假如实体类十分多,主张运用第二种

第一种能够diy别号,第二种则不可,假如非要改,需求在实体类上添加注释

5.设置

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

6.其他装备

  • typeHandlers(类型处理器)]

  • objectFactory(目标工厂)

  • plugins(插件)

    • mybatis-generator-core
    • mybatis-plus
    • 通用mapper

7.映射器(mappers)

MapperRegistry:注册绑定咱们的Mapper文件

办法一:

 <!--每一个Mapper.xml都需求在mybatis中心装备文件中注册-->
<mappers>
        <mapper resource="com/he/dao/UserMapper.xml"/>
    </mappers>

办法二:

 <mappers>
        <mapper class="com.he.dao.UserMapper"/>
    </mappers>

留意:

  • 接口和他的Mapper装备文件有必要同名
  • 接口和他的Mapper装备文件有必要在同一个包下

办法三:

运用扫描包进行注入绑定

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

8.生命周期和效果域

生命周期类别是至关重要的,因为过错的运用会导致十分严峻的并发问题。

SqlSessionFactoryBuilder

  • 一旦创立了SqlSessionFactory,就不再需求它了
  • 局部变量

SqlSessionFactory

  • 说白了便是能够幻想为:数据库连接池
  • SqlSessionFactory 一旦被创立就应该在应用的运转期间一向存在 ,没有任何理由丢掉它或重新创立另一个实例。
  • SqlSessionFactory 的最佳效果域是应用效果域
  • 最简略的便是运用单例形式或许静态单例形式。

SqlSession

  • 连接到连接池的一个恳求
  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的效果域是恳求或办法效果域
  • 用完之后需求赶忙封闭,不然资源被占用

这儿面的每一个Mapper,就代表一个详细的事务

5.解决特点名和字段名不一致的问题

1.问题

数据库中的字段

新建一个项目,复制之前的,测验实体类字段不一致的状况

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

测验呈现问题

解决办法:

  • 起别号

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

2.resultMap

成果集映射

id name pwd
id name password
<resultMap id="UserMap" type="User">
    <result column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="pwd" property="password"/>
</resultMap>
<select id="getUserById"  resultType="UserMap">
    select *  from mybatis.user where id = #{id}
</select>
  • resultMap 元素是 MyBatis 中最重要最强壮的元素。
  • ResultMap 的规划思想是,对简略的句子做到零装备,关于杂乱一点的句子,只需求描绘句子之间的联系就行了。
  • ResultMap 的优异之处——你完全能够不用显式地装备它们

6.日志

1.日志工厂

假如一个数据库操作呈现了反常,咱们需求排错,日志便是最好的帮手

从前:sout debug

现在:日志工厂

  • SLF4J
  • LOG4J 【把握】
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING 【把握】
  • NO_LOGGING

在Mybatis中详细运用那一个日志完成,在设置中设定

STDOUT_LOGGING 标准日志输出

在mybatis中心装备文件中,装备咱们的日志

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

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

#将等级为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/he.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.装备log4j为日志的完成

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

4.log4j的运用,直接测验运转刚才的查询

简略运用

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

  2. 日志参数,参数为当时类的class

    static Logger logger = Logger.getLogger(UserDaoTest.class);
    
  3. 日志等级

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

7.分页

思考:为什么要分页

  • 减少数据的处理量

1.运用limit分页

语法:select *from user limit startIndex,pageSize;
select *from user limit 3; #[0,n]

运用Mybatis完成分页,中心sql

  1. 接口

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

        <!--分页-->
        <select id="getUserByLimit" parameterType="map" resultType="UserMap">
            select *from mybatis.user limit #{startIndex},#{pageSize}
        </select>
    
  3. 测验

     @Test
        public void GetUserByLimit(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserDao mapper = sqlSession.getMapper(UserDao.class);
            HashMap<String,Integer>map = new HashMap<String,Integer>();
            map.put("startIndex",0);
            map.put("pageIndex",2);
            List<User> userList = mapper.getUserByLimit(map);
            for (User user : userList) {
                System.out.println(user);
            }
            sqlSession.close();
        }
    

2.RoeBounds分页

不再运用sql完成分页

  1. 接口
//    分页2
    List<User> getUserByRowBounds();

2.mapper.xml

<!--分页2-->
<select id="getUserByRowBounds"  resultType="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.he.dao.UserDao.getUserByRowBounds",null,rowBounds);
        for (User user : UserList) {
            System.out.println(user);
        }
        sqlSession.close();
    }

3.分页插件

8.运用注解开发

1.面向接口编程

2.运用注解开发

  1. 注解在接口上完成
    @Select("select * from User")
    List<User> getUsers();

2.需求在中心装备文件中绑定接口

  <!--绑定接口-->
    <mappers>
        <mapper class="com.he.dao.UserDao"/>
    </mappers>

3.测验

本质:反射机制完成

底层:动态署理

Mybatis详细的履行流程

3.CRUD

咱们能够在东西类创立的时分完成主动提交事务

 public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession(true);
    }

编写接口,添加注解

//    办法存在多个参数,
    @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 = #{uid}")
    int delete(@Param("uid")int id);

测验类

留意:咱们有必要要将接口绑定到咱们的中心装备文件中

关于@Param()注解

  • 根本类型的参数或许String类型,需求加上
  • 引证类型不需求加上
  • 假如只需一个根本类型的话,能够忽略,主张加上
  • 咱们在sql中引证的便是咱们这儿的@Param()中设定的特点

9.lombok

Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java. Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.

@Getter and @Setter
@NonNull
@ToString
@EqualsAndHashCode
@Data
@Cleanup
@Synchronized
@SneakyThrows

运用过程:

  1. 在IDEA中装置Lombok插件
  2. 在项目中导入Lombok的jar包
  3. 在实体类上加注解即可

10.多对一处理

  • 多个学生,对应一个学生
  • 关于学生这边而言,相关,多个学生,相关一个学生【多对一】
  • 关于多个学生,调集,一个教师,有许多学生【一对多】
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);

建立测验环境

  1. 导入lombok
  2. 新建实体类Teacher,Student
  3. 建立Mapper接口
  4. 建立Mapper.xml文件
  5. 在中心装备文件中绑定注册咱们的mapper接口或许文件
  6. 测验查询是否能够成功

依照查询嵌套处理

        <!--
        思路:
        1.查询一切的学生信息
        2.依据查询出来的学生的tid,寻找对应的教师
    -->
<select id="getStudent" resultType="Student">
        select * from student
    </select>
    <resultMap id="StudentTeacher" type="Student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
    </resultMap>
    <select id="getTeacher" resultType="Teacher">
        select * from teacher where id = #{id}
    </select>

依照成果嵌套查询

<select id="getStudent2" resultMap="StudentTeacher2">
    select s.id sid ,s,name sname,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="name" column="tname"/>
    </association>
</resultMap>

回忆Mysql多对一查询办法

  • 子查询
  • 联表查询

11.一对多处理

比方:一个教师具有多个学生

关于教师而言,便是一对多的联系

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> students;
}
<!--杂乱的特点,咱们需求独自处理 目标:association 调集: collection
javaType=""指定特点的类型
调集中的泛型信息,咱们运用ofType获取
-->

依照成果嵌套处理

<select id="getTeacher" resultMap="TeacherStudent">
    select s.id sid,s.name sname,t.name tname,t.id tid
    from student s,teacher t
    where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <collection property="students" ofType="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>

依照查询嵌套处理

    <select id="getTeacher2" resultMap="TeacherStudent2">
        select * from mybatis.teacher where id = #{tid}
    </select>
<resultMap id="TeacherStudent2" type="Teacher">
    <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
    select * from mybatis.student where tid = #{tid}
</select>

小结

1.相关-association【多对一】

2.调集-collection【一对多】

3.javaType & ofType

  1. javaType 用来指定实体类中特点的类型
  2. ofType 用来指定映射到list或许调集中的pojo类型,泛型中的约束类型

留意点:

  • 确保sql的可读性,尽量确保通俗易懂
  • 留意一对多和多对一中,特点名和字段的问题
  • 假如问题不好排查过错,能够运用日志,主张运用log4j

面试高频:

  • Mysql引擎
  • InnoDB底层原理
  • 索引
  • 索引优化

12.动态SQL

什么是动态SQL:动态SQL便是指依据不同的条件生成不同的SQL句子

运用动态 SQL 并非一件易事,但凭借可用于任何 SQL 映射句子中的强壮的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
假如你之前用过 JSTL 或任何根据类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需求花时间了解大量的元素。凭借功用强壮的根据 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比本来的一半还要少。
if
choose (when, otherwise)
trim (where, set)
foreach

建立环境

CREATE TABLE blog
(
  id varchar(50) not null comment '博客id',
  title varchar(100) not null comment '博客标题',
  auther varchar(30) not null comment '博客作者',
  create_time datetime not null comment '创立时间',
  view 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 auther;
    private Date create_time;
    private int views;
}

4.编写实体类对应Mapper和Mapper.xml文件

<insert id="addBlog" parameterType="blog">
    insert into mybatis.blog(id, title, author, createTime, views)
     values (#{id}, #{title}, #{author}, #{createTime}, #{views})
</insert>

IF

<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>
 @Test
    public void queryBlogIF(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap map = new HashMap();
//        map.put("title","我是小仙女");
        map.put("author","小何");
        List<Blog> blogs = mapper.queryBlogIF(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }

choose(when,otherwise)

<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>
            <otherwise>
                  and views = #{views}
            </otherwise>
        </choose>
    </where>
</select>

trim(where,set)

<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>
<update id="updateBlog" parameterType="map">
    update mybatis.blog
    <set>
        <if test="title!=null" >
            title = #{title},
        </if>
        <if test="author!=null" >
            author = #{author}
        </if>
    </set>
    where id = #{id}
</update>

所谓的动态SQL,本质仍是SQL句子,仅仅咱们能够在SQL层面,去履行一个逻辑代码

if

where set choose when

foreach

select * from user where 1=1 and
<foreach item="id" index="index" collection="list"
      open="(" separator="or" close=")">
        #{id}
  </foreach>
(id = 1 or id = 2 or id = 3)
<!--
    select *from mybatis.blog where 1=1 and (id = 1 or id = 2 or id = 3)
    咱们现在传递一个全能的map,这map中能够存在一个调集
-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <foreach collection="ids" item="id" open="and (" close=")" separator="or">
            id = #{id}
        </foreach>
     </where>
</select>

SQL片段

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

  1. 运用SQL标签抽取公共的部分

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

<select id="queryBlogIF" parameterType="map" resultType="blog">
        select *from mybatis.blog
        <where>
          <include refid="if-title-author">
          </include>
        </where>
    </select>

留意:

  • 最好根据单表来界说SQL片段
  • 不要存在where标签

动态sql便是在拼接sql句子,咱们只需求确保sql的正确性,依照sql的格局,去排列组合就好了

主张:先在Mysql中写出完整的sql,再对应修正成为咱们的动态sql完成通用即可

13.缓存

1.简介:

查询 :连接数据库 消耗资源
一次查询的成果,给他暂存到一个能够直接取到的地方 --->内存:缓存
咱们再次查询相同的数据的时分,直接走缓存,就不用走数据库了

什么是缓存?

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

为什么运用缓存?

  • 减少和数据库的交互次数,减少体系开支,进步体系功率

什么样的数据能够运用缓存?

  • 常常查询并且不常常改变的数据【能够运用缓存】

2.Myabtis缓存

  • MyBatis包含一个十分强壮的查询缓存特性,它能够十分便利的定制和装备缓存,缓存能够极大的进步查询功率。 MyBatis体系中默许界说了两级缓存:一级缓存和二级缓存 默许状况下,只需一级缓存敞开(SqlSession等级的缓存,也称为本地缓存) 二级缓存需求手动敞开和装备,他是根据namespace等级的缓存。 为了进步可扩展性,MyBatis界说了缓存接口Cache。咱们能够经过完成Cache接口来界说二级缓存。

3.一级缓存

  • 一级缓存也叫本地缓存:SqlSession

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

测验过程:

  1. 敞开日志
  2. 测验在一个Session中查询两次相同的记录
  3. 检查日志输出

缓存失效的状况:

  1. 查询不同的东西
  2. 增修改操作,可能会改变原理的数据,所以必定会改写缓存
  3. 查询不同的Mapper.xml
  4. 手动整理缓存
@Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUsersById(1);
        System.out.println(user);
//        mapper.updateUser(new User(2,"aaa","bbb"));
        sqlSession.clearCache();//手动整理缓存
        System.out.println("==========================");
        User user2 = mapper.queryUsersById(1);
        System.out.println(user2);
        System.out.println(user==user2);
        sqlSession.close();
    }

小结:一级缓存默许是敞开的,只在一次sqlsession中有用,也便是拿到连接到封闭连接这个区间段

一级缓存相当于一个map

4.二级缓存

  • 二级缓存也叫大局缓存,一级缓存效果域太低了,所以诞生了二级缓存;
  • 根据namespace等级的缓存,一个称号空间,对应一个二级缓存;
  • 作业机制
  • 一个会话查询一条数据,这个数据就会被放在当时会话的一级缓存中; 假如当时会话封闭了,这个会话对应的一级缓存就没了;但是咱们想要的是,会话封闭了,一级缓存中的数据被保存到二级缓存中; 新的会话查询信息,就能够从二级缓存中获取内容; 不同的mapper查出的数据就会放在自己对应的缓存(map)中;
  • 过程:
  1. 在mybatis-config.xml敞开大局缓存
<!--显现的敞开大局缓存-->
<setting name="cacheEnabled" value="true"/>

2.在要运用二级缓存的Mapper中敞开

<cache/>

也能够自界说参数

<!--在当时Mapper.xml中运用二级缓存-->
    <cache  eviction="FIFO"
            flushInterval="60000"
            size="512"
            readOnly="true"/>

3.测验

  1. 问题:咱们需求将实体类序列化

小结:

  • 只需敞开了二级缓存,在同一个Mapper下就有用
  • 一切的数据都会先放在一级缓存中
  • 只需当会话提交,或许封闭的时分,才会提交到二级缓存中

5.缓存原理

6 .自界说缓存-ehcache(能够了解)

Ehcache是一种广泛运用的开源Java分布式缓存,首要面向通用缓存。

要在程序中运用ehcache,先要导包!

<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.1.0</version>
        </dependency>

在mapper中指定运用咱们的ehcache缓存完成!

Redis数据库来做缓存

\