b站狂神老师的Mybatis学习笔记

本文详细介绍了Mybatis的基础搭建、数据库配置、工具类使用、实体类与接口设计,涵盖了CRUD操作、分页、RowBounds、动态SQL、缓存(一级和二级)以及使用注解的开发。还演示了如何解决属性名冲突和使用Lombok简化开发。
摘要由CSDN通过智能技术生成

2.第一个Mybatis程序

思路 : 搭建环境–》导入Mybatis–》编写代码–》测试

2.1搭建数据库
2.2 新建一个maven项目
2.3 导入核心配置文件
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="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>
2.4 使用mybatis

创建一个com.guo.dao文件 封装好pojo和utils

  • 封装工具类
package com.guo.dao;

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;

public  class MyBatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            String resource = "org/mybatis/example/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(){
        return sqlSessionFactory.openSession();

    }

}

  • 实体类

    package com.guo.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/mapper)

    userdao

    package com.guo.dao;
    
    import com.guo.pojo.User;
    
    import java.util.List;
    
    public interface UserDao {
        List<User> getUserList();
    }
    

    UserMappert.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=绑定一个对应的DAO/Mapper-->
    <mapper namespace="com.guo.dao.UserDao">
    
    <!-- sql查询语句   -->
        <select id="getUserList" resultType="com.guo.pojo.User">
            select * from User
        </select>
    </mapper>
    
  • 报错

  1. 问题出在java和resource的xml文件无法被导出
Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource com/guo/dao/UseMapper.xml

解决办法

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>
  1. maven无法clean

    解决办法: 进入idea --》 file–》settings-》maven 重新配置maven

    如果没有下载maven请重新配置环境变量

  2. 报错字符集编码问题

    在父maven项目中的pom.xml文件中

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

3、CRUD

3.1 namespace

​ namespace中的包名要和Dao/Mapper接口包名一直

3.2 select insert update delete

​ 选择查询

  • id: 就是队名namespace的方法名
  • resultType: Sql语句执行的返回值
  • paramType: 传入参数类型
  1. 编写接口
  2. 编写对应的mapper中的sql语句
  3. 测试

注意:

  • 除了select其他的操作需要提交事务

3 万能的map

我们的实体类或者数据库中的表、字段和参数过多,我们应该考虑使用map

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

<insert id="insertUser2" parameterType="map">
    insert into mybatis.user (id, name, pwd) values(#{userId}, #{userName}, #{password})
</insert>

对象传递参数,直接在sql中取出属性

<insert id="insertUser" parameterType="com.guo.pojo.User">
    insert into mybatis.user values(#{id}, #{name}, #{pwd})
</insert>

只有一个基本类型参数的情况下,可以直接在sql中取到 parameterType=“int”(可以省略不写)

4. 模糊查询

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

    <!-- sql查询语句 模糊查询   -->
    <select id="getLikeUser" resultType="com.guo.pojo.User">
        select * from mybatis.user where name like #{value};
    </select>
    
    List<User> list = userMapper.getLikeUser("%g%");
    
  2. 在sql中拼接中使用通配符 “%”

    List<User> list = userMapper.getLikeUser("g");
    
    <!-- sql查询语句 模糊查询   -->
    <select id="getLikeUser" resultType="com.guo.pojo.User">
        select * from mybatis.user where name like "%"#{value}"%";
    </select>
    

    相比之下,第二种方法更加安全

5.配置解析

5.1 核心配置
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)

5.2 环境配置(environments)

​ mybatis可以配置成适应于多种环境

​ 不过记住:尽管可以配置多种环境,但是每个sqlSessionFactory只能选择一种环境,选择的环境由default字段决定,

​ 学会配置多种环境

<environments default="development">

​ mybatis中默认的事务管理器 是 JDBC ,连接池:POOLED

5.3 属性(Properties)

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

<properties resource="db.properties" />

db.properties文件

driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybatis?useUnicode=true;characterEncoding=utf-8;serverTimezone=GMT;nullCatalogMeansCurrent = true
usernname = root
password = 123456

引入文件后,xml中文件可以直接引用properties中的变量

<environment id="development">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${root}"/>
        <property name="password" value="${password}"/>
    </dataSource>
</environment>

注意:

  1. properties还有第二种用法==
<properties resource="db.properties" >
    <property name="password" value="111111"/>
</properties>

当properties标签中定义键值对和引用文件中的键值对发生冲突时, 外部文件优先级高于内部文件

  1. 在xml文件中 每一个标签有一个固定的顺序,不能随意更改
The content of element type "configuration" must match "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".
5.4 类型别名
  • 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。

两种方式配置别名

  1. typeAlias 配置Java Bean文件

    <typeAliases>
        <typeAlias type="com.guo.pojo.User" alias="User"/>
    </typeAliases>
    
  2. 也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean

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

注意: 第一种方法和第二种方法都能配置别名,

  • 但是第一种方法可以自己设置alias,

  • 第二种方法在Java Bean没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。;若有注解,则别名为其注解值

@Alias("hello")
public class User {
    ...
}
5.6.设置settings

​ 需要记住的几个设置

  • cacheEnabled全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。true | falsetrue
    lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。true | falsefalse
    localCacheScopeMyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。SESSION | STATEMENTSESSION

当遇到设置问题,请去官方文档上查找

5.7. 其他配置
5.8. 映射器(Mappers)

MapperRegistery: 注册绑定我们的mapper文件

方式一 : 直接使用xml文件名进行绑定

 <mappers>
        <mapper resource="com/guo/dao/UserMapper.xml"/>
 </mappers>

方式二: 使用接口名进行绑定

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

注意:

  • 使用接口名直接绑定时, 接口文件名和MapperXML文件必须相同
  • 两个文件必须在同一个文件夹下

方式三:使用包名扫描绑定

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

注意:

  • 使用接口名直接绑定时, 接口文件名和MapperXML文件必须相同
  • 两个文件必须在同一个文件夹下
5.9. 生命周期和作用域

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qjb5BL21-1621000778478)(C:\Users\MSI\AppData\Roaming\Typora\typora-user-images\image-20210412143621378.png)]

SqlSessionFactoryBuilder
  • 一旦创建了 SqlSessionFactory,就不再需要SqlSessionFactoryBuilder了,其最大的作用就是创建SqlSessionFactory
  • 因此其最佳作用域为 方法作用域(作用在一个方法内)
SqlSessionFactory
  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
  • 最佳作用域是 应用作用域
  • 使用单例模式或者静态单例模式。
SqlSession
  • 每个线程都应该有它自己的 SqlSession 实例。
  • SqlSession 的实例不是线程安全的,因此是不能被共享的,
  • 最佳的作用域是 请求或方法作用域。
  • 使用后应该立马关闭
5.10.解决属性名和字段名不一致问题
1.问题

​ 当JavaBean和pojo中的对应属性名不同的时候,会发生冲突

​ 例如

​ User.class

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

UserMapper.xml

<select id="getUserList" resultType="user">
    select * from mybatis.user;
</select>

查询出来的结果

User{id=1, name='狂神说', password='null'}
User{id=2, name='guo', password='null'}
User{id=10, name='10', password='null'}
User{id=12, name='ghl', password='null'}

解决办法:

  • 起别名:

    <select id="getUserList" resultType="user">
        select id,name,pwd as password from mybatis.user;
    </select>
    
2.resultMap 结果集映射
  • resultMap 元素是 MyBatis 中最重要最强大的元素。

  • ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。

  • ResultMap 的优秀之处——你完全可以不用显式地配置它们。(处理发生冲突字段就行)

  • 如果这个世界总是这么简单就好了。

    例如上述例子

<resultMap id="userResultMap" type="user">
    <result property="password" column="pwd"/>
</resultMap>

<select id="getUserList" resultMap="userResultMap">
    select * from mybatis.user;
</select>

6. 日志

6.1 maybatis日志工场
设置名描述有效值默认值
logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING未设置

log信息

==>  Preparing: select * from mybatis.user; 
==> Parameters: 
<==    Columns: id, name, pwd
<==        Row: 1, 狂神说, 123456
<==        Row: 2, guo, 123456
<==        Row: 10, 10, 10
<==        Row: 12, ghl, 122344
<==      Total: 4
6.2 LOG4J

​ 什么是LOG4J?

​ Log4j是Apache的一个开源项目

  • 控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器

  • 我们也可以控制每一条日志的输出格式;

  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。

  • 可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码

使用LOG4G

​ 1.先导包

<!--pom.xml-->
<dependencies>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
</dependencies>

​ 2.配置log4j log4j.properties文件

### set log levels ###
log4j.rootLogger = DEBUG,Console,File

###  输出到控制台  ###
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern= %d{ABSOLUTE} %5p %c{1}:%L - %m%n


### 输出到日志文件 ###
log4j.appender.File=org.apache.log4j.RollingFileAppender 
log4j.appender.File.File=${project}/WEB-INF/logs/app.log
log4j.appender.File.DatePattern=_yyyyMMdd'.log'
log4j.appender.File.MaxFileSize=10MB
log4j.appender.File.Threshold=ALL
log4j.appender.File.layout=org.apache.log4j.PatternLayout
log4j.appender.File.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH\:mm\:ss,SSS}][%c]%m%n
  1. 设置mybatis中的settings

    <!--mybatis-confi.xml-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    
  2. 测试和使用(记住导入的包要apache.log4j.Logger)

    static Logger logger = Logger.getLogger(User.class);
    @Test
    public void testLogger(){
        logger.info("进入了testdebug中");
    }
    

7. 分页

使用分页的原因:

  • 提升用户体验
  • 减少查询数据量

分页sql

7.1.使用Mybatis实现分页

UserMapper中定义

<select id="getLimitList" resultMap="userResultMap">
    select * from mybatis.user  limit #{startIndex}, #{pageSize}
</select>

test测试

@Test
public void getLimitList(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();

    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    Map<String,Integer> map = new HashMap<String, Integer>();
    map.put("startIndex", 0);
    map.put("pageSize", 2);

    List<User> list = userMapper.getLimitList(map);
    for (User user : list) {
        System.out.println(user);
    }
    sqlSession.close();
}
7.2 RowBounds分页

不在使用SQl实现分页

  1. 接口

    List<User> getUserByRowBounds(Map<String,Integer> map);
    
  2. mapper.xml

    <select id="getUserByRowBounds" resultMap="userMap">
        select * from mybatis.user;
    </select>
    
  3. 测试

    @Test
    public void getUserByRowBounds(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
    
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        RowBounds rowBounds = new RowBounds(0, 2);
        List<User> list = sqlSession.selectList("com.guo.dao.UserMapper.getUserByRowBounds",
                null, rowBounds);
        for (User user : list) {
            System.out.println(user);
        }
    
        sqlSession.close();
    }
    
7.3 分页插件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2bRiCbpa-1621000778481)(C:\Users\MSI\AppData\Roaming\Typora\typora-user-images\image-20210413102325273.png)]

8.使用注解开发

8.1 面向接口编程
8.2 使用注解开发
  1. 注解在接口上实现

    public interface UserMapper {
    //  1.获取全部用户数据
        @Select("select * from mybatis.user")
        List<User> getUserList();
    
    
    }
    
  2. 需要在核心位置中绑定接口

    <mappers>
            <mapper class="com.guo.dao.UserMapper"/>
     </mappers>
    
  3. 测试

    @Test
    public void getUserList(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> list = userMapper.getUserList();
        for (User user : list) {
            System.out.println(user);
        }
    
        sqlSession.close();
    }
    
  4. 结果:

    User{id=1, name='狂神说', password='null'}
    User{id=2, name='guo', password='null'}
    User{id=10, name='10', password='null'}
    User{id=12, name='ghl', password='null'}
    

    注意: 注解语句用于处理简单的sql语句,如果碰到结构复杂的语句或者需要使用resultMap的情况时,注解的使用会使得代码愈发复杂

本质:反射机制实现

底层:动态代理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SObM1Qm9-1621000778483)(C:\Users\MSI\AppData\Roaming\Typora\typora-user-images\image-20210413105716489.png)]

mybatis详细执行流程

8.3 CRUD

方法存在多个参数,所有的参数前面必须加上@Param(“id”) 注解

1.设置openSession方法参数为true 以后不用手动提交

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

}

2.增删改查

  1. 写接口

  2. 写注解

    @Select("select * from mybatis.user where id = #{uid}")
    User getUserById(@Param("uid") int id);
    
  3. 测试

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

关于@Param()注解

  • 基本类型的参数或者String类型需要+此注解
  • 引用类型不需要
  • 方法存在多个参数,所有的参数前面必须加上@Param("") 注解

9.Lombok

使用步骤

  1. 在IDEA中安装lombok的插件
  2. 在项目导入jar包
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
@ExtensionMethod (Experimental, activate manually in plugin settings)

10. 多对一

1.数据库SQL语句
CREATE TABLE `teacher` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

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

CREATE TABLE `student` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  `tid` INT(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fktid` (`tid`),
  CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

测试环境搭建

  1. 导入Lombok
  2. 建立实体类
  3. 建立Mapper接口
  4. 建立Mapper.xml文件
  5. 在核心配置文件中绑定注册
  6. 测试查询能否成功
2.复杂的属性需要单独处理,对象–association 集合–collection

<!--  1.按照结果嵌套处理  -->
<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>
<!-- 2.思路
    查询出所有学生的信息
    根据据查询的到的学生的tid寻找对应的老师
   -->
<select id="getStudent" resultMap="StudentTeacher">
    select * from student
</select>

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

回顾Mysql多对一查询方式

  • 联表查询—类似于方案1
  • 子查询—类似于方案2

11.一对多

​ 比如:一个老师拥有多个学生

按照结果嵌套处理

<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" />
<!--    复杂的属性:需要单独处理
    javaType=“” 指定属性类型
    ofType:指定集合泛型信息
-->
    <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 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 student where tid= #{id}
</select>

小结:

1.关联-association

2.集合-collection

3.javaType & ofType

​ javaType-用来指定实体类中给的属性类型

​ ofType-泛型约束类型

12.动态sql

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

搭建环境
IF(一般和where一起使用)
<select id="queryBlogIf" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <if test="title != null">
                title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </where>

    </select>

​ where标签会帮你进行自动的匹配,当用户只有第二个输入条件正确的时候,会自动的去掉if标签中的and 或 or 关键字来保证sql语句的输入正确性

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

​ 使用if标签的时候不用在意if标签是不是最后一个标签,都可以安心加上逗号

所谓的动态sql,本质就是sql语句,只是我们在sql层面去执行一个逻辑代码

if where set choose when

SQL片段

有的时候,我们可能会将一下功能部分抽取出来进行复用

<sql id="if-title-author">
    <if test="title != null">
        title = #{title}
    </if>
    <if test="author != null">
        and author = #{author}
    </if>
</sql>

使用时:
<include refid="if-title-author"></include>

实现代码的复用

注意事项:

  • 最好基于单表进行SQL片段
  • 不要存在where标签
Foreach

初始语句

select * from id =1 or id=2 or id=3

简单化

<select id="queryBlogForeach" parameterType="map" resultType="blog">
    select * from blog
    <where>
       <foreach collection="list" item="id" open="and (" close=")" separator="or">
           id = #{id}
        </foreach>
    </where>
</select>

动态SQL就是在拼接SQl语句,我们只要保证他SQL的正确性

小知识点
@SuppressWarnings("all")
//镇压警告(所有)
<!--  是否开启 经典数据库列名到java驼峰命名转化      -->
<setting name="mapUnderscoreToCamelCase" value="true"/>

13、缓存

13.1 一级缓存

​ 一级缓存默认打开

​ 当调用相同的查询语句时,回从缓存中调用,同一个session级有效,也就是从打开session到关闭关系sqlSession。

​ 刷新缓存的方法:

​ 1.手动清理

​ 2.查询不同东西

​ 3.执行增删改的操作刷新缓存

​ 4.查询不同的mapper

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

步骤:

1.开启缓存(默认true)

<!--    显示开启全局缓存    -->
<setting name="cacheEnabled" value="true"/>

2.再要使用的二级缓存的Mapper开启

<cache/>
<select id="selectById" resultType="user" useCache="true">

测试问题:

1.实体类报错没有进行序列化,使用缓存时,mybatis会自动调用serialize()方法,该方法必须要求实体化pojo才能正常调用

13.3 缓存机制、

缓存顺序:

1.先看二级缓存中有没有

2.再看一级缓存有无

3.最后进行数据库的查询,并将其放入缓存中

13.4 自定义缓存-ehcache

1.使用ehcache时,要先导包

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

2.在mapper使用

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

3.ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!--
       diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
       user.home – 用户主目录
       user.dir  – 用户当前工作目录
       java.io.tmpdir – 默认临时文件路径
     -->
    <diskStore path="java.io.tmpdir/Tmp_EhCache"/>
    <!--
       defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
     -->
    <!--
      name:缓存名称。
      maxElementsInMemory:缓存最大数目
      maxElementsOnDisk:硬盘最大缓存个数。
      eternal:对象是否永久有效,一但设置了,timeout将不起作用。
      overflowToDisk:是否保存到磁盘,当系统宕机时
      timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
      timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
      diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
      diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
      diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
      memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
      clearOnFlush:内存数量最大时是否清除。
      memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
      FIFO,first in first out,这个是大家最熟的,先进先出。
      LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
      LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
   -->
    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>

</ehcache>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值