Mybatis学习笔记之Mybatis的快速开始

1 Mybatis简介

1.1 什么是Mybatis?

它是一款半自动ORM持久层框架,具有较高的SQL灵活性,支持高级映射(一对一,一对多),动态SQL,延迟加载和缓存等特性,但它的数据库无关性较低.
Mybatis官方文档
GitHub地址

持久化是什么

持久化是将程序数据在持久状态和瞬时状态间转换的机制。

  • 即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等。
  • JDBC就是一种持久化机制。文件IO也是一种持久化机制。
  • 在生活中 : 将鲜肉冷藏,吃的时候再解冻的方法也是。将水果做成罐头的方法也是。

为什么需要持久化服务呢?那是由于内存本身的缺陷引起的

  • 内存断电后数据会丢失,但有一些对象是无论如何都不能丢失的,比如银行账号等,遗憾的是,人们还无法保证内存永不掉电。
  • 内存过于昂贵,与硬盘、光盘等外存相比,内存的价格要高2~3个数量级,而且维持成本也高,至少需要一直供电吧。所以即使对象不需要永久保存,也会因为内存的容量限制不能一直呆在内存中,需要持久化来缓存到外存。

持久层又是什么呢

  • 完成持久化工作的代码块 . ----> dao层 【DAO (Data Access Object) 数据访问对象】
  • 大多数情况下特别是企业级应用,数据持久化往往也就意味着将内存中的数据保存到磁盘上加以固化,而持久化的实现过程则大多通过各种关系数据库来完成。
  • 不过这里有一个字需要特别强调,也就是所谓的“层”。对于应用系统而言,数据持久功能大多是必不可少的组成部分。也就是说,我们的系统中,已经天然的具备了“持久层”概念?也许是,但也许实际情况并非如此。之所以要独立出一个“持久层”的概念,而不是“持久模块”,“持久单元”,也就意味着,我们的系统架构中,应该有一个相对独立的逻辑层面,专注于数据持久化逻辑的实现.

ORM是啥?

Object Relation Mapping,对象关系映射。对象指的是Java对象,关系指的是数据库中的关系模型,对象关系映射,指的就是在Java对象和数据库的关系模型之间建立一种对应关系,比如用一个Java的Student类,去对应数据库中的一张student表,类中的属性和表中的列一一对应。Student类就对应student表,一个Student对象就对应student表中的一行数据

那么为什么说mybatis是半自动的ORM框架?

用mybatis进行开发,需要手动编写SQL语句。而全自动的ORM框架,如hibernate,则不需要编写SQL语句。用hibernate开发,只需要定义好ORM映射关系,就可以直接进行CRUD操作了。由于mybatis需要手写SQL语句,所以它有较高的灵活性,可以根据需要,自由地对SQL进行定制,也因为要手写SQL,当要切换数据库时,SQL语句可能就要重写,因为不同的数据库有不同的方言(Dialect),所以mybatis的数据库无关性低。虽然mybatis需要手写SQL,但相比JDBC,它提供了输入映射和输出映射,可以很方便地进行SQL参数设置,以及结果集封装。并且还提供了关联查询和动态SQL等功能,极大地提升了开发的效率。并且它的学习成本也比hibernate低很多

1.2 Mybais的第一个程序

思路流程:搭建环境–>导入Mybatis—>编写代码—>测试
而在编写代码时只需要通过如下几个步骤,即可用mybatis快速进行持久层的开发

该程序最后的项目文件架构如下:
在这里插入图片描述

1、搭建实验数据库


CREATE DATABASE `mybatis`;
 
USE `mybatis`;
 
DROP TABLE IF EXISTS `user`;
 
CREATE TABLE `user` (
  `id` int(20) NOT NULL,
  `name` varchar(30) DEFAULT NULL,
  `pwd` varchar(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
insert  into `user`(`id`,`name`,`pwd`) values (1,'偷学者1号','123456'),(2,'偷学者2号','abcdef'),(3,'偷学者3号','987654');

在这里插入图片描述

2、打开IDEA,创建一个maven项目
在这里插入图片描述

3、导入相关的jar 包

 <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
<!--         lombok插件依赖的导入 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.8.1</version>
            <scope>test</scope>
        </dependency>
<!--         log4j依赖的导入 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory><!--所在的目录-->
                <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory><!--所在的目录-->
                <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

4、配置log4j配置文件

#将等级为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

5、配置数据源db.properties文件
这个要根据自己数据库所在的IP地址与密码

db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://192.168.10.104:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8
db.user=root
db.password=12345678

6、编写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>
    <!-- 配置文件信息 -->
    <properties resource="db.properties"></properties>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!-- 从配置文件中加载属性 -->
                <property name="driver" value="${db.driver}"/>
                <property name="url" value="${db.url}"/>
                <property name="username" value="${db.user}"/>
                <property name="password" value="${db.password}"/>
            </dataSource>
        </environment>
    </environments>

</configuration>

7、配置MybatisUtils工具类,来加载全局配置文件和生成SqlSessionFactory

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static{
        try{
            String resource ="mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static SqlSession getSession(){
        return sqlSessionFactory.openSession();
    }

}

8、创建User实体类
这里为例防止代码冗余,我使用了Lombok插件,不会的可以去搜索如何使用,非常方便。

@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
    private int id;
    private String name;
    private String pwd;
}

9、编写映射接口:

import com.zjw.bean.User;

import java.util.List;

public interface UserMapper {
    List<User> selectUser();
}

10、编写对应的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">
<mapper namespace="com.zjw.Dao.UserMapper">
  <select id="selectUser" resultType="com.zjw.Dao.User">
    select * from user
  </select>
</mapper>

11、编写完mapper映射文件后去全局配置文件中去注册

     <mappers>
            <mapper resource="com/zjw/Dao/UserMapper.xml"/>
       </mappers>

12、编写测试类

public class MyTest {
    @Test
    public void selectUser() {
        SqlSession session = MybatisUtils.getSession();
        //方法一:
        List<User> users = session.selectList("com.zjw.Dao.UserMapper.selectUser");
                //方法二:
//        UserMapper mapper = session.getMapper(UserMapper.class);
        for (User user: users){
            System.out.println(user);
        }
        session.close();
    }
}

13、启动测试类,出现结果:
在这里插入图片描述
不过根据整个简单的项目代码来看,我们仅仅为了完成一个select操作,好像创建了许多的XML配置文件,那么似乎与他方便的特点相反呀,但其实我们在后续的编写SQL语句就非常的轻松,因为在一个 XML 映射文件中,可以定义无数个映射语句,后面我们只需要在Mapper文件中添加定义,然后在对应的XML文件编写sQL语句就可以了。

总结:
搭建好了一个环境之后,进行SQL操作,就是重复以下几个步骤:

  1. 编写mapper接口,声名SQL的方法
  2. 编写mapper.xml,书写SQL,并定义好SQL的输入参数,和输出参数
  3. 编写全局配置文件,配置数据源,以及要加载的mapper.xml文件
  4. 通过全局配置文件,创建SqlSessionFactory
  5. 每次进行CRUD时,通过SqlSessionFactory创建一个SqlSession
  6. 调用SqlSession上的selectOne,selectList,insert,delete,update等方法,传入mapper.xml中SQL标签的id,以及输入参数

1.3 搭建项目中容易出现的问题

1、配置文件中namespace中的名称为对应Mapper接口或者Dao接口的完整包名不一致
例如Mapper的映射文件
在这里插入图片描述
以及全局配置文件中注册的mapper地址
在这里插入图片描述

2、db.properties配置的属性名字与Mybatis全局配置名字不一致
在这里插入图片描述
在这里插入图片描述
3、出现找不到mapper映射文件的错误
这样的情况出现的原因我知道的有两种情况

  1. 注册的时候文件分割符使用的是.而不是/
    在这里插入图片描述
  2. 或者去生成的target的文件夹下看看有没有mapper映射文件
    在这里插入图片描述
    如果没有的话可以直接复制粘过去就行,然后在pom文件中加入以下代码防止之后再次出现这种情况,我之前给出的代码中已经加上了这个,不要重复。
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory><!--所在的目录-->
                <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory><!--所在的目录-->
                <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

4、明明数据库中的用户名与密码均填写正确却出现连接超时的情况
可以看看自己的这个是true还是false
在这里插入图片描述

1.4 项目搭建过程中的一些详细说明

1.4.1 全局配置文件的标签说明与顺序

注意在全局配置文件中,各个标签要按照如下顺序进行配置,因为mybatis加载配置文件的源码中是按照这个顺序进行解析的

<configuration>
	<!-- 配置顺序如下
     properties  

     settings

     typeAliases

     typeHandlers

     objectFactory

     plugins

     environments
        environment
            transactionManager
            dataSource

     mappers
     -->
</configuration>

各个子标签说明如下:

  1. <properties>
    一般将数据源的信息单独放在一个properties文件中,然后用这个标签引入,在下面environment标签中,就可以用${}占位符快速获取数据源的信息。例如我们前面给出的mybatis-config.xml中的代码
    在这里插入图片描述

  2. <settings>
    用来开启或关闭mybatis的一些特性,比如可以用<setting name="lazyLoadingEnabled" value="true"/>开启延迟加载,可以用<settings name="cacheEnabled" value="true"/>开启二级缓存

  3. <typeAliases>
    在mapper.xml中需要使用parameterTyperesultType属性来配置SQL语句的输入参数类型和输出参数类型,类必须要写上全限定名,比如一个SQL的返回值映射为User类,则resultType属性要写com.zjw.Dao.User,这太长了,所以可以用别名来简化书写,比如我在mybatis-config.xml中加入以下代码:

    <typeAliases>
    	<typeAlias type="com.zjw.Pojo.User" alias="user"/>
    </typeAliases>
    

    然后修改UserMapper.xml代码,从而达到代码不那么繁琐的目的:
    在这里插入图片描述
    当然,如果想要一次性给某个包下的所有类设置别名,可以用如下的方式

    <typeAliases>
       <package name="com.zjw.bean"/>
    </typeAliases>
    

    如此,指定包下的所有类,都会以简单类名的小写形式,作为它的别名

  4. <typeHandlers>(不经常用)
    用于处理Java类型和Jdbc类型之间的转换,mybatis有许多内置的TypeHandler,比如StringTypeHandler,会处理Java类型String和Jdbc类型CHAR和VARCHAR。这个标签用的不多

  5. <objectFactory>(不经常用)
    mybatis会根据resultType或resultMap的属性来将查询得到的结果封装成对应的Java类,它有一个默认的DefaultObjectFactory,用于创建对象实例,这个标签用的也不多

  6. <plugins>
    可以用来配置mybatis的插件,比如在开发中经常需要对查询结果进行分页,就需要用到pageHelper分页插件,这些插件就是通过这个标签进行配置的。在mybatis底层,运用了责任链模式+动态代理去实现插件的功能。

    <!-- PageHelper 分页插件 -->
    <plugins>
      <plugin interceptor="com.github.pagehelper.PageInterceptor">
         <property name="helperDialect" value="mysql"/>
      </plugin>
    </plugins>
    
    
  7. <environments>
    用来配置数据源

  8. <mappers>
    用来配置mapper.xml映射文件,这些xml文件里都是SQL语句。而在实际工作中,一般我们会将一张表的SQL操作封装在一个mapper.xml中 ,可能有许多张表需要操作,那么我们是不是要在<mappers>标签下写多个<mapper>标签呢?其实不用,还有第三种加载mapper的方法,使用<package>标签

    <mappers>
        <package name="com.zjw.Dao"/>
    </mappers>
    

    这样就会自动加载com.zjw.Dao包下的所有mapper,这种方式需要将mapper接口文件和mapper.xml文件都放在com.zjw.Daor包下,且接口文件和xml文件的文件名要一致。
    三种加载mapper的方式总结

    1. 加载普通的xml文件,传入xml的相对路径(相对于类路径)
    <!-- 使用相对于类路径的资源引用 -->
    <mappers>
      <mapper resource="org/mybatis/builder/PostMapper.xml"/>
    </mappers>
    
    1. 使用完全限定资源定位符(URL)
    <!-- 使用完全限定资源定位符(URL) -->
    <mappers>
      <mapper url="file:///var/mappers/AuthorMapper.xml"/>
    </mappers>
    
    1. 使用映射器接口实现类的完全限定类名(需要配置文件名称和接口名称一致,并且位于同一目录下)
    <!--
    使用映射器接口实现类的完全限定类名
    需要配置文件名称和接口名称一致,并且位于同一目录下
    -->
    <mappers>
      <mapper class="org.mybatis.builder.AuthorMapper"/>
    </mappers>
    
1.4.2 mapper接口和mapper.xml之间遵循的规则

mapper接口和mapper.xml之间需要遵循一定规则,才能成功的让mybatis将mapper接口和mapper.xml绑定起来

  1. mapper接口的全限定名,要和mapper.xml的namespace属性一致
  2. mapper接口中的方法名要和mapper.xml中的SQL标签的id一致
  3. mapper接口中的方法入参类型,要和mapper.xml中SQL语句的入参类型一致
  4. mapper接口中的方法出参类型,要和mapper.xml中SQL语句的返回值类型一致
1.4.3 SqlSession的作用域(Scope)和生命周期

理解我们目前已经讨论过的不同作用域和生命周期类是至关重要的,因为错误的使用会导致非常严重的并发问题。

我们可以先画一个流程图,分析一下Mybatis的执行过程!
在这里插入图片描述
作用域理解

  • SqlSessionFactoryBuilder 的作用在于创建 SqlSessionFactory,创建成功后,SqlSessionFactoryBuilder 就失去了作用,所以它只能存在于创建 SqlSessionFactory 的方法中,而不要让其长期存在。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
  • SqlSessionFactory 可以被认为是一个数据库连接池,它的作用是创建 SqlSession 接口对象。因为 MyBatis 的本质就是 Java 对数据库的操作,所以 SqlSessionFactory 的生命周期存在于整个 MyBatis 的应用之中,所以一旦创建了 SqlSessionFactory,就要长期保存它,直至不再使用 MyBatis 应用,所以可以认为 SqlSessionFactory 的生命周期就等同于 MyBatis 的应用周期。
  • 由于 SqlSessionFactory 是一个对数据库的连接池,所以它占据着数据库的连接资源。如果创建多个 SqlSessionFactory,那么就存在多个数据库连接池,这样不利于对数据库资源的控制,也会导致数据库连接资源被消耗光,出现系统宕机等情况,所以尽量避免发生这样的情况。
    因此在一般的应用中我们往往希望 SqlSessionFactory 作为一个单例,让它在应用中被共享。所以说 SqlSessionFactory 的最佳作用域是应用作用域。
  • 如果说 SqlSessionFactory 相当于数据库连接池,那么 SqlSession 就相当于一个数据库连接(Connection 对象),你可以在一个事务里面执行多条 SQL,然后通过它的 commit、rollback 等方法,提交或者回滚事务。所以它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给 SqlSessionFactory,否则数据库资源就很快被耗费精光,系统就会瘫痪,所以用 try…catch…finally… 语句来保证其正确关闭。所以 SqlSession 的最佳的作用域是请求或方法作用域。

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤独的偷学者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值