MyBatis详解【上】

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: MyBatis 环境: JDK,Mysql,Maven,IDEA 回顾: JDBC,Mysql,Java基础,Maven,Junit 框架:有配置文件。最好的方式:看官网文档。 1、简介 1.1、什么是MyBatis? MyBatis 是一款优秀的持久层框架 它支持自定义 SQL、存储过程以及高级映

MyBatis


环境:

JDK,Mysql,Maven,IDEA


回顾:

JDBC,Mysql,Java基础,Maven,Junit


框架:有配置文件。最好的方式:看官网文档。


1、简介


1.1、什么是MyBatis?


  • MyBatis 是一款优秀的持久层框架


  • 它支持自定义 SQL、存储过程以及高级映射。


  • MyBatis免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。


  • MyBatis可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。



  • 2013年11月迁移到Github


如何获得MyBatis?


  • maven仓库:


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




1.2、持久化


数据持久化


  • 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
  • 内存:断电即失
  • 数据库(jdbc),io文件持久化。
  • 生活:冷藏,罐头。


为什么需要持久化?


  • 有一些对象,不能让他丢掉。
  • 内存太贵了


1.3、持久层


Dao层,Service层,Controller层...

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


1.4、为什么需要MyBatis?


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


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


Spring SpringMVC SpringBoot


1.5、MyBatis的三个核心接口


SqlSessionFactoryBuilder,SqlSessionFactory,SqlSession


2、第一个MyBatis程序


思路:搭建环境-->导入MyBatis-->编写代码-->测试!


程序流程:



2.1、搭建环境


搭建数据库


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,'狂神','123456'),(2,'张三','123456'),(3,'李四','123456')


新建项目

  1. 新建一个普通的maven项目
  2. 删除src目录
  3. 导入maven依赖


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


2.2、创建一个模块


  • 编写mybatis的核心配置文件


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=true&amp;serverTimezone=GMT"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!--    <mappers>-->
    <!--        <mapper resource="org/mybatis/example/BlogMapper.xml"/>-->
    <!--    </mappers>-->
</configuration>


  • 编写mybatis工具类


//工具类 SqlSessionFactory --> SqlSession
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            //使用Mybatis第一步:获取SqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //既然有了SqlSessionFactory,顾名思义,我们就可以从中获得SqlSession的实例了。
    //SqlSession完全包含了面向数据库执行SQL命令所需的所有方法。
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}


2.3、编写代码


  • 实体类


//实体类
public class User {
    private int id;
    private String name;
    private String pwd;
    public User() {
    }
    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}


  • Dao接口


public interface UserDao {
    List<User> getUserList();
}


  • 接口实现类由原来的UserDaoImpl转换为一个Mapper配置文件


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.kuang.dao.UserDao">
    <!--select查询语句-->
    <select id="getUserList" resultType="com.kuang.pojo.User">
        select * from mybatis.user;
    </select>
</mapper>


2.4、测试


注意点:

org.apache.ibatis.binding.BindingException: Type interface com.kuang.dao.UserDao is not known to the MapperRegistry.


MapperRegistry是什么?


核心配置文件中注册mappers


  • junit测试


public class UserDaoTest {
    @Test
    public void test(){
        //第一步:获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //执行SQL  方式一:getMapper
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        List<User> userList = mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
        //关闭SqlSession
        sqlSession.close();
    }
}


测试中遇到的问题:


  1. 配置文件没有注册


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


  1. 绑定接口错误


  1. 方法名不对


  1. 返回类型不对


  1. Maven导出资源问题


<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>


3、CRUD


1、namespace


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


2、select


选择,查询语句;

  • id:就是对应的namespace中的方法名;
  • resultType:Sql语句执行的返回值! Class,
  • parameterType:参数类型


写接口-->配置文件中写sql-->测试

  1. 编写接口
  2. 编写对应的mapper中的sql
  3. 测试


3、Insert,Update,Delete


  1. 编写接口


public interface UserMapper {
    //查询全部用户
    List<User> getUserList();
    //根据ID查询用户
    User getUserById(int id);
    //insert一个用户
    int addUser(User user);
    //修改用户
    int updateUser(User user);
    //删除一个用户
    int deleteUser(int id);
}


  1. 编写对应的mapper中的sql


<?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.kuang.dao.UserMapper">
    <!--select查询语句-->
    <select id="getUserList" resultType="com.kuang.pojo.User">
        select * from mybatis.user;
    </select>
    <select id="getUserById" parameterType="int" resultType="com.kuang.pojo.User">
        select * from mybatis.user where id = #{id};
    </select>
    <!--对象中的属性,可以直接取出来-->
    <insert id="addUser" parameterType="com.kuang.pojo.User">
        insert into mybatis.user (id, name, pwd) VALUES (#{id},'#{name}','#{pwd}');
    </insert>
    <update id="updateUser" parameterType="com.kuang.pojo.User">
        update mybatis.user
        set name = #{name}, pwd = #{pwd}
        where id = #{id};
    </update>
    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id = #{id};
    </delete>
</mapper>


  1. 测试


public class UserMapperTest {
    @Test
    public void test(){
        //第一步:获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //执行SQL  方式一:getMapper
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        //方式二:
        //List<User> userList = sqlSession.selectList("com.kuang.dao.UserDao.getUserList");
        for (User user : userList) {
            System.out.println(user);
        }
        //关闭SqlSession
        sqlSession.close();
    }
    @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 addUserTest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int res = mapper.addUser(new User(4, "hh", "123456"));
        if (res>0){
            System.out.println("插入成功!");
        }
        //提交事务
        sqlSession.commit();
        sqlSession.close();
    }
    @Test
    public void updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int res = mapper.updateUser(new User(4, "王五", "123456"));
        if (res>0){
            System.out.println("修改成功!");
        }
        sqlSession.commit();
        sqlSession.close();
    }
    @Test
    public void deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int res = mapper.deleteUser(4);
        if (res>0){
            System.out.println("删除成功!");
        }
        sqlSession.commit();
        sqlSession.close();
    }
}


注意点:

  • 增删改需要提交事务!


4、分析错误


  • 标签不要匹配错


  • resource绑定mapper,需要使用路径!


  • 程序配置文件必须符合规范!


  • NullPointerException,没有注册到资源!


  • 输出的xml文件中存在中文乱码问题!


  • maven资源没有导出问题!


5、万能的Map


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


//万能的Map
int addUser2(Map<String,Object> map);
===================================================================================
@Test
public void addUser2(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("userid",5);
    map.put("username","赵六");
    map.put("password","123456");
    mapper.addUser2(map);
    sqlSession.commit();
    sqlSession.close();
}


<!--对象中的属性,可以直接取出来 传递map的key-->
<insert id="addUser2" parameterType="map">
    insert into mybatis.user (id,name,pwd) values (#{userid},#{username},#{password})
</insert>


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


对象传递参数,直接在sql中取对象的属性即可!


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


多个参数用Map,或者注解!


6、思考题


模糊查询怎么写?


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


List<User> users = mapper.getUserLike("%李%");


  1. 在sql拼接中使用通配符!


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

4、配置解析


1、核心配置文件


  • mybatis-config.xml
  • MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。


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


2、环境配置(environments)


MyBatis可以配置成适应多种环境


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


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


MyBatis默认的事务管理器就是JDBC,连接池:POOLED


3、属性(properties)


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

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



编写一个配置文件


db.properties


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


在核心配置文件中引入


<!--引入外部配置文件,优先使用外部配置文件-->
<properties resource="db.properties">
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</properties>


  • 可以直接引入外部文件


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


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


4、类型别名(typeAliases)


  • 类型别名可为 Java 类型设置一个缩写名字。


  • 它仅用于 XML 配置,意在降低冗余的全限定类名书写。


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


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

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


<!--可以给实体类起别名-->
<typeAliases>
    <package name="com.kuang.pojo"/>
</typeAliases>


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

如果实体类十分多,建议使用第二种。

第一种可以DIY别名,第二种则不行,如果非要改,需要在实体类上增加注解


@Alias("hello")
public class User {


5、设置


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




6、其他配置


  • typeHandlers(类型处理器)


  • objectFactory(对象工厂)


  • plugins插件
  • mybatis-generator-core
  • mybatis-plus
  • 通用mapper


7、映射器(mapper)


MapperRegistry:注册绑定我们的Mapper文件;


方式一:【推荐使用】


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


方式二:使用class文件绑定注册


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


注意点:

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


方式三:使用扫描包进行注入绑定


<!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!-->
<mappers>
    <package name="com.kuang.dao"/>
</mappers>


注意点:

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


练习时间:

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


8、生命周期和作用域



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

SqlSessionFactoryBuilder:

  • 一旦创建了 SqlSessionFactory,就不再需要它了。
  • 局部变量


SqlSessionFactory:

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


SqlSession:

  • 连接到连接池的一个请求!
  • SqlSession的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
  • 用完之后需要赶紧关闭,否则资源被占用!



这里面的每一个Mapper,就代表一个具体的业务!


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

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2天前
|
SQL 缓存 Java
|
6月前
|
SQL Java 数据库连接
|
SQL XML Java
|
22天前
|
SQL 缓存 Java
Mybatis
【10月更文挑战第5天】Mybatis
21 0
|
29天前
|
SQL 缓存 Java
Mybatis知识
Mybatis知识
35 0
|
SQL Java 数据库连接
Mybatis之discriminator(鉴别器)详解
前言 最近干了一个工作是使用discriminator去写一个新的API,那么写这个新的API原因是什么呢?原因是这样的:我们的项目使用Mybatis,我们项目中有一个实体类叫做User,在User中还含有很多别的实体类,例如Role,Permission,Address等(有经验的肯定知道这种嵌套实体类的情况,使用和)。
4132 0
|
4月前
|
SQL Java 关系型数据库
MyBatis-Plus详解(4)
MyBatis-Plus详解(4)
36 0
|
11月前
|
Java 数据库连接 测试技术
mybatis中@Many
mybatis中@Many
91 0
|
Java 数据库连接 mybatis
MyBatis
MyBatis
58 0
|
SQL XML 缓存
了解mybatis
了解mybatis
64 0