【知识】Mybatis-学习笔记

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
RDS MySQL DuckDB 分析主实例,集群系列 8核16GB
简介: 【知识】Mybatis-学习笔记

image.png

一、MyBatis简介


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。


如何获得Mybatis?


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


中文文档:https://mybatis.org/mybatis-3/zh/getting-started.html


1.2 持久化


数据持久化


持久化就是将程序的数据在持久状态和瞬时状态转化的过程


内存:断电即失


数据库(JDBC),I/O文件持久化


生活:冷藏、罐头


1.3 持久层


Dao层、Service层、Controller层


完成持久化工作的代码块

层的界限十分明显


1.4 为什么需要Mybatis?


帮助程序员将数据存储到数据库中

方便、传统的JDBC代码太复杂,Mybatis框架更容易上手

简单易学、灵活

sql和代码的分离,提高了可维护性。

提供映射标签,支持对象与数据库

orm字段关系映射

提供对象关系映射标签,支持对象关系组建维护

提供xml标签,支持编写动态sql。

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

二、第一个Mybatis程序


思路:


1.创建父工程 引入mysql mybatis Junit 依赖


2.maven子工程 编写mybatis核心配置文件 mybatis-config.xml 连接数据库


3.untils层 pojo层 dao层


4.编写mybatis工具类 编写实体类


5.编写Mapper接口 以及对应UseMapper.xml配置文件


6.Junit测试

1665318211112.jpg


2.1 新建项目


建立mysql数据库


CREATE DATABASE MYBATIS;
USE MYBATIS;
CREATE TABLE user(
id INT(20) NOT NULL PRIMARY KEY,
name VARCHAR(30) DEFAULT NULL,
pwd VARCHAR(30) DEFAULT NULL
)ENGINE = INNODB DEFAULT CHARSET = utf8;
INSERT INTO user(id, name, pwd) VALUES 
(1, '孙孙孙', 2002),
(2, '铭铭铭', 1208),
(3, '孙不坚', 1234);

新建项目

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

2.删除src目录

3.导入maven依赖


将该工程当做父工程

 <!--导入依赖-->
    <dependencies>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!--mybatis驱动-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.3</version>
        </dependency>
        <!--junit驱动-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

4.创建子工程


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&amp;serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="sm1208"/>
            </dataSource>
        </environment>
    </environments>
    <!--每一个Mapper.xml都需要Mybatis核心配置文件中注册!-->
    <mappers>
        <mapper resource="com/sun/dao/UserMapper.xml"/>
    </mappers>
</configuration>

编写Mybatis的工具类

package com.sun.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 = null;
    static {
        try {
            // 使用Mybatis 第一步:获取sqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream in = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // 有了SqlSessionFactory,顾名思义,我们就可以从中获得 SqlSession 的实例了
    // SqlSession  完全包含了面向数据库执行 SQL 命令所需要的所有方法
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

2.3 编写代码


实体类

package com.sun.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 + '\'' +
                '}';
    }
}

Mapper接口


package com.sun.dao;
import com.sun.pojo.User;
import java.util.List;
public interface UserMapper {
    //查询所有的用户
    List<User> getUserList();
}

接口实现类,由原来的UserDaoImp转变为一个Mapper配置文件,即UseMapper.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.sun.dao.UserMapper">
    <!-- select查询语句 -->
    <select id="getUserList" resultType="com.sun.pojo.User">
        select * from mybatis.user;
    </select>
</mapper>

2.4 测试


junit 测试

package com.sun.dao;
import com.sun.pojo.User;
import com.sun.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserMapperTest {
    @Test
    public void test(){
        // 第一步:获取SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        // 方式一:getMapper
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.getUserList();
        for (User user :
                userList) {
            System.out.println(user);
        }
        // 关闭 SqlSession
        sqlSession.close();
    }
}

2.5 常见问题

a 解决maven引入依赖资源过滤问题

  <!-- 在build中配置resources,防止资源导出失败的问题 -->
    <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>

b 解决xml文件中文字符集产生报错的问题

//引入依赖
<!--    <properties>-->
<!--        &lt;!&ndash; 设置默认编码 &ndash;&gt;-->
<!--        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>-->
<!--    </properties>-->

c 核心配置文件中注册 mappers

注意点:org.apache.ibatis.binding.BindingException: Type interface com.xulong.dao.UserDao is not known to the MapperRegistry.


 <!--每一个Mapper.xml都需要Mybatis核心配置文件中注册!-->
    <mappers>
        <mapper resource="com/sun/dao/UserMapper.xml"/>
    </mappers>

三、CRUD


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


在xml文件sql


id : 就是对应的 namespace 中的方法名

resultType : Sql 语句执行的返回值

parameterType :参数类型

编写接口 编写对应Mapper中的sql语句 编写测试


增 删 改 需要提交事务 !


1. Select


//根据ID查询用户
User getUserByID(int id);
<select id="getUserByID" parameterType="int" resultType="com.sun.pojo.User">
  select * from mybatis.user where id = #{id};
</select>
@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();
}

2. Insert

int addUser(User user);
<!-- 对象中的属性可以直接取出来 -->
<insert id="addUser" parameterType="com.sun.pojo.User">
  insert into mybatis.user (id, name, pwd) values (#{id}, #{name}, #{pwd});
</insert>
@Test
public void addUser(){
  SqlSession sqlSession = MybatisUtils.getSqlSession();
  UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  User user = new User(4, "孙明明", "1324214");
  int result = mapper.addUser(user);
  if (result > 0){
  System.out.println("插入成功!");
  }
  //提交事务
  sqlSession.commit();
  sqlSession.close();
}

3. Updata


//修改用户
int updateUser(User user);
<update id="updateUser" parameterType="com.sun.pojo.User">
  update mybatis.user set name = #{name}, pwd = #{pwd} where id = #{id};
</update>
@Test
    public void updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = new User(5, "旺财", "14432434");
        mapper.updateUser(user);
        int result = mapper.updateUser(user);
        if (result > 0){
            System.out.println("修改成功!");
        }
        sqlSession.commit();
        sqlSession.close();
    }

4. Delete

//删除用户
int deleteUser(int id);
<delete id="deleteUser" parameterType="int">
  delete from mybatis.user where id = #{id};
</delete>
@Test
public void deleteUser(){
  SqlSession sqlSession = MybatisUtils.getSqlSession();
  UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  mapper.deleteUser(4);
  sqlSession.commit();
  sqlSession.close();
}

5. Map


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


//万能的Map
int addUser1(Map<String, Object> map);
<!-- 对象中的属性可以直接取出来    传递Map中的key -->
<insert id="addUser1" parameterType="Map">
  insert into mybatis.user (id, name, pwd) values (#{userid}, #{username}, #{password});
</insert>
@Test
public void addUser1(){
  SqlSession sqlSession = MybatisUtils.getSqlSession();
  UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  Map<String, Object> map = new HashMap<>();
  map.put("userid", 5);
  map.put("username", "赵六");
  map.put("password", "144324324");
  mapper.addUser1(map);
  sqlSession.close();
}

Map传递参数,直接在sql中取出key即可【parameterType=“Map”】

对象传递参数,直接在sql中取对象的属性即可【parameterType=“Object”】

只有一个基本类型参数的情况下,可以直接在sql中取到,不需要parameterType的设置

多个参数用Map,或者注解


四、核心配置解析


mybatis-config.xml配置解析

1665318628163.jpg

1. 属性 (properties)


xml里属性都是可外部配置且可动态替换的,我们可以通过properties属性来实现引用配置文件。


编写一个配置文件 db.properties


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

在核心配置文件中引入


直接引入外部文件


<!-- 引入外部配置文件 -->

<properties resource="db.properties"> </properties>


可以在其中增加一些属性配置


<!-- 引入外部配置文件 -->
<properties resource="db.properties">
  <property name="username" value="root"/>
  <property name="password" value="sm1208"/>
</properties>

如果两个文件有同一个字段,优先使用外部配置文件

2. 设置 (settings)

1665318705152.jpg



3. 类型别名(typeAliases)


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


第一种配置方式 ,User 可以用在任何使用 com.sun.pojo.User 的地方使用。


<typeAliases>
  <typeAlias alias="User" type="com.sun.pojo.User"/>
</typeAliases>

第二种配置方式,指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,例如:

扫描实体类pojo的包,它的默认别名就为这个类的类名User。

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

在实体类比较少的情况,推荐使用第一种方式,如果实体类多的情况下,建议使用第二种方式,第一种可以DIY别名,第二种则不行,如果想实现第二种的DIY,在第二种配置方式的基础上还需要在实体类上增加注解:


import org.apache.ibatis.type.Alias;
@Alias("hello")
public class User {
}

4. 类型处理器(typeHandlers)

5. 对象工厂(objectFactory)

6. 插件(plugins)

7. 环境配置(environments)

MyBatis 可以配置成适应多种环境,尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。


默认使用的环境 ID(比如:default=“development”)。

每个 environment 元素定义的环境 ID(比如:id=“development”)。

事务管理器的配置(比如:type=“JDBC”)。

数据源的配置(比如:type=“POOLED”)。

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


8. 数据库厂商标识(databaseIdProvider)

9. 映射器(mappers)

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


【推荐使用】


<!-- 使用相对于类路径的资源引用  --> 
<mappers>
  <mapper resource="com/sun/dao/UserMapper.xml"/>
</mappers>

使用class文件进行绑定


<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="com.sun.dao.UserMapper"/>
</mappers>

接口和其对应的Mapper配置文件必须同名

接口和其对应的Mapper配置文件必须在同一个包下

使用扫描包进行注入绑定


<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="com.sun.dao"/>
</mappers>

接口和其对应的Mapper配置文件必须同名

接口和其对应的Mapper配置文件必须在同一个包下

10. 生命周期和作用域


五、使用注解开发


1. 面向接口编程

大家之前都学习过面向对象编程,也学习过接口,但在真正的开发中,很多时候我们会选择面向接口编程。

根本原因:解耦,可拓展,提高复用,分层开发中,上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好。

在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协助完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了。

而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大道各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是按照这种思想来编程。


关于接口的理解


接口从更深层次的理解,应是定义(规范、约束)与实现(名实分离的原则)的分离。

接口的本身反映了系统设计人员对系统的抽象理解。

接口应有两种

第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class)

第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface)

一个体可能有多个抽象面,抽象体和抽象面是有区别的。


三个面向区别


面向向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法。

面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现。

接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题,更多的体现就是对系统整体的架构。


2. 使用注解开发


注解在接口上实现


@Select("select * from user")
List<User> getUsers();

在核心配置文件中绑定接口


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

测试

@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();
}

本质:反射机制实现

底层:动态代理


Mybatis详细执行流程

1665318897137.jpg



3.注解-CRUD


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


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

编写接口,添加注解

@Select("select * from user")
List<User> getUsers();
// 方法中如果有多个参数,那么每一个参数前都必须加上@Param("")
@Select("select * from user where id = #{id}")
User getUserByID(@Param("id") int id);
//    User getUserByID(@Param("id") int id, @Param("name") String name);
@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(@Param("id") int id);

测试类


【注意,我们必须要将接口绑定到核心配置文件mybatis-config.xml文件中】


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

持续更新中…


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
缓存 JavaScript
运行vue报错npm ERR! A complete log of this run can be found in解决办法
在这里我们需要清除npm的缓存: (1)在cmd命令行窗口中输入:npm cache clean --force (2)然后再运行我们需要安装模块的命令,输入npm install。 有时是网络问题,依赖包加载不完整,删掉node_modules文件后,重新执行npm install即可。
2757 0
|
移动开发 关系型数据库 PostgreSQL
PostgreSQL 条件判断函数
PostgreSQL 条件判断函数
1111 1
|
机器人 BI vr&ar
伙伴客户案例|阿里云RPA助力制造零售企业降本增效 ——财务场景篇
RPA全称机器人流程自动化(Robotic Process Automation),是一种新兴的“数字劳动力”,可以替代或辅助人完成规则明确的重复性劳动,大幅提升业务流程效率,实现企业业务流程的自动化和智能化,从而降本增效。目前,RPA解决方案的应用场景几乎涵盖了所有行业,包括银行、保险、制造、零售、医疗、物流、电子商务甚至政府和公共机构。
3147 3
伙伴客户案例|阿里云RPA助力制造零售企业降本增效 ——财务场景篇
|
分布式计算 资源调度 Hadoop
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
2069 1
|
机器学习/深度学习 存储 自然语言处理
使用Python实现深度学习模型:语言翻译与多语种处理
【7月更文挑战第21天】 使用Python实现深度学习模型:语言翻译与多语种处理
612 0
|
小程序
小程序 define is not defined
小程序 define is not defined
306 0
|
存储 关系型数据库 数据管理
在 Postgres 中使用 Create Table
【8月更文挑战第11天】
1369 0
在 Postgres 中使用 Create Table
|
数据可视化 程序员
IDEA插件-Rainbow Variable/IDEA彩色变量
"Rainbow Variable"是一款用于 IntelliJ IDEA 的插件,旨在提高代码中变量的可视化区分度。通过使方法中的参数和变量呈现不同的颜色,提高代码可读性。 插件允许用户自定义颜色,使得在同一个函数内部相同的变量采用相同的颜色,从而避免误用。
2792 0
IDEA插件-Rainbow Variable/IDEA彩色变量
|
移动开发 前端开发 JavaScript
技术笔记:sortable的基本属性
技术笔记:sortable的基本属性
332 0