Mybaitis入门

Mybaits

环境:

  • JDK1.8
  • Mysql 5.7
  • maven 3.6.3
  • IDEA

回顾

  • JDBC
  • Mysql
  • Java基础
  • Maven
  • Junit

SSM框架 配置文件 最好的方式 看官网文档

https://mybatis.org/mybatis-3/zh/index.html

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。

如何获得Mybaitis

  • Maven仓库

    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>
    
  • Github https://github.com/mybatis/mybatis-3/releases/tag/mybatis-3.5.2

  • 中文文档 https://mybatis.org/mybatis-3/zh/index.html

1.2 持久层

数据持久化

  • 持久化㐊将程序的数据在持久状态(存放在SQL的数据)和瞬时状态(用户获得数据)转化的过程
  • 内存 断电既失
  • 数据库(JDBC) io文件持久化
  • 生活 冷藏 罐头

为什么需要持久化?

  • 有一些对象 不能让他丢掉

  • 内存太贵了

1.3 持久层

Dao层 service层 controller层…

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

1.4 为什么需要Mybatis

  • 方便
  • 传统的JDBC代码太复杂了 简化 框架
  • 帮助程序员将数据存入到数据库中
  • 不用Mybatis 更容易上手 技术没有高低之分
  • 优点
    • 简单易学
    • 灵活
    • sql和代码的分离,提高了可维护性。
    • 提供映射标签,支持对象与数据库的orm字段关系映射
    • 提供对象关系映射标签,支持对象关系组建维护
    • 提供xml标签,支持编写动态sql。

最重要的一点:使用的人多

spring springMVC

2.第一个mybatis程序

思路 搭建环境–>导入mybatis–>编写代码–>测试

2.1搭建环境

搭建数据库

CREATE DATABASE `mybatis`
USE mybatis
CREATE TABLE `user`(
`id` INT(20) NOT NULL ,
`name` VARCHAR(10) DEFAULT NULL,
`pwd` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY(`id`)

)ENGINE=INNODB DEFAULT CHARSET=utf8 ;

INSERT INTO `user`(id,`name`,`pwd`) VALUES(1,'林宏程','1'),(2,'我','1'),(3,'你','1')

新建项目

  1. 新建一个普通的maven项目

  2. 删除src目录

  3. 导入maven依赖

    <dependencies>
        
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.31</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=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
    
                </dataSource>
            </environment>
        </environments>
    <!--    每一个Mapper.xml都需要在Mybatis核心配置文件中注册-->
    <mappers>
        <mapper resource="com/lhc/dao/userMapper.xml"/>
    </mappers>
    
    </configuration>
    
  • 编写mybatis工具类

    package com.lhc.utils;
    
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    //sqlSessionFactory -->sqlSession
    public class MybatisUtils {
        private static SqlSessionFactory SqlSessionFactory;
    
    
        static {
            try {
                //1.获取使用 sqlSessionFactory 对象
                String resource = "mybatis-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                SqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
            
        }
    
        //既然有了SqlSessionFactory 顾名思义 我们就可以从中获得SqlSession的实例了
        //SqlSession完全包含了面向数据库执行sql命令所需要的所有方法
    
        public static SqlSession getSqlSession() {
            //获得 sqlSession对象
            return SqlSessionFactory.openSession();
        }
    }
    

2.3编写代码

  • 实体类

    package com.lhc.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接口

    package com.lhc.dao;
    
    import com.lhc.pojo.User;
    
    import java.util.List;
    
    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.lhc.dao.UserDao">
        <!--查询语句-->
        <!--id 相当于 重写接口的方法名 之前在Dao层实现的方法名-->
        <select id="getUserList" resultType="com.lhc.pojo.User">
            SELECT * FROM mybatis.user
        </select>
    </mapper>
    

2.4测试

核心配置文件中注册 mappers

  • Junit测试

    package com.lhc.Dao;
    
    import com.lhc.dao.UserDao;
    import com.lhc.pojo.User;
    import com.lhc.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import java.util.List;
    
    public class UserDaoTest {
        @Test
        public void Test(){
            //1.获取sqlSession对象
            SqlSession sqlSession = MybatisUtils.getSqlSession();
    
            //2.方式1  这里其实相当也先前执行DaoImpl的实现类
            UserDao mapper = sqlSession.getMapper(UserDao.class);
            List<User> userList = mapper.getUserList();
    
            for (User user : userList) {
                System.out.println(user);
            }
    
            //3.用完关闭
            sqlSession.close();
        }
    }
    

可能遇到的问题

  1. 配置文件没有注册

  2. 绑定接口错误

  3. 方法名不对

  4. 返回类型不对

  5. Maven导出资源问题 (resources和java目录下的文件打包)

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

3.CRUD

1.namespace

namespace中的包名要和接口的包名一致!

2.select

选择 查询语句

  • id 重写接口的方法名 之前在Dao层实现的方法名
  • resultType sql执行返回值的类型
  • parameterType 传入参数的类型

1.编写接口

//根据ID查询用户
User getUserId(int id);

2.编写对应的mapper中的sql语句

<select id="getUserId" resultType="com.lhc.pojo.User" parameterType="int">
    SELECT * FROM mybatis.user where id=#{id}
</select>

3.测试

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

    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    User user = mapper.getUserId(1);
    System.out.println(user);


    sqlSession.close();
}

3.Insert

1.编写接口

//插入一个用户
int addUser(User user);

2.编写对应的mapper中的sql语句

<!--对象中的属性 可以直接取出来-->
<insert id="addUser" parameterType="com.lhc.pojo.User">
    insert into mybatis.user(id,`name`,pwd) values(#{id},#{name},#{pwd})
</insert>

3.测试

//增
@Test
public void addUser(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    int rs = mapper.addUser(new User(4, "他", "1"));
    if (rs>0){
        //提交事务
        sqlSession.commit();

        System.out.println("插入成功");
    }

    sqlSession.close();
}

4.Update

1.编写接口

//修改用户
int updateUser(User user);

2.编写对应的mapper中的sql语句

<update id="updateUser" parameterType="com.lhc.pojo.User">
    update mybatis.user set `name` = #{name},pwd=#{pwd} where id=#{id} ;
</update>

3.测试

//改
@Test
public void updateUser(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    int rs = mapper.updateUser(new User(4, "林宏程", "1"));

    if (rs>0){
        //提交事务
        sqlSession.commit();

        System.out.println("插入成功");
    }

    sqlSession.close();
}

5.Delete

1.编写接口

//删除用户
int deleteUser(int id);

2.编写对应的mapper中的sql语句

<delete id="deleteUser" parameterType="int">
    delete from mybatis.user where id=#{id};
</delete>

3.测试

//删除
@Test
public void deleteUser(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    int rs = mapper.deleteUser(4);

    if (rs>0){
        //提交事务
        sqlSession.commit();

        System.out.println("删除成功");
    }

    sqlSession.close();
}

6.分析错误

  • 标签不要匹配错
  • mybatis-config.xml下的 mapper标签的 resource绑定mapper必须使用路径/ 不能用.
  • mybatis-config.xml程序配置文件必须规范
  • 空指针异常 没有注册到资源
  • 输出的xml文件中存在乱码注释

7.万能map

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

增(使用map)

    <!--传递map的key-->
    <insert id="addUser2" parameterType="map">
        insert into mybatis.user(id,`name`,pwd) values(#{userid},#{username},#{password})
    </insert>
//增2
@Test
public void addUser2() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    HashMap<String, Object> map = new HashMap<String, Object>();

    map.put("userid",5);
    map.put("username","我去你的");
    map.put("password","1");

    int rs = mapper.addUser2(map);
    if (rs > 0) {
        //提交事务
        sqlSession.commit();

        System.out.println("插入成功");
    }

    sqlSession.close();
}

查(使用map)

<select id="getUserId2" resultType="com.lhc.pojo.User" parameterType="map">
    SELECT * FROM mybatis.user where id=#{id} and `password`=#{password}
</select>
//查2
@Test
public void getUserId2() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("id",6);
    map.put("password","1");

    User user = mapper.getUserId2(map);
    System.out.println(user);


    sqlSession.close();
}

Map传递参数 直接在sql中取出key即可(可以在调用的时候随意设置参数名称) [parameterType=“map”]

对象传递参数 直接在sql中取对象的属性(必须和属性名完全一样)

[parameterType=“com.lhc.pojo.User”]

只有 基本类型参数的情况下 可以直接在sql中取到!

[parameterType=“int”]

多个数用Map 或者注解

8.思考题

模糊查询

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

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

    <select id="getUserLike" resultType="com.lhc.pojo.User" parameterType="string" >
        SELECT * FROM mybatis.user where `name` like "%"#{value}"%"
    </select>
    
  3. 一定要选择在sql拼接 不然可能导致sql注入问题!

4.配置解析

1核心配置文件

  • mybatis-config.xml

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

    configuration(配置)
    properties(属性)
    settings(设置)
    typeAliases(类型别名)
    typeHandlers(类型处理器)
    objectFactory(对象工厂)
    plugins(插件)
    environments(环境配置)
    environment(环境变量)
    transactionManager(事务管理器)
    dataSource(数据源)
    databaseIdProvider(数据库厂商标识)
    mappers(映射器)
    
<resources>
    <resource>
        <directory>src/main/resources</directory>
        <includes>
            <include>**/*.xml</include>
            <include>**/*.properties</include>
        </includes>
        <filtering>true</filtering>
    </resource>
    <resource>
        <directory>src/main/java</directory>
        <includes>
            <include>**/*.xml</include>
            <include>**/*.properties</include>
        </includes>
        <filtering>true</filtering>
    </resource>
</resources>

2配置环境(environment)

Mybatis可以适应多种环境 但是每次只能选择一个环境

Mybatis默认的事务管理器就是JDBC 地址池 POOLED

学会使用配置多套运行环境

3属性(properties)

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

db.propertise属性(数据库配置)

编写一个数据库配置文件

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

在核心配置文件中引入

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 可以直接引入外部文件
  • 可以在其中增加一些属性配置
  • 如果两个文件有同一字段 优先使用外部配置文件

4.别名

  • 类型别名是为Java类型设置一个短的名字
  • 存在的意义仅在用于减少类完全限定名的冗余

第一种

<!--可以给实体类起别名-->
<typeAliases>
    <typeAlias type="com.lhc.pojo.User" alias="User"/>
</typeAliases>

第二种

扫描实体类的包 它的默认别名就为这个类的 类名(驼峰命名 第一个单词首字母小写 后面单词首字母大写)

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

在实体类比较少的时候 使用第一种

在实体类比较多的时候 使用第二种

第一种可以DIY别名 第二种不行

第三组

@Alias("hello")
public class User

5.设置

这是Mybatis中极为重要的调整文职 它们会改变Mybatis的运行时行为

在这里插入图片描述

6.其他配置

类型处理器

对象工厂

plugin插件

7.mapper

MapperRegister 注册绑定我们的Mapper文件

第一种 使用xml文件绑定注册

<mappers>
    <mapper resource="com/lhc/dao/userMapper.xml"/>
</mappers>

第二种 使用class文件绑定注册

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

注意点

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

第三种 使用包绑定注册

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

注意点

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

步骤

  • 将数据库配置文件外部引入
  • 实体类别名
  • 保证 userMapper接口和userMapper.xml改为一直 而且放在同一个包下

8.生命周期和作用域

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

在这里插入图片描述

SqlSessionFactoryBuilder

  • 一旦创建SqlSessionFactoryBuilder就不需要他了
  • 局部变量

SqlSessionFactory

  • 说白了可以想象成 数据库连接池
  • 一旦创建SqlSessionFactory 就要一直存在 没有理由丢弃和删除
  • 应用作用域
  • 最简单的使用单例模式 (只需要一个)

SqlSession

  • 连接到连接池的请求
  • SqlSession的实例不是线程安全的 因此不能被共享 应该在使用作用域
  • 用完马上关闭

在这里插入图片描述

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

1.问题

数据库中的字段

在这里插入图片描述

实体类

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

测试出现

在这里插入图片描述

解决方法

  • 起别名

    <select id="getUserLike" resultType="com.lhc.pojo.User" parameterType="int" >
        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="com.lhc.pojo.User">
    <!--column数据库中的字段 property实体类的属性-->
    <result column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="pwd" property="password"/>
</resultMap>
<select id="getUserLike" resultMap="UserMap" parameterType="int">
    SELECT id,`name`,pwd  FROM mybatis.user where id = #{id}
</select>
  • resultMap元素是mybatis中最强大的元素
  • resultMap的设计思想是 对于简单的SQL语句根本不需要配置显式的结果集 而对于复杂的SQL语句 只需要描述他的关系就可以了
  • resultMap最优秀的地方在于 对于复杂的数据库字段你可以映射 对于简单的数据库字段不需要映射
  • 例如 多个学生对应一个老师 这个时候映射就没那么简单了

6日志

6.1 日志工厂

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

曾经 sout debug

现在 日志工厂

这是Mybatis中极为重要的调整文职 它们会改变Mybatis的运行时行为

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bwl2hxWk-1604131743669)(F:\JAVA的学习\java note\图片\image-20201027153254871.png)]

  • SLF4J
  • Apache Commons Logging
  • Log4j 2(重点)
  • Log4j
  • JDK logging
  • STDOUT_LOGGING

在mybatis中 具体使用哪个日志实现 在设定中设置!

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

在这里插入图片描述

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. 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/kuang.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

    public class UserDaoTest {
    
        static Logger logger = Logger.getLogger(UserDaoTest.class);
    
        //模糊查询
        @Test
        public void getUserLike() {
            SqlSession sqlSession = MybatisUtils.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
            logger.info("测试  info 进入了 testLog4j成功");
    
            List<User> userList = mapper.getUserLike(1);
    
            for (User user : userList) {
                System.out.println(user);
            }
    
    
            sqlSession.close();
        }
    
        @Test
        public void testlog4j(){
            logger.info("info 进入了 testLog4j");
            logger.debug("debug 进入了testLog4j");
            logger.error("error 进入了testLog4j");
    
        }
        //
    }
    

7 分页

思考 为什么要分页

  • 减少数据的处理量

7.1 使用limit分页

SELECT * FROM `user` LIMIT 从哪里开始,一页显示多少行;
SELECT * FROM `user` LIMIT 3 #[0,3]

使用Mybatis实现分页 核心sql

  1. 接口

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

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

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

7.2 RowBounds分页

这个已经很老了 不需要去学 有时间可以看

8. 使用注解开发

8.1 面向接口编程

根本原因 解耦

8.2使用注解开发

  1. 注解在接口上实现

    @Select("select * from user")
    List<User> getUsers();
    
  2. 需要在核心配置文件(mybatis-config.xml)中绑定接口

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

    @Test
    public void test(){
        //底层主要应用反射
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
        List<User> users = mapper.getUsers();
    
        for (User user : users) {
            System.out.println(user);
        }
    
    
        sqlSession.close();
    }
    

本质 反射机制实现

底层 动态代理模式

在这里插入图片描述

8.3详细的执行流程

在这里插入图片描述

8.4 CRUD

我们可以在工具类创建的时候 自动提交事务

public static SqlSession getSqlSession() {
    //获得 sqlSession对象
    return SqlSessionFactory.openSession(true);
}

编写接口 增加注解

//方法存在多个参数 所有的参数前面必须加上@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(int id );

测试类(注意 我们必须要将接口 注册绑定到我们的核心配置文件中)

package com.lhc.Dao;

import com.lhc.dao.UserMapper;
import com.lhc.pojo.User;
import com.lhc.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserDaoTest {

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

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        User user = mapper.getUserById(1);


        System.out.println(user);


        sqlSession.close();

    }

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

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        mapper.addUser(new User(5, "hhh", "111"));

        sqlSession.close();
    }

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

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        mapper.updateUser(new User(2, "你好我我我", "1"));

        sqlSession.close();
    }

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

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        mapper.deleteUser(4);

        sqlSession.close();
    }

    //
}

关于@Params()注解

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

#{}是预编译的(preparedstatement) #{}是直接编译的容易被SQL注入(statement)

9 Lombok

  • java library
  • plug
  • build tools

使用步骤

  1. 在IDEA中安装
  2. 导入jar包
  3. 在实体类加注解
  4. 这个类已经有了

@Data 无参构造 get set tostring hashcode equals
@AllArgsConstructor 有参全部构造

//实体类
@Data
@AllArgsConstructor
public class User {
    private int id;
    private String name;
    private String password;

}

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'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

测试环境搭建

  1. 导入lombok
  2. 新建实体类
  3. 建立Mapper接口
  4. 建立Mapper.xml
  5. 在核心配置文件中绑定注册我们的Mapper接口(方法有三个 resource class url)
  6. 测试

按照查询嵌套处理

<select id="getStudent" resultMap="Student_Teacher">
select * from student
</select>
<resultMap id="Student_Teacher" 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=#{id}
</select>

按照结果嵌套处理

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

<resultMap id="Student_Teacher2" 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. 环境搭建

实体类

package com.lhc.pojo;

import lombok.Data;

import java.util.List;

@Data
public class Teacher {
    private int id;
    private String name;

    //一个老师拥有多个学生
    private List<Student> students;
}
package com.lhc.pojo;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}

按照查询嵌套处理

<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" column="id"/>
</resultMap>

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

按照结果嵌套处理

    <!--按结果嵌套-->
    <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"/>
        <!--复杂的属性 我们需要单独处理 对象用 association集合用 collection
        javaType 指定的属性类型
        集合中的泛型信息 我们使用ofType
        -->
        <collection property="students" ofType="Student" javaType="ArrayList" >
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

小结

  1. 关联association 多对一
  2. 集合 collection 一对多
  3. javaTepe & ofType
    1. javaTepe 用来sh指定实体类中属性的类型
    2. ofType 用来指定射到到List或者集合中的pojo类型 泛型中的约束类型

注意点

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

面试高频

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

12 动态sql

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

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

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

环境搭建

sql

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. 编写实体类

    package com.lhc.pojo;
    
    import lombok.Data;
    
    import java.util.Date;
    @Data
    public class Blog {
        private int id;
        private String title;
        private  String author;
    
        private Date datCreateTime;
        private int views;
    
    }
    
  4. 编写实体类对应的Mapper接口和 Mapper.XML文件

where

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

IF

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

</select>

choose(when、otherwise)

<select id="queryBlogChoose" parameterType="map" resultType="blog">
    select * from 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)

<insert 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}
</insert>
    <select id="queryBlogChoose" parameterType="map" resultType="blog">
        select * from 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>

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

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

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

注意事项

  • 最好基于单标来定义SQL片段
  • 不要存在where标签

foreach

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

<!--我们现在传递一个万能的map 这map中可以存在一个集合-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">

    select * from blog
    <where>
                    <!--collection 选择遍历的List item 每次输出的参数 open 拼接SQL后面的开端字符 close 拼接SQL后面的结束字符 separator以什么分割 -->
        <foreach collection="ids" item="id" open="id in(" close=")" separator=",">
            #{id}
        </foreach>
    </where>
</select>
@Test
public void queryBlogForeach(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);


    HashMap hashMap = new HashMap();
    ArrayList<Integer> ids = new ArrayList<Integer>();
    ids.add(1);
    ids.add(2);
    ids.add(3);

    hashMap.put("ids",ids);

    mapper.queryBlogForeach(hashMap);

    sqlSession.close();
}

13缓存

13.1 什么是缓存

什么是缓存

连接数据库 耗费资源

一次查询的结果 暂存在一个可以直接取到的地方 内存 放在内存里的数据 就是缓存

我们再次查询相同数据的时候 直接走缓存 就不用走数据库了

  1. 什么是缓存
    1. 存在内存中的临时数据
    2. 将用户经常查询的数据放在内存中
  2. 为什么使用缓存
    1. 减少和数据库的交互次数 减少系统开销 提高系统效率
  3. 什么样的数据库能使用缓存
    1. 经常使用查询 而且不经常改变的{可以使用}

13.2Mybatis缓存

是默认开启一级缓存

二级缓存需要配置

13.3 一级缓存

一级缓存也叫本地缓存 SqlSession

  • 和数据库同一次回话中 会查询到的数据会放在本地缓存中
  • 以后如果需要获取同样的数据 直接从缓存中拿

测试步骤

  1. 开启日志
  2. 测试
  3. 日志中发现查询同一个结果 执行2次 日志中只连接了一次数据库 说明数据已经被缓存 不需要再次连接数据查询数据

缓存失效的情况

  1. 增删改操作可能会更改原来的数据 所以必定会重新刷新缓存

  2. 查询不同的东西

  3. 查询不同的Mapper.xml

  4. 手动清除缓存

    sqlsession.clearcache

一级缓存是默认开启的 只在一次sqlsession中有效 也就是拿到连接到关闭连接这个区间

13.4二级缓存

  • 二级缓存也叫全局缓存 一级缓存作用域太低了 所以诞生了二级缓存
  • 基于namespace级别的缓存
  • 工作机制
    • 一个会话查询一条数据 这个数据就会被放在当前会话的一级缓存
    • 如果当前会话被关闭了 一级缓存就没了 但是一级缓存关闭后 会存入二级缓存中
    • 新的会话查询会从二级缓存中获取
    • 不同的mapper查出的数据会放自己对应的缓存中

步骤

  1. 开启全局缓存

    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    
  2. 在要使用二级缓存的Mapper.xml中开启

    <!--在当前Mapper.xml中使用二级缓存-->
    <cache eviction="FIFO" 先进先出
           flushInterval="60000" 每60000s刷新一次 把用的最少的缓存删除
           size="512" 最多存512个缓存
           readOnly="true"
    />
    

    也可以自定义参数

  3. 测试

    1. 问题 我们需要将实体化序列号 否则就会报错(也可以在缓存自定义参数 eviction=“FIFO” 先进先出)

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

小结

  • 只要开启了二级缓存 在同一个Mapper就有效
  • 所有的数据都会存放在一级缓存中
  • 只有当前会话提交 或者关闭的时候 才会提交二级缓存

13.5 Mybatis缓存原理

在这里插入图片描述

13.6自定义缓存 ehcache

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> ``` 2. 创建一个Mapper接口,例如UserMapper.java: ```java public interface UserMapper { User getUserById(int id); } ``` 3. 创建一个mapper.xml文件,例如UserMapper.xml,定义SQL语句: ```xml <mapper namespace="com.example.mapper.UserMapper"> <select id="getUserById" resultType="com.example.model.User"> SELECT * FROM users WHERE id = #{id} </select> </mapper> ``` 4. 在应用程序中使用MyBatis: ```java public class MyApp { public static void main(String[] args) { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); try (SqlSession session = sqlSessionFactory.openSession()) { UserMapper userMapper = session.getMapper(UserMapper.class); User user = userMapper.getUserById(1); System.out.println(user); } } } ``` 这是一个简单的MyBatis示例,它演示了如何使用Mapper接口和mapper.xml文件来执行SQL查询操作。当然,实际使用中还可以进行更多的配置和操作。 MyBatis是一个Java持久层框架,它提供了缓存机制来提高数据库访问性能[^1]。 一级缓存是MyBatis默认开启的本地缓存,它存储在会话级别,即在同一个会话中,相同的查询语句将会从缓存中获取结果,而不是再次向数据库发出查询请求。一级缓存的作用是减少数据库访问次数,提高性能[^1]。 二级缓存是全局缓存,它存储在会话工厂级别,即在不同的会话中,相同的查询语句将会从缓存中获取结果。二级缓存的工作机制是将查询结果序列化后存储在缓存中,当需要获取结果时,将缓存中的序列化结果反序列化为对象返回。二级缓存的使用需要在MyBatis的配置文件中进行配置[^1]。 以下是MyBatis缓存的一些相关配置: - eviction:缓存的回收策略,包括LRU(最近最少使用)、FIFO(先进先出)和SOFT(软引用)等。 - flushInterval:缓存刷新间隔,即多长时间刷新一次缓存。 - readOnly:是否只读,如果设置为true,则缓存中的对象不会被修改。 - size:缓存存放多少元素。 - type:指定自定义缓存的全类名[^1]。 总结来说,MyBatis的缓存机制可以提高数据库访问性能,通过一级缓存和二级缓存的使用,可以减少数据库查询次数,提高系统性能[^1]。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值