栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Mybatis学习笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Mybatis学习笔记

概述
什么是框架?

框架是我们软件开发中的一套解决方案,不同的框架解决不同的问题。

使用框架的好处:框架封装了很多的细节,使开发者可以用极简的方式实现功能。大大提高开发效率。

三层架构

表现层:用于展示数据

业务层:处理业务需求(service)

持久层:和数据库交互

持久层技术解决方案

JDBC技术:

​ Connection

​ preparedStatement

​ ResultSet

Spring的JdbcTemplate:

​ Spring中对jdbc的简单封装

Apache的DBUtils:

​ 它和Spring的JdbcTemplate很像,也是对Jdbc的简单封装

以上这些都不是框架

​ JDBC是规范

​ Spring的JdbcTemplate和Apache的DBUtils都只是工具类

Mybatis
Mybatis官方文档

Mybatis官网地址:https://mybatis.org/mybatis-3/zh/getting-started.html

官方网站始终是最好的学习方式

[Mybatis官网链接](mybatis – MyBatis 3 | 入门 )

[Mybtais百度百科](MyBatis_百度百科 (baidu.com) )

第一个Mybatis程序:搭建环境 => 导入Mybatis => 编写代码 => 测试

Mybatis概述

mybatis是一个持久层框架,用java编写的

它封装了jdbc操作的很多细节,使开发者只需要关注sql语句本身,而无需关注注册驱动,创建连接等繁杂过程

它使用了ORM思想实现了结果集的封装

ORM:

​ Object Relational Mapping 对象关系映射

简单的说:就是把数据库表和实体类及实体类的属性对应起来,让我们可以操作实体类就实现操作数据库表

第一个Mybatis程序 环境配置

    新建一个普通的maven项目

    删除src(使之成为父工程)并导入依赖,pom.xml代码如下

    
    
        4.0.0
        
        com.yao
        mvn-mybatis
        1.0-SNAPSHOT
    
        
        
            
            
                mysql
                mysql-connector-java
                5.1.47
            
            
            
                org.mybatis
                mybatis
                3.5.2
            
            
            
                junit
                junit
                4.12
            
        
    
    
    

    创建模块

    编写mybatis的核心配置文件(在resource目录下new一个file,mybatis-config.xml)

    
    
    
    
        
        
            
                
                
                
                
                    
                    
                    
                    
                
            
        
    
        
        
            
        
    
    
    

    编写mybatis的工具类(在项目中建一个工具包(utils)目录下)

    package com.yao.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 {
                //获取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(){
            return sqlSessionFactory.openSession();
        }
    }
    
编写代码

Pojo(实体类)

package com.yao.pojo;

public class Account {
    private int id;
    private String name;
    private double money;

    public Account(){}

    public Account(int id, String name, double money) {
        this.id = id;
        this.name = name;
        this.money = money;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public double getMoney() {
        return money;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "account{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", money=" + money +
                '}';
    }
}

AccountDao

package com.yao.dao;

import com.yao.pojo.Account;

import java.util.List;

public interface AccountDao {
    List getList();
}

AccountMapper.xml


        




    select * from test.account


在父模块和子模块的pom.xml中加入

    
        
            
                src/main/resources
                
                    ***.xml
                
            
            
                src/main/java
                
                    ***.xml
                
                true
            
        
    
测试

AccountDaoTest

package com.yao.dao;

import com.yao.pojo.Account;
import com.yao.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class AccountDaoTest {
    @Test
    public void test(){


        SqlSession sqlSession = MybatisUtils.getSqlSession();

        AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
        List accountList = accountDao.getList();

        for(Account account : accountList){
            System.out.println(account);
        }


        sqlSession.close();
    }
}

(PS:有时候会报 error building SqlSession,将每个mapper配置文件encoding="UTF-8"全部改为encoding="UTF8"就能成功运行)

CRUD

其实就是增删改查

增加(Create)

读取查询(Retrieve)

更新(Update)

删除(Delete)

Mapper

    List getList();

    Account getAccountById(int id);

    int addAccount(Account account);

    int deleteAccount(int id);

Mapper.xml





    
    
        select * from test.account where id = #{id}
    

    
        insert into test.account (id,aname,money) values(#{id},#{aname},#{money})
    

    
        delete from test.account where id=#{id}
    

Test

    @Test
    public void test(){


        SqlSession sqlSession = MybatisUtils.getSqlSession();

        AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
        List accountList = accountDao.getList();

        for(Account account : accountList){
            System.out.println(account);
        }


        sqlSession.close();
    }

    @Test
    public void TestGetAccountById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        AccountDao mapper = sqlSession.getMapper(AccountDao.class);

        Account account = mapper.getAccountById(10);
        System.out.println(account);

        sqlSession.close();
    }

    @Test
    public void TestAddAccount(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        AccountDao mapper = sqlSession.getMapper(AccountDao.class);

        mapper.addAccount(new Account(11,"哈哈",3000));
        //插入必须得提交事务才能插入成功
        sqlSession.commit();

        sqlSession.close();
    }

    @Test
    public void delete(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        AccountDao mapper = sqlSession.getMapper(AccountDao.class);

        mapper.deleteAccount(11);

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

###CRUD总结

namespace中的包名要和Mapper/Dao接口保持一致resultType:Sql语句执行返回的类型(除了class就是基本数据类型)parameterType:参数类型更新,删除,插入操作都需要sqlSession.commit()提交事务,否则就无法改变数据库里的记录pojo类里面的属性可以拆开;在xml配置文件里的CRUD标签用#{xx}接受到Mapper里方法传过来的参数,且参数名需保持一致 Mybatis执行流程

参考链接:https://blog.csdn.net/qq_38270106/article/details/93398694

Map

假设,我们的实体类,或者数据库中的表,字段或者参数过多,我们应该考虑用map去实现数据库的操作(企业开发中)

例子:

// Mapper接口
int updateAccount(Map map);
   
	
        update test.account set aname=#{aname} where id=#{id}
    
//Test
    @Test
    public void TestUpdate(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        AccountDao mapper = sqlSession.getMapper(AccountDao.class);
        Map map = new HashMap();
        map.put("id",10);
        map.put("aname","潘潘");
        mapper.updateAccount(map);
        sqlSession.commit();

        sqlSession.close();
    }

Map传递参数时,直接在sql中取出key即可(parameterType=“map”)

多个参数适合用map(非正式),或者注解

配置解析

1、核心配置文件

mybatis-config.xml

Mybatis的配置文件包含了会深深影响Mybatis行为的设置和属性信息

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

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

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

所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推,记起来很简单:

每个数据库对应一个 SqlSessionFactory 实例

为了指定创建哪种环境,只要将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可。可以接受环境配置的两个方法签名是:

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);

如果忽略了环境参数,那么将会加载默认环境

environments 元素定义了如何配置环境


  
    
      
    
    
      
      
      
      
    
  

注意一些关键点:

默认使用的环境 ID(比如:default=“development”)。每个 environment 元素定义的环境 ID(比如:id=“development”)。事务管理器的配置(比如:type=“JDBC”)。数据源的配置(比如:type=“POOLED”)。

默认环境和环境 ID 顾名思义。 环境可以随意命名,但务必保证默认的环境 ID 要匹配其中一个环境 ID。

事务管理器(transactionManager)

在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]") ,默认事务管理是JDBC

JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。

如果使用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。

这两种事务管理器类型都不需要设置任何属性。它们其实是类型别名,换句话说,你可以用TransactionFactory 接口实现类的全限定名或类型别名代替它们。

数据源(dataSource)

dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。

大多数 MyBatis 应用程序会按示例中的例子来配置数据源。虽然数据源配置是可选的,但如果要启用延迟加载特性,就必须配置数据源。

有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"),默认数据源类型是POOLED

UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。

POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。

此外,对于**“池”**,如果每次连数据库都需要创建一次连接,是非常占用资源的,一个用户连完后先不要关闭它,等待下一个用户继续连,直到最后可以回收(用完后可以回收)

2、属性(properties)

我们可以通过properties属性(在resources目录下)来实现引用配置文件

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

编写一个配置文件(resources目录下)

db.properties(Java 属性文件中配置这些属性)

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

在配置文件映入时,所有的xml文件都有规定标签的顺序,例如properties只能放在最上面

然后在核心配置文件中配置properties,讲db.properties导进来


官方文档


  
  

如果有相同的字段,则优先使用外部配置文件的字段

设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值


  
  
  
  

3、类型别名(typeAliases)

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


  
  
  
  
  
  

当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。

也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:


  

扫描包的情况下,别名就是该实体类的类名全部小写;一般来说,对于类比较少的情况下,我们使用第一种,类比较多的话我们使用第二种

每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。例如:

@Alias("author")
public class Author {
    ...
}
4、设置(settings)

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。

具体内容参考官方文档

5、映射器(mappers)

既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。例如:

方法一



  
  
  

方法二



  
  
  

方法二注意事项:

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

使用扫描包进行注入绑定注意的点也跟上述一样,一般情况下都是用resource,即方法一进行绑定。

6、其他配置

typeHandlers(类型处理器)objectFactory(对象工厂)plugins(插件)

mybatis-generator-coremybatis-plus(mybatis再简化,增删改查都不用写,只用写复杂得实现)通用mapper 作用域(Scope)和生命周期

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

SqlSessionFactoryBuilder:

一旦创建了SqlSessionFactoryBuilder,就不再需要它了放在局部变量

SqlSessionFactory:

可以想象成数据连接池SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。因此SqlSessionFactory的最佳作用域是应用作用域(全局变量)最简单的就是使用单例模式或者静态单例模式

SqlSession

连接到连接池的一个请求!SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域用完之后需要赶紧关闭,否则资源被占用 解决属性名和字段名不一致的问题

数据库:
id name pwd
实体类:
id name password

解决办法一:在SQL语句里面起别名,使查出来的pwd是password,从而可以构造正常的实体类

解决办法二:

resultMap:

结果集映射


    
	
    
    



其实只要映射不一样的属性就可以了,其他的属性可以不写

实际上UserMap是不存在的返回类型,但它通过映射找到对应id的映射集,在该映射集里规定数据库和实体类属性的映射关系

日志 1、日志工厂(setting)

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

曾经:sout,debug

现在我们用日志工厂来辅助我们开发:

SLF4JLOG4JLOG4J2JDK_LOGGINGCOMMONS_LOGGINGSTDOUT_LOGGING(标准日志工厂)NO_LOGGING

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

STDOUT_LOGGING是标准的日志输出,什么都不用配

设置名描述有效值
logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J | LOG4J(deprecated since 3.5.9) | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING

logImpl没有默认值

例:


    

Opening JDBC Connection
Created connection 1858609436.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6ec8211c]
==>  Preparing: select * from test.account 
==> Parameters: 
<==    Columns: id, aname, money
<==        Row: 10, 潘潘, 3000
<==        Row: 11, 哈哈, 3000
<==        Row: 20, 姚姚, 200
<==        Row: 30, 赛文, 0
<==        Row: 40, 老大, 10
<==      Total: 5
account{id=10, name='潘潘', money=3000.0}
account{id=11, name='哈哈', money=3000.0}
account{id=20, name='姚姚', money=200.0}
account{id=30, name='赛文', money=0.0}
account{id=40, name='老大', money=10.0}
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6ec8211c]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6ec8211c]
Returned connection 1858609436 to pool.
2、LOG4J

[log4j百度百科](log4j_百度百科 (baidu.com) )

什么是LOG4J?

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

mvn仓库网址:https://mvnrepository.com

1、导入log4j依赖(查看[mvn库](Maven Repository: log4j » log4j » 1.2.17 (mvnrepository.com) ))


    log4j
    log4j
    1.2.17

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为日志的实现


    

4、log4j的使用

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

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

static Logger logger = Logger.getLogger(LogDemo.class); //LogDemo为相关的类

3.日志级别

logger.info("xxx");
logger.debug("xxx");
logger.error("xxx");
分页 使用Limit分页
select * from user limit startIndex,pageSize
select * from user limit n  #[0,n]

limit后接两个参数是从数据库查询的起始记录和终止记录,分页是为了减少数据的处理量

用Mybatis实现分页

Mapper接口

List = getPojoByLimit(Map map);

Mapper.xml


    select * from test.account limit #{startIndex},#{pageSize}

Test类

@Test
public void test(){

    SqlSession sqlSession = MybatisUtils.getSqlSession();
    AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);

    HashMap map = new HashMap();
    map.put("startIndex",0);
    map.put("pageSize",2);

    List accountList = mapper.getAccountByLimit(map);
    accountList.for{
        sout(account);
    }

    sqlSession.close();
}
RowBounds(了解即可)

通过java代码层面实现分页

Mapper接口

List = getPojoByRowBounds();

Mapper.xml


        select * from test.student
    

    
    select s.id sid,s.name sname,t.name tname
    from student s,teacher t
    where s.tid=t.id;



    
    
    
        
    

测试:

    @Test
    public void testStudent2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        List studentList = mapper.getStudent2();
        for (Student student : studentList) {
            System.out.println(student);
        }
        sqlSession.close();
    }

个人理解:

property是pojo内的元素column则代表数据库查出来时的列名在association里,如果有需要也要进行嵌套映射在结果嵌套查询里多关注sql的select列名,column需和它们保持一致 多对一处理

实体类

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

Mapper接口:

public interface TeacherMapper {
    Teacher getTeacher(@Param("tid") int id);
}

Mapper.xml


    
    
    select * from test.student where 1=1
    
        and id = #{sid}
    
    
        and name = #{sname}
    

测试

@Test
public void test(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
    HashMap map = new HashMap();
    map.put("sid",1);
    map.put("sname","小明");
    List studentList = mapper.sIf(map);
    for (Student student : studentList) {
        System.out.println(student);
    }
    sqlSession.close();
}
choose (when, otherwise)

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

还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回大量的无意义随机 Blog,还不如返回一些由管理员精选的 Blog)。


  SELECT * FROM BLOG
  WHERe
  
    state = #{state}
  
  
    AND title like #{title}
  
  
    AND author_name like #{author.name}
  

如果没有匹配的条件会怎么样?最终这条 SQL 会变成这样:

SELECT * FROM BLOG
WHERe

这会导致查询失败。如果匹配的只是第二个条件又会怎样?这条 SQL 会是这样:

SELECt * FROM BLOG
WHERe
AND title like ‘someTitle’

这个查询也会失败。这个问题不能简单地用条件元素来解决。这个问题是如此的难以解决,以至于解决过的人不会再想碰到这种问题。

MyBatis 有一个简单且适合大多数场景的解决办法。而在其他场景中,可以对其进行自定义以符合需求。而这,只需要一处简单的改动:


  SELECT * FROM BLOG
  
    
         state = #{state}
    
    
        AND title like #{title}
    
    
        AND author_name like #{author.name}
    
  

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

如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:


  ...

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

用于动态更新语句的类似解决方案叫做 setset 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:


  update Author
    
      username=#{username},
      password=#{password},
      email=#{email},
      bio=#{bio}
    
  where id=#{id}

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

来看看与 set 元素等价的自定义 trim 元素吧:


  ...

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

(摘自[动态SQL](mybatis – MyBatis 3 | 动态 SQL ))

SQL片段

    select * from test.student where 1=1
    
        and id = #{sid}
    
    
        and name = #{sname}
    



    

这样的格式也能跑

这方便我们有些代码的复用最好基于单表来定义SQL片段不要存在where标签 foreach

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


测试:

@Test
public void testForEach(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);

    HashMap map = new HashMap();
    ArrayList ids = new ArrayList();

    //动态查找
    ids.add(1);
    ids.add(2);
    map.put("ids",ids);

    List studentList = mapper.sForeach(map);
    for (Student student : studentList) {
        System.out.println(student);
    }
    sqlSession.close();
}

提要

item是迭代项通过collection使用方法中的参数open是开始close是结束separator是用什么分隔 补充知识

面试高频:

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

去掉下划线:@SuppressWarnings(“all”) //抑制警告

mapUnderscoreToCamelCase是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。true | falss

驼峰命名映射只适用于从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。

例如java属性名是createTime,数据库列名是create_Time,这种情况下就能自动完成映射,而不用去使用resultMap手动映射

缓存
查询需要连接数据库,如果多次查询的话非常耗费资源
如果我们将一次查询的结果放在一块内存里(缓存),
当我们再次查询相同数据时,直接走缓存,就不用再去做数据库的相关操作了,效率大大提升
简介

什么是缓存?

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

为什么使用缓存?

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

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

经常查询并且不经常改变的数据 Mybatis缓存

Mybatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率Mybatis系统中默认定义了两级缓存:

一级缓存二级缓存

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

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

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

测试:

    开启日志

    测试在一个Session中查询两次相同记录

        @Test
        public void cacheTest(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);
    
            Account account = mapper.getByID(10);
            System.out.println(account);
    		//如果这中间出现了增删改的操作,缓存会失效
            System.out.println("=========================");
    
            Account account2 = mapper.getByID(10);
            System.out.println(account2);
    
            System.out.println(account==account2);
        }
    
    

    查看日志输出

缓存失效的原因:

查询内容不同

增删改操作

查询不同的Mapper.xml

手动清理缓存

SqlSession.clearCache(); //手动清理缓存

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

二级缓存

二级缓存也叫全局缓存,一级缓存作用域太低,所以诞生了二级缓存基于namespace级别的缓存,一个名称空间,对应一个二级缓存工作机制

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

步骤:

1、开启全局缓存


2、在要使用二级缓存的mapper中开启


也可以自定义参数


Mybatis的缓存机制

参考链接:https://tech.meituan.com/2018/01/19/mybatis-cache.html

自定义缓存

mybatis – MyBatis 3 | XML 映射器

最后

只是单纯地记录下自己的学习过程,如果能或多或少帮到一些跟我一样刚入门Mybatis的小白们,是我最开心的事情该笔记是自己的一些心得且大部分笔记内容基于b站up主:遇见狂神说,并附上链接:【狂神说Java】Mybatis最新完整教程IDEA版通俗易懂_哔哩哔哩_bilibili学习之路漫漫,很多优秀的人尚且都在努力学习,自己有什么理由不坚持下去呢。

END

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/711160.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号