mybatis快速入门

文章目录

1 MyBatis框架的概述

1.1 三层架构

mvc:web开发中,使用mvc架构模式。m:数据 v:视图 c:控制器

  • c:控制器:接收请求,调用service对象,显示请求的处理结果。当前使用servlet作为控制器
  • v:视图:显示请求的结果的结果,把m中数据显示出来。当前使用jsp,html,css,js等
  • m:数据:来自数据库mysql,来自文件,来自网络

mvc作用:

  • 实现解耦
  • 让mvc各司其职
  • 使得系统扩展更好

三层架构:

1.界面层(视图层):接收用户的请求,调用service,显示请求的处理结果。包含了jsp,html,servlet等对象。对应的包controller

2.业务逻辑层:处理业务逻辑,使用算法处理数据的。把数据返回给界面层。对应的是service包,和保重的很多XXXService类。例如:StudentService,OrderSerVice,ShopService

3.持久层(数据访问层):访问数据库,或者是读取文件,访问网络,获取数据。对应的包是dao。dao包中有很多的StudentDao,OrderDao,ShopDao等等

1.2 三层架构请求的处理流程

用户发起请求→界面层→业务逻辑层→持久层→数据库(mysql)

原理图如下:

pic_c0708459.png

1.3 为什么要使用三层

1.结构清晰、耦合度低。各层分工明确

2.可维护性高,可扩展性高

3.有利于保准化

4.开发人员可以只关注整个结构中的其中某一层的功能实现

5.有利于各层逻辑的复用

1.4 三层架构模式和框架

每一层对应着一个框架

  • 界面层—SpringMVC框架
  • 业务层—Spring框架
  • 持久层—Mybatis框架

MyBatis框架:

MyBatis是一个优秀的基于java的持久层框架,内部封装了jdbc,开发者只需要关注sql语句本身,而不需要处理加载驱动、创建连接、创建statement、关闭连接

Spring框架:
Spring框架为了解决软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前非常复杂的企业级开发。

SpringMVC框架:

SpringMVC属于SpringFrameWork3.0版本假如的一个模块,为Spring框架提供了构建Web应用程序的能力。

1.5 框架

什么是框架?

框架(Framework)是整个或不分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种认为,框架是可被应用开发者定制的应用模板。

    简单的说,框架其实就是半成品软件,就是一组组件,供你使用完成你自己的系统。从另一个角度来说框架时一个舞台,你再舞台上做表演,在框架基础上假如你要完成的功能。

    框架时安全的,可复用的,不断升级的软件。

    框架是对某一个方面是有用的,不是全能的。

1.6 框架解决的问题

1.框架能实现技术的整合

2.提高开发的效率,降低难度

1.7 jdbc访问数据库的优缺点

优点:

1.直观,好理解

缺点:

  • 创建创建很多对象Connection,Statement,ResultSet
  • 注册驱动
  • 执行sql语句
  • 把ResultSet转为Student,List集合
  • 关闭资源
  • sql语句和业务逻辑代码混为一起

1.8 MyBatis框架

什么是MyBatis?

MyBatis是一个持久层框架,原名是ibatis,2013年改名为MyBatis.

MyBatis可以操作数据库,对数据执行增删改查,看做是高级的JDBC,解决JDBC的缺点

MyBatis可以做什么?

1.注册驱动

2.创建jdbc中使用的Connection,Statement,ResultSet

3.执行sql语句,得到ResultSet

4.处理ResultSet,把记录集中的数据转为java对象,同时还能把java对象放入到List集合

5.关闭资源

6.实现sql语句和java代码的解耦合

2 MyBatis框架快速入门

2.1 使用MyBatis准备

学习文档:

mybatis – MyBatis 3 | 入门

我们按照这个学习路线来学习

在学习此教程之前你需要会这些知识:Java基础,JDBC,Maven

2.2 搭建MyBatis项目八步

2.2.1 创建mysql数据库和表

数据库名:ssm;表名:student

pic_abb53e93.png

插入一条数据:

pic_0cc48f0d.png

-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('1001', 'sa', 'sa', '55');

2.2.2 在idea中创建一个空项目

pic_8702667d.png

然后输入项目名

pic_d8f30078.png

创建完成之后,我们在里面添加Modules

pic_4dab0b26.png

创建一个Maven项目

pic_dfdf5b01.png

输入名字:

pic_9d8c9213.png

一直点next直到创建完成项目,创建完成后我们来查看项目的结构

pic_dbbc6a07.png

2.2.3 修改pom.xml文件

1)加入依赖:mybatis依赖,MySQL驱动,junit

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2)在加入资源插件

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

2.2.4 创建一个实体类Student

首先创建一个实体包,创建一个Student实体类

pic_e6e10254.png

定义属性,属性名和列名保持一致

package com.lu.entity;
 
public class Student {
   
     
     
    //属性名和列名保持一致
    private Integer id;
    private String name;
    private String email;
    private Integer age;
 
    public Integer getId() {
   
     
     
        return id;
    }
 
    public void setId(Integer id) {
   
     
     
        this.id = id;
    }
 
    public String getName() {
   
     
     
        return name;
    }
 
    public void setName(String name) {
   
     
     
        this.name = name;
    }
 
    public String getEmail() {
   
     
     
        return email;
    }
 
    public void setEmail(String email) {
   
     
     
        this.email = email;
    }
 
    public Integer getAge() {
   
     
     
        return age;
    }
 
    public void setAge(Integer age) {
   
     
     
        this.age = age;
    }
 
    @Override
    public String toString() {
   
     
     
        return "学生实体信息{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }
}

2.2.5 创建Dao接口,定义操作数据库的方法

创建dao包

pic_4f3a26d3.png

代码如下:

package com.lu.dao;
 
import com.lu.entity.Student;
 
public interface StudentDao {
   
     
     
    
    //查询一个学生
    Student selectStudentById(Integer id);
}

2.2.6 创建xml文件(mapper文件),写sql语句

mybatis框架推荐是把sql语句和java代码分开

mapper文件:定义和dao接口在同一目录,一个表一个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.lu.dao.StudentDao">
 
    <!--查询一个学生Student
        <select>:表示查询操作,里面是select语句
        id:要执行的sql语句的唯一标识,是一个自定义字符串
           推荐使用dao接口中的方法名称
        resultType:告诉mybatis,执行sql语句,把数据赋值给哪个类型的Java对象
                resultType的值现在使用的Java对象的全限定名称
    -->
    <select id="selectStudentById" resultType="com.lu.entity.Student">
        select id,name,email,age from student where id = 1001
    </select>
</mapper>
 
<!--
    1.约束文件
        http://mybatis.org/dtd/mybatis-3-mapper.dtd
        约束文件的作用:定义和限制当前文件中可以使用的标签和属性,以及标签出现的顺序
    2.mapper是根标签
        namespace:命名空间,必须有值,不能为空。唯一值
                   推荐使用Dao接口的全限定名称
        作用:参与识别sql语句的作用。
    3.在mapper里面可以写 <insert>,<update>,<delete>,<select>等标签
        <insert>里面是insert语句,表示执行的是insert操作
        <update>里面是update语句,表示执行的是update操作
        <delete>里面是delete语句,表示执行的是delete操作
        <select>里面是select语句,表示执行的是select操作
    -->

2.2.7 创建mybatis的主配置文件(xml文件):只有一个,放在resources目录下

1)定义创建连接实例的数据源(DataSource)对象

2)指定其他mapper文件的位置

<?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"/>
            <!--配置数据源:创建Connection对象-->
            <dataSource type="POOLED">
                <!--driver:驱动的内容-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <!--链接数据库的url-->
                <property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8"/>
                <!--用户名-->
                <property name="username" value="root"/>
                <!--密码-->
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
 
    <!--指定其他mapper文件的位置:
        指定其他mapper文件目的是找到其他文件的sql语句
    -->
    <mappers>
        <!--
            使用mapper的resource属性执行mapper文件的路径
            这个路径是从target/classes路径开启的
            使用注意:
            resource="mapper文件的路径,使用的是 \ 做分隔路径"
            一个mapper resource指定一个mapper文件
        -->
        <mapper resource="com\lu\dao\StudentDao.xml"/>
    </mappers>
</configuration>

2.2.8 创建测试的内容

使用main方法,测试mybatis访问数据库

也可以使用junit访问数据库

代码如下:

package com.lu;
 
import com.lu.entity.Student;
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 org.junit.Test;
 
import java.io.IOException;
import java.io.InputStream;
 
public class MyTest {
   
     
     
    //测试mybatis执行sql语句
    @Test
    public void testSelectStudentById() throws IOException {
   
     
     
        //调用mybatis某个对象方法,执行mapper文件中的sql语句
        //mybatis的个心累:SqlSessionFactory
 
        //1.定义mybatis主配置文件的位置,从类路径开始的相对路径
        String config = "mybatis.xml";
        //2.读取主配置文件,使用mybatis框架中的Resources类
        InputStream inputStream = Resources.getResourceAsStream(config);
        //3.创建SqlSessionFactory对象,使用SqlSessionFactoryBuilder类
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
 
        //4.获取SqlSession对象
        SqlSession session = factory.openSession();
 
        //5.指定要执行的sql语句的id
        //  sql语句的id = namespave + "." + select|update|insert|delete标签的id属性值
        String sqlId = "com.lu.dao.StudentDao" + "." + "selectStudentById";
 
        //6.通过SqlSession的方法来执行sql语句
        Student student = session.selectOne(sqlId);
        System.out.println("使用mybatis来查询一个学生:" + student);
 
        //7.关闭SqlSession对象
        session.close();
    }
}

控制台输出:

pic_766f822a.png

到这里我们已经实现了第一个MyBatis的例子

下面我们来修改一下代码,体验一下占位符

2.3 MyBatis使用占位符

我们修改StudentDao.xml文件中select语句

<select id="selectStudentById" resultType="com.lu.entity.Student">
    select id,name,email,age from student where id = #{studentId}
</select>

这样我们就使用了占位符,#{}

占位符表示从Java程序中传入过来的数据

我们修改测试代码

Student student = session.selectOne(sqlId, 1001);

重新执行代码,得到一样的输出

pic_852aaa03.png

2.4 MyBatis使用日志

2.4.1 日志的介绍

我们打开官方教程,看到可以一下几种日志供我们使用

pic_a30631cb.png

我们来看这一段话

pic_2e77776e.png

不少应用服务器(如 Tomcat 和 WebShpere)的类路径中已经包含 Commons Logging。注意,在这种配置环境下,MyBatis 会把 Commons Logging 作为日志工具。这就意味着在诸如 WebSphere 的环境中,由于提供了 Commons Logging 的私有实现,你的 Log4J 配置将被忽略。这个时候你就会感觉很郁闷:看起来 MyBatis 将你的 Log4J 配置忽略掉了(其实是因为在这种配置环境下,MyBatis 使用了 Commons Logging 作为日志实现)。如果你的应用部署在一个类路径已经包含 Commons Logging 的环境中,而你又想使用其它日志实现,你可以通过在 MyBatis 配置文件 mybatis-config.xml 里面添加一项 setting 来选择其它日志实现。

这段话的意思也就是或如果我们使用了类似于Tomcat,WebShpere之类的服务器,那么MyBatis会默认使用这些 服务器自带的Commons Logging作为日志工具。而如果我们还想使用其他日志来进行实现,我们必须在主配置文件中添加一项setting来选择其他日志实现。

格式如下:

<configuration>
  <settings>
    ...
    <setting name="logImpl" value="LOG4J"/>
    ...
  </settings>
</configuration>

name代表了我们日志的名称,而value的值是我们选择何种日志实现方式

可选的值有:SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、NO_LOGGING

我们一般使用的是LOG4J和STDOUT_LOGGING

结合我们昨天学习的东西,我们去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>
    <!--设置日志-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
 
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--配置数据源:创建Connection对象-->
            <dataSource type="POOLED">
                <!--driver:驱动的内容-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <!--链接数据库的url-->
                <property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8"/>
                <!--用户名-->
                <property name="username" value="root"/>
                <!--密码-->
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
 
    <!--指定其他mapper文件的位置:
        指定其他mapper文件目的是找到其他文件的sql语句
    -->
    <mappers>
        <!--
            使用mapper的resource属性执行mapper文件的路径
            这个路径是从target/classes路径开启的
            使用注意:
            resource="mapper文件的路径,使用的是 \ 做分隔路径"
            一个mapper resource指定一个mapper文件
        -->
        <mapper resource="com\lu\dao\StudentDao.xml"/>
    </mappers>
</configuration>

我们重新来运行代码,执行查询操作

pic_f93b3b11.png

我们可以看到输出的信息比以前更详细了,但出现了几个新的概念。

什么是自动提交?

当你的sql语句执行完毕后,提交事务。数据库更新操作之间保存到数据

什么是手动提交事务?

在你需要提交事务的位置,执行方法,提交事务或者回滚事务

我们下面通过一个添加学生数据的例子,来更清楚的弄懂自动提交和手动提交事务的区别。

2.4.2 添加学生数据

既然我们要添加学生数据,我们首先需要在StudentDao结构中定义一个方法

代码如下:

package com.lu.dao;
 
import com.lu.entity.Student;
 
public interface StudentDao {
   
     
     
 
    //查询一个学生
    Student selectStudentById(Integer id);
 
    //添加学生
    //返回值int,表示本次操作影响的数据库的行数
    int insertStudent(Student student);
}

然后在StudentDao.xml文件中来写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">
 
<mapper namespace="com.lu.dao.StudentDao">
 
    <select id="selectStudentById" resultType="com.lu.entity.Student">
        select id,name,email,age from student where id = #{studentId}
    </select>
 
    <!--添加insert-->
    <insert id="insertStudent">
        insert into student values(1003,"王五","wangwu@qq.com",18)
    </insert>
 
 
</mapper>

接下来我们来测试,测试代码如下:

@Test
public void testInsertStudent() throws IOException {
   
     
     
 
    String config = "mybatis";
    InputStream inputStream = Resources.getResourceAsStream(config);
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession session = factory.openSession();
 
    String sqlId = "com.lu.dao.StudentDao" + "." + "insertStudent";
 
    int rows = session.insert(sqlId);
    System.out.println("使用mybatis添加一个学生,rows = " + rows);
 
    session.close();
}

执行以下:

pic_d8bad757.png

看控制台我们好像成功了,也返回了rows=1

我们去数据库查看

pic_10534390.png

却没有发现1003王五的数据,这到底是什么回事呢?

我们看划横线的地方,这里关闭了JDBC事务的自动提交

所以原因是mybatis默认执行sql语句是 手动提交事务 的模式,在做insert,update,delete后需要提交事务。

我们再来修改代码

@Test
public void testInsertStudent() throws IOException {
   
     
     
 
    String config = "mybatis";
    InputStream inputStream = Resources.getResourceAsStream(config);
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession session = factory.openSession();
 
    String sqlId = "com.lu.dao.StudentDao" + "." + "insertStudent";
 
    int rows = session.insert(sqlId);
 
    session.commit();
 
    System.out.println("使用mybatis添加一个学生,rows = " + rows);
 
    session.close();
}

再来看控制台的输出:

pic_324a5f8b.png

这里多出来了 一行提交JDBC事务,就是我们上面多加的哪一行代码session.commit()

我们再去看数据库,发现数据已经添加上去了

pic_61cb45ce.png

好了,到这里我们这个例子已经成功的搞定了自动提交事务和手动提交事务的区别,那么还有一个问题,就是添加的数据我们是写死的,怎么能够动态的添加的,其实前面我们已经讲了,就是使用占位符

2.4.3 使用占位符

我们来修改StudentDao.xml文件中的insert语句

<!--添加insert
    如果传入给mybatis是一个Java对象,使用#{属性名}获取此属性的值
    属性值放到 #{} 占位符,mybatis执行此属性对应的getXXX()方法
    例如 #{id} 执行的是getId();
    -->
<insert id="insertStudent">
    insert into student values(#{id},#{name},#{email},#{age})
</insert>

我们来修改测试代码:

@Test
public void testInsertStudent() throws IOException {
   
     
     
 
    String config = "mybatis";
    InputStream inputStream = Resources.getResourceAsStream(config);
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession session = factory.openSession();
 
    String sqlId = "com.lu.dao.StudentDao" + "." + "insertStudent";
 
    Student student = new Student();
    student.setId(1004);
    student.setName("维桑");
    student.setEmail("weisang@qq.com");
    student.setAge(24);
    int rows = session.insert(sqlId, student);
 
    session.commit();
 
    System.out.println("使用mybatis添加一个学生,rows = " + rows);
 
    session.close();
}

执行程序:

pic_c0aa80e2.png

看着应该是成功了,我们去数据库查看数据

pic_a59eb1ce.png

插入成功了,这就是占位符的使用

下面我们来回顾以下,具体的讲解以下MyBatis的一些重要对象

2.5 MyBatis的一些重要对象

2.51.Resources

mybatis框架中的对象,一个作用读取主配置信息

InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");

2.5.2 SqlSessionFactoryBuilder

负责创建SqlSessionFactory对象

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

2.5.3 SqlSessionFactory

SqlSessionFactory是一个重量级对象:创建此对象需要使用更多的资源和时间。在项目中有一个就行了。

SqlSessionFactory接口:作用是SqlSession的工厂,就是创建SqlSession对象

DefaultSqlSessionFactory实现类

public class DefaultSqlSessionFactory implements SqlSessionFactory {
   
     
     }

SqlSessionFactory接口中的方法

**openSession():**获取一个默认的SqlSession对象,默认是需要手工提交事务的

**openSession(boolean):**boolean参数表示是否自动提交事务

  • true:创建一个自动提交事务的SqlSession
  • false:等同于没有参数的openSession()

那么这时候我们就可以设置成自动提交事务,就不要在代码中写session.commit()了

修改代码:

@Test
public void testAutoCommitInsertStudent() throws IOException {
   
     
     
 
    String config = "mybatis";
    InputStream inputStream = Resources.getResourceAsStream(config);
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession session = factory.openSession(true);
 
    String sqlId = "com.lu.dao.StudentDao" + "." + "insertStudent";
 
    Student student = new Student();
    student.setId(1005);
    student.setName("卢桑");
    student.setEmail("lusang@qq.com");
    student.setAge(22);
    
    int rows = session.insert(sqlId, student);
 
    System.out.println("使用mybatis添加一个学生,rows = " + rows);
 
    session.close();
}

重新执行:

pic_93bd3bba.png

我们去数据库中查看:

pic_fa0639d9.png

数据插入成功

2.5.4 SqlSession对象

SqlSession对象是通过SqlSessionFactory获取的。SqlSession本身是接口,它的实现类是

pic_30b9029b.png

public class DefaultSqlSession implements SqlSession {
   
     
      }

SqlSession提供了大量的执行sql的方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B2PA4AdH-1657273669568)(http://175.178.73.222:888/images/pic_c5058931.png)]

  • selectOne():执行select语句,得到最多一条记录,多余1行是错误
  • selectList():执行select语句,返回多行数据
  • selectMap():执行select语句,得到一个Map集合
  • insert():执行insert语句
  • update():执行update语句
  • delete():执行delete语句
  • commit():提交事务
  • rollback():回滚事务

注意SqlSession对象不是线程安全的,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2p7AAsYt-1657273669568)(http://175.178.73.222:888/images/pic_b049d6ba.png)]

使用的步骤:

  1. 确保SqlSession的对象在方法的内部,执行sql语句之前,先获取SqlSession对象
  2. 调用SqlSession的方法,执行sql语句
  3. 关闭SqlSession对象,执行SqlSession.close()

2.6 mapper和主配置文件创建模板

我们创建一个新的项目MyBatis-second

创建步骤参考2.2章节创建MyBatis项目八步

然后在第六步,我们需要创建一个mapper文件来写sql语句,在这个文件里面,只有你写的sql语句是自己写的,其他都是不变的,这样我们就可以创建一个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="dao接口的全限定名称">
    <!--使用insert,update,delete,select标签写sql-->
 
 
</mapper>

第二步,打开Settings(快捷键 Ctrl + Alt + S)

pic_1af822cb.png

根据箭头步骤来

第三步,我们将第一步准备好的模板放进去

pic_6bf31440.png

第四步,点击ok,测试

pic_4a392640.png

成功创建

pic_97365ee8.png

那么我们也可以仿照上面的步骤来创建主配置文件模板

先来准备一个主配置文件的模板,具体的数据库名称密码等根据自己的实际情况来填写

<?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>
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
 
    <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/ssm?useUnicode=true&characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
 
    <mappers>
        <mapper resource="mapper文件的全限定名称"/>
    </mappers>
</configuration>

按照上面的步骤,我们成功创建主配置文件模板

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Btypghnm-1657273669569)(http://175.178.73.222:888/images/pic_9c1caaf1.png)]

pic_02661339.png

3 MyBatis框架之dao代理

3.1 传统dao方法

3.1.1 创建工具类

我们创建工具类是因为我们在测试的时候不必再写重复的代码,直接调用工具类的方法来获取session对象

我们创建一个util包,然后创建一个MyBatisUtil工具类

pic_6fda181c.png

具体的代码如下:

package com.lu.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;
 
/*
 *   工具类:创建SqlSession对象
 */
public class MyBatisUtil {
   
     
     
    private static SqlSessionFactory factory = null;
    static {
   
     
     
        String config = "mybatis.xml";
        try {
   
     
     
            InputStream inputStream = Resources.getResourceAsStream(config);
            factory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
   
     
     
            e.printStackTrace();
        }
    }
 
    //创建方法来获取SqlSession对象
    public static SqlSession getSqlSession() {
   
     
     
        SqlSession session = null;
        if (factory != null) {
   
     
     
            session = factory.openSession();
        }
        return session;
    }
}

那么我们如何使用这个工具类呢

我们来写一个测试类

package com.lu;
 
import com.lu.entity.Student;
import com.lu.utils.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
 
public class MyTest {
   
     
     
 
    @Test
    public void testSelectById() {
   
     
     
        //1.获取SqlSession对象
        SqlSession session = MyBatisUtil.getSqlSession();
 
        //2.指定sqlId
        String sqlId = "com.lu.dao.StudentDao" + "." + "selectStudentById";
 
        //3.执行方法
        Student student = session.selectOne(sqlId, 1001);
 
        System.out.println(student);
 
        //4.关闭SqlSession对象
        session.close();
    }
}

运行一下

pic_7155f350.png

运行成功,但是我们在测试类中要写的代码却精简了很多,这种重复代码封装成工具类的思想我们要多学习一下,既避免了代码的重复敲,也避免了错误的发生

3.1.2 查询多条数据

我们已经学会了查询一条语句,使用了selectOne(),那么如果我们查询多条语句呢

SqlSession对象有一个selectList()方法

返回的是一个结果集List

我们先在StudentDao接口中定义一个方法

List<Student> selectStudents();

再来修改mapper文件,添加查询所有数据的sql语句

<select id="selectStudents" resultType="com.lu.entity.Student">
    select id, name, email, age from student
</select>

然后编写测试代码:

@Test
public void testSelectStudents() {
   
     
     
    //1.获取SqlSession对象
    SqlSession session = MyBatisUtil.getSqlSession();
 
    //2.指定sqlId
    String sqlId = "com.lu.dao.StudentDao" + "." + "selectStudents";
 
    //3.执行方法
    List<Student> students = session.selectList(sqlId);
 
    for (Student stu :
            students) {
   
     
     
        System.out.println(stu);
    }
    //4.关闭SqlSession对象
    session.close();
}

执行测试类

pic_f327b6c6.png

成功将所有数据查询出来

3.1.3 使用传统的dao执行sql

为了更加精简测试类的代码量,我们使用传统的dao来执行sql,也就是说实现dao接口的实现类

我们来编写StudentDao接口的实现类StudentDaoImpl.java

package com.lu.dao;
 
import com.lu.entity.Student;
import com.lu.utils.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
 
import java.util.List;
 
public class StudentDaoImpl implements StudentDao {
   
     
     
    @Override
    public Student selectStudentById(Integer id) {
   
     
     
        //1.获取SqlSession对象
        SqlSession session = MyBatisUtil.getSqlSession();
 
        //2.指定sqlId
        String sqlId = "com.lu.dao.StudentDao" + "." + "selectStudentById";
 
        //3.执行方法
        Student student = session.selectOne(sqlId, id);
 
        //4.关闭SqlSession对象
        session.close();
        return student;
    }
 
    @Override
    public List<Student> selectStudents() {
   
     
     
        //1.获取SqlSession对象
        SqlSession session = MyBatisUtil.getSqlSession();
 
        //2.指定sqlId
        String sqlId = "com.lu.dao.StudentDao" + "." + "selectStudents";
 
        //3.执行方法
        List<Student> students = session.selectList(sqlId);
 
        //4.关闭SqlSession对象
        session.close();
        return students;
    }
}

我们再来新建一个测试类MyTest2

package com.lu;
 
import com.lu.dao.StudentDao;
import com.lu.dao.StudentDaoImpl;
import com.lu.entity.Student;
import org.junit.Test;
 
import java.util.List;
 
public class MyTest2 {
   
     
     
 
    @Test
    public void testSelectOne() {
   
     
     
        //要使用dao的方法
        // 接口类型 变量 = new 接口的实现类();
        StudentDao dao = new StudentDaoImpl();
        Student student = dao.selectStudentById(1001);
        System.out.println("通过dao执行方法得到的对象 = " + student);
    }
 
    @Test
    public void testSelectStudents() {
   
     
     
        StudentDao dao = new StudentDaoImpl();
        List<Student> students = dao.selectStudents();
        for (Student stu :
                students) {
   
     
     
            System.out.println(stu);
        }
    }
}

分别执行

pic_41e07898.png

pic_c5c83f01.png

这样我们在测试类中的代码又精简了,但是我们发现一个问题,好像这样也没有少写代码,这只不过代码放到dao接口的实现类当中去了,所以我们必须谋求一种更精简的方式。

3.2 MyBatis使用动态代理

3.2.1 引出代理技术

今天我们继续学习前一天的内容,昨天我们使用了传统的dao来执行sql,我们来分析一下,来看下面这两行代码,就是dao接口我们写的实现类里面的两行代码,我们怎么样通过dao调用方法来得到这两行代码的信息呢?

String sqlId = "com.lu.dao.StudentDao.selectStudentById";
Student student = session.selectOne(sqlId, id);

测试方法中:调用dao的方法

Student student = dao.selectStudentById(1001);

我们来分析一下,首先分析后面的dao.selectStudentById()

1.dao:通过反射能够得到全限定类型名称

dao是StudentDao类型的,全限定名称:com.lu.dao.StudentDao,那么通过反射我们就可以得到sqlId前面的内容com.lu.dao.StudentDao"

2.selectStudentById:dao中的方法名称,方法名称就是mapper文件中标签的id

现在我们sqlId后面的内容"selectStudentById"也得到了,两个一拼接就得到了完整的sqlId

也就是说通过dao.selectStudentById()可以得到sqlId的信息

sqlId = "com.lu.dao.StudentDao.selectStudentById"

现在我们已经得到了sqlId的值,那么我们还需要得到第二行代码,也就是如何确定SqlSession调用的那个方法。

**3.确定调用SqlSession的哪个方法 **

1).根据dao接口的返回值,如果返回的是一个对象,例如Student,说明调用SqlSession.selectOne()

2).如果dao接口中的方法返回List,调用SqlSession的selectList();

3).根据mapper文件中的标签,如果标签是,调用SqlSession.insert()方法

现在我们根据Student student = dao.selectStudentById(1001);这一行代码可以得到上面两行代码的信息。同样,mybatis框架,发现使用dao的方法调用能确定执行sql语句的必要信息,那么mybatis就能简化dao对象的实现。

由mybatis框架在程序执行期间,根据你的Dao接口,创建一个内存中的接口的实现类对象

mybatis把这个技术叫做dao技术(动态代理,dao的动态代理)

**dao代理技术:**由mybatis创建StudentDao接口的实现类Proxy(StudentDaoImpl),使用框架创建的StudentDaoImpl代替你手工实现的StudentDaoImpl类的功能,开发人员不再需要写dao接口的实现类。

使用dao的代理要求:

1.mapper文件中的namespace:必须是dao接口的全限定名称

2.mapper文件中标签的id是dao接口中的方法名称(一模一样)

3.2.2 代理的实现方式

要想实现代理,其实很简单,我们来看官网的介绍

pic_87ed32d5.png

使用SqlSession对象的方法 getMapper(dao.class)

例如:现在有StudentDao接口

SqlSession session = MyBatisUtils.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.class);
Student student = dao.selectStudentById(1001);

//上面代码中
StudentDao dao = session.getMapper(StudentDao.class);
//等同于
StudentDao dao = new StudentDaoImpl();

通过这三行代码,我们就可以实现数据库的查询,这样我们的代码又精简了,不用自己再写dao接口的实现类了。

3.2.3 实例

我们再来新建一个Maven项目,实现数据库的添加

项目目录结构为

pic_5f821858.png

其他的没有什么不同,但是我们没有dao接口的实现类了

同时MyTest的代码为

@Test
public void testselectStudentById() {
   
     
     
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
    Student student = dao.selectStudentById(1001);
    System.out.println(student);
    session.close();
}

控制台输出:

pic_4177cef8.png

查询成功!

那么我们生成的dao对象到底是什么,我们来输出一下

pic_302c016a.png

可以看到dao对象是一个代理

**到现在我们又进一步精简化了代码,实现了mybatis的代理,dao接口实现类的代码mybatis也帮我们写了,是不是方便了很多,学到这里我们已经将mybatis的大概学会了,接下来我们会讲解mybatis的参数详细理解。 **

3.3 MyBatis参数详解

参数就是通过java程序把数据传入到mapper文件中的sql语句。参数主要是指dao接口方法的形参

3.3.1 parameterType

**parameterType:**表示参数的类型,指定dao方法的形参数据类型。这个形参的数据类型是给mybatis使用。mybatis是给sql语句的参数赋值时使用。

PreparedStatement.setXXX(位置, 值)

要想理解这里必须对JDBC中的PreparedStatement有足够的了解,推荐看我之前写的一篇文章

一文学会JDBC(两万字,适用于新手)_ypxcan的博客-CSDN博客

我们来看mapper文件中select查询语句

<select id="selectStudentById" resultType="com.lu.entity.Student">
    select id, name, email, age from student where id = #{studentId}
</select>

mybatis要执行的sql语句为:

select id, name, email, age from student where id = ?

?是占位符,使用JDBC中的PreparedStatement执行这样的sql语句

PreparedStatement ps = conn.prepareStatement("select id, name, email, age from student where id = ?");

我们给 ? 位置进行赋值

  • 如果参数是Integer,则执行ps.setInt(1, 1005)
  • 如果参数是String,则执行ps.setString(1, “1005”)

那么parameterType的第一个用法:

java类型的全限定类型名称 parameterType = “java.lang.Integer”

那么代码就是这样写:

<select id="selectStudentById" parameterType="java.lang.Integer" resultType="com.lu.entity.Student">
    select id, name, email, age from student where id = #{studentId}
</select>

第二种用法,使用别名

别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
object Object
map Map
hashmap HashMap
list List
arraylist ArrayList
collection Collection
iterator Iterator
既然我们这里是Integer类型,那么别名就是int,那么代码就是这么写

<select id="selectStudentById" parameterType="int" resultType="com.lu.entity.Student">
    select id, name, email, age from student where id = #{studentId}
</select>

我们在测试类中测试一下

pic_5c13e646.png

发现是可以执行的

但是我们发现一个问题,好像parameterType不写也是可以的,没错,parameterType不是强制的,mybatis通过反射机制是可以得到参数类型的,绝大多数情况下我们不需要写这个参数。

3.3.2 dao接口方法参数一个简单类型的参数

如果dao接口中方法的形参是一个简单类型,那么mapper文件中,获取这个参数值,使用#{任意字符}

简单类型:八种基本类型 + String

我们来讲一个例子,首先在dao接口中定义一个方法

package com.lu.dao;
 
import com.lu.entity.Student;
 
public interface StudentDao {
   
     
     
 
    Student selectStudentByEmail(String email);
}

在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.lu.dao.StudentDao">
    <!--使用insert,update,delete,select标签写sql-->
    
    <select id="selectStudentByEmail" resultType="com.lu.entity.Student">
        select id, name, email, age from student where email = #{studentEmail}
    </select>
 
</mapper>

我们去测试类中去调用

@Test
public void testselectStudentByEmail() {
   
     
     
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
    Student student = dao.selectStudentByEmail("zhangsan@qq.com");
    System.out.println(student);
    session.close();
}

控制台输出:

pic_ab7d1559.png

3.3.3 dao接口方法中有多个简单类型的参数

这里我们要使用@Param这个注解

@Param:命名参数,在方法的形参前面使用的,定义参数名。

我们先来看一下不适用这个注解会出现什么情况

我们在dao接口中重新定义一个方法

List<Student> selectByNameOrAge(String name, Integer age);

在mapper文件中写代码

<select id="selectByNameOrAge" resultType="com.lu.entity.Student">
    select id, name, email, age from student where name = #{studentName} or age = #{studentAge}
</select>

在测试类中测试

@Test
public void testSelectByNameOrAge() {
   
     
     
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
    List<Student> students = dao.selectByNameOrAge("张三", 25);
    students.forEach(student -> System.out.println(student));
    session.close();
}

控制台输出:

pic_9187e6ee.png

报错了,mybatis不能识别多个参数,所以这时候我们就需要使用**@Param注解**

该注解的使用位置在dao接口中

List<Student> selectByNameOrAge(@Param("myname") String name, @Param("myage") Integer age);

当使用了@Param后,例如@Param(“myname”),在mapper文件中,使用#{命名的参数},

例如#{myname},那么mapper文件中就需要改成

<select id="selectByNameOrAge" resultType="com.lu.entity.Student">
    select id, name, email, age from student where name = #{myname} or age = #{myage}
</select>

重新在测试类汇总进行测试

pic_96eaa06f.png

可以看到测试成功了,这种方式只针对少量参数,如果参数比较多,四五个或者更多,那么这样就会非常繁琐,如果参数非常多,我们推荐使用对象的方式

3.3.4 dao接口方法使用一个对象作为参数

方法的形参是一个java对象,这个java对象表示多个参数。使用对象的属性值作为参数使用。

下面我们来举一个例子

我们首先在dao接口中定义一个方法

/*
* 一个java对象作为参数(对象有属性,每个属性有set,get方法)
*/
List<Student> selectByObject(Student student);

然后在mapper文件中写sql语句

<!--
    一个java对象作为方法的参数,使用对象的属性作为参数值使用
    简单地语法:#{属性名},mybatis调用此属性的getXXX()方法获取属性值
-->
<select id="selectByObject" resultType="com.lu.entity.Student">
    select id, name, email, age from student where name = #{name} or age = #{age}
</select>

这里我们只写了name和age,那么测试类中就可以这么写

@Test
public void testSelectByObject() {
   
     
     
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
 
    Student student = new Student();
    student.setName("张三");
    student.setAge(25);
    List<Student> students = dao.selectByObject(student);
    students.forEach(stu -> System.out.println(stu));
 
    session.close();
}

控制台输出:

pic_2a5342e3.png

可以看到可以正常输出

我们必须明白我们的参数不一定使我们定义的Student实体类,也可以是其他类,只要该类的属性有set和get方法即可

3.3.5 dao接口中多个简单类型的参数,使用位置

参数位置:dao接口中方法的形参列表,从左往右,参数位置是0,1,2…

语法格式:#{arg0},#{arg1}

下面来讲一个例子:

我们首先在接口中定义一个方法

/*
* 使用位置
* */
List<Student> selectByPosition(String name, Integer age);

mapper文件中

<select id="selectByPositon" resultType="com.lu.entity.Student">
    select id, name, email, age from student where name = #{arg0} or age = #{arg1}
</select>

在测试类中

@Test
public void testSelectByPositon() {
   
     
     
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
    List<Student> students = dao.selectByPosition("张三", 18);
    students.forEach(student -> System.out.println(student));
    session.close();
}

控制台输出:

pic_6ab894a4.png

这种方法看起来好像更简单,但是我们不推荐使用这种方法,因为代码可读性低,我们要想知道传的是什么值,就必须去dao接口中查看方法的参数,不能见名知意

3.3.6 dao接口参数是一个Map

map作为dao接口的参数,使用key获取参数值,mapper文件中, 语法格式 #{key}

我们来写一个例子:

我们首先在dao接口中定义一个方法

//使用Map作为参数
List<Student> selectStudentByMap(Map<String, Object> map);

mapper文件中:

<select id="selectStudentByMap" resultType="com.lu.entity.Student">
    select id, name, email, age from student where name = #{myname} or age = #{myage}
</select>

测试类中:

@Test
public void testSelectByMap() {
   
     
     
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
 
    //使用Map传递参数
    Map<String, Object> data = new HashMap<>();
    data.put("myname", "张三");
    data.put("myage", 20);
    List<Student> students = dao.selectStudentByMap(data);
    students.forEach(student -> System.out.println(student));
 
    session.close();
}

控制台输出:

pic_144d27b3.png

mybatis中,占位符有两个,一个是#,一个是$,这两个有什么区别,我们分别来讲解一下

3.4 MyBatis占位符的讲解

3.4.1 占位符#{}

语法:#{字符}

#占位符告诉mybatis使用实际的参数值代替。并,#{…}代替sql语句的"?"。这样做更安全,更迅速,通常也是首选做法

mapper文件中

<select id="selectStudentById" parameterType="int" resultType="com.lu.entity.Student">
	select id, name, email, age from student where id = #{studentId}
</select>

转为mybatis的执行是:

String sql = "select id, name, email, age from student where id = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, 1001);    //传递参数
ResultSet rs = ps.executeQuery();	//执行sql语句

#{}占位符的特点:

  1. 使用PrepareStatement对象执行sql语句
  2. 使用PrepareStatement对象,能避免sql注入,sql语句执行更安全
  3. #{}常常作为列值使用的,位于等号的右侧,#{}位置的值和数据类型有关的

3.4.2 占位符${}

语法:${字符}

mybatis执行${}占位符的sql语句

<select id="selectStudentById" parameterType="int" resultType="com.lu.entity.Student">
	select id, name, email, age from student where id = ${studentId}
</select>

表 示 字 符 串 连 接 , 把 ‘ s q l ‘ 语 句 的 其 他 内 容 和 {}表示字符串连接,把`sql`语句的其他内容和 表示字符串连接,把‘sql‘语句的其他内容和{}内容使用字符串(+) 连接的方式连在一起

转为mybatis的执行是:

String sql = "select id, name, email, age from student where id =" + "1001";
Statement stmt = conn.createStatement(sql);
ResultSet rs = stmt.executeQuery();

${}的特点

  1. 使用Statement对象,执行sql语句,效率低
  2. ${}占位符的值,使用的字符串连接方式,有sql注入的风险。有代码安全的问题
  3. ${}数据是原样使用的,不会区分数据类型
  4. 常 用 作 表 名 或 者 列 明 , 再 能 保 证 数 据 安 全 的 情 况 下 使 用 {}常用作表名或者列明,再能保证数据安全的情况下使用 常用作表名或者列明,再能保证数据安全的情况下使用{}

我们来实现一个例子,首先在dao接口中写方法

List<Student> queryStudent(@Param("studentname") String name);

在mapper文件中

<select id="queryStudent" resultType="com.lu.entity.Student">
	select * from student where name = ${studentname}
</select>

在测试类中

@Test
    public void testQueryStudent() {
   
     
     
        SqlSession session = MyBatisUtil.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        List<Student> students = dao.queryStudent("张三");
        students.forEach(student -> System.out.println(student));

        session.close();
    }

我们来执行一下

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

报了一个错,代码把张三当成一个列了,那么我们怎么修改呢

List<Student> students = dao.queryStudent("'张三'");

我们需要在传值的时候在值的两边加上单引号 ‘’

再重新执行一下,发现可以查询成功了
pic_def2c6be.png

还有一点我们需要注意的,就是在dao接口中定义方法的时候,我们必须用@Param来指定名称,不然同样会报错。

${}最不能解决的问题,就是sql注入的问题,关于sql注入,可以看这一篇文章

PreparedStatement如何防止sql注入

3.4.3 #{}和${}组合使用

有时候我们单独的使用#{}或者${}都不能很好的解决问题,比如下面这个例子

我们要从指定的数据中查询名字为XXX的数据,并且按照姓名进行降序排序

首先在dao接口中定义方法

List<Student> queryStudentOrderByColumn(@Param("myname") String name, @Param("colName") String colName, @Param("tableName") String tableName);

在mapper文件中

<select id="queryStudentOrderByColumn" resultType="com.lu.entity.Student">
	select * from ${tableName} where name = #{myname} order by ${colName} desc
</select>

在测试类中

@Test
    public void testQueryStudentOrderByColName() {
   
     
     
        SqlSession session = MyBatisUtil.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        List<Student> students = dao.queryStudentOrderByColumn("张三", "id", "student");
        students.forEach(student -> System.out.println(student));

        session.close();
    }

控制台输出:

pic_ba494799.png

现在我们已经实现了#{}和${}的组合使用

封装输出结果:MyBatis执行sql语句,得到ResultSet,转为java对象

这里我们两个,分别为resultType和resultMap

3.5 resultType

resultType属性:在执行select时使用,作为标签的属性出现的。

resultType:执行sql得到ResultSet转换的类型,使用类型的完全限定名或别名。注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。

它的值有两种:

  1. java类型的全限定名称
  2. 使用别名

3.5.1 java类型的全限定名称

dao接口中定义方法

Student selectStudentById(Integer id);

mapper文件中

<select id="selectStudentById" parameterType="int" resultType="com.lu.entity.Student">
	select id, name, email, age from student where id = #{studentId}
</select>

resultType:现在使用的是java类型的全限定名称。表示的意思是mybatis执行sql,把ResultSet中的数据转为Student类型的对象。

mybatis会做一下操作:

1.调用com.lu.entity.Student的无参构造方法, 创建对象。

Student student = new Student();	//使用反射创建对象

2.同名的列赋值给同名的属性

student.setId(rs.getInt("id"));
student.setName(rs.getString("name"));

3.得到java对象,如果dao接口返回值是List集合,mybatis把student对象放入到List集合

所以执行 Student mystudent = dao.selectById(1001);

得到数据库中 id = 1001这行数据,这行数据的列值,赋值给了mystudent对象的属性。你能得到mystudent对象,就相当于是id = 1001这行数据。

3.5.2 自定义别名

mybatis提供的对java类型定义简短,好记的名称。

自定义别名有两种方式:分别为typeAlias和package

3.5.2.1 typeAlias自定义别名

使用typeAlias自定义别名的步骤:

1.在mybatis主配置文件,使用typeAliases标签声明别名

<typeAliases>
    <!--第一种语法格式
    	type:java类型的全限定名称(自定义类型)
    	alias:自定义别名
    -->
	<typeAlias type="com.lu.entity.Student" alias="stu"></typeAlias>
</typeAliases>

注意:标签必须写在标签后面

2.在mapper文件中,resultType = “别名”

<select id="selectStudentById" parameterType="int" resultType="stu">
	select id, name, email, age from student where id = #{studentId}
</select>

3.测试类中测试

@Test
    public void testselectStudentById() {
   
     
     
        SqlSession session = MyBatisUtil.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        Student student = dao.selectStudentById(1002);
        System.out.println(student);
        session.close();
    }

控制台输出:
pic_dc7b1f1f.png

使用typeAlias有优点也有缺点

优点:别名可以自定义

缺点:每个类型必须单独定义

3.5.2.2 package自定义别名

主配置文件中:

<!--第二种方式
	name:包名,mybatis会把这个包中所有类名作为别名
-->
<package name="com.lu.entity"/>

mapper文件中:

<select id="selectStudentById" parameterType="int" resultType="student">
	select id, name, email, age from student where id = #{studentId}
</select>

这一种方式resultType中不区分大小写,所以全用小写同样也可以

测试类中测试:

pic_7c347922.png

同样测试成功

优点:使用方便,一次给多个类定义别名。

缺点:别名不能随便定义,必须是类名。

这两种自定义别名都有优点和缺点,所以建议是不适用别名,就使用全限定名称,这样清晰明了。

3.5.3 resultType表示简单类型

我们首先在dao接口中定义一个方法

long countStudent();

在mapper文件中编写sql语句

<!--执行sql语句,得到的是一个值(一行一列)-->
<select id="countStudent" resultType="java.lang.Long">
	select count(*) from student
</select>

在测试类中测试

@Test
    public void testCountStudent() {
   
     
     
        SqlSession session = MyBatisUtil.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        long nums = dao.countStudent();
        System.out.println("nums = " + nums);

        session.close();
    }

控制台输出:
pic_fa6db9ae.png

3.5.4 resultType

dao接口中定义方法:

Map<Object, Object> selectMap(Integer id);

mapper文件中写sql语句:

<!--
	执行sql得到一个Map结构数据,mybatis执行sql,把ResultSet转为map
-->
<select id="selectMap" resultType="java.util.HashMap">
	select id, name from student where id = #{studentid}
</select>

测试类中进行测试:

@Test
    public void testSelectMap() {
   
     
     
        SqlSession session = MyBatisUtil.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        Map<Object, Object> map = dao.selectMap(1001);
        System.out.println("map = " + map);
        System.out.println("name = " + map.get("name"));
        System.out.println("id = " + map.get("id"));
        session.close();
    }

控制台输出:
pic_360febda.png

我们可以看到执行结果,列名作为map的key,列值作为value

dao接口返回一个map,sql语句最多能获取一行记录,多于一行是错误

3.6 resultMap

resultMap:结果映射。自定义列名和Java对象属性的对应关系。常用在列名和属性名不同的情况。

用法:

1.先定义resultMap标签,指定列名和属性名称对应关系

2.在select标签使用resultMap属性,指定上面定义的resultMap的id值

我们来举一个例子

首先定义一个CustomObject类

package com.lu.entity;

public class CustomObject {
   
     
     
    private Integer cid;
    private String cname;
    private String email;
    private Integer age;

    public Integer getCid() {
   
     
     
        return cid;
    }

    public void setCid(Integer cid) {
   
     
     
        this.cid = cid;
    }

    public String getCname() {
   
     
     
        return cname;
    }

    public void setCname(String cname) {
   
     
     
        this.cname = cname;
    }

    public String getEmail() {
   
     
     
        return email;
    }

    public void setEmail(String email) {
   
     
     
        this.email = email;
    }

    public Integer getAge() {
   
     
     
        return age;
    }

    public void setAge(Integer age) {
   
     
     
        this.age = age;
    }

    @Override
    public String toString() {
   
     
     
        return "CustomObject{" +
                "cid=" + cid +
                ", cname='" + cname + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }
}

我们发现这里cid和cname和数据库里面的列名不一致

我们再在dao接口中定义一个方法

CustomObject selectById2(Integer id);

如果我们要将从数据库取出来的内容赋值给CustomObject对象,那么如果我们继续用resultType的话,从数据库中取出来的数据只能赋值给email和age,无法给cid和cname进行赋值,这个时候我们就需要用到resultMap

我们在mapper文件中这样来写:

<!--
        使用resultMap定义列和属性的关系
        定义resultMap
            id:给resultMap的映射关系起个名称,唯一值
            type:Java类型的全限定名称
    -->
    <resultMap id="customMap" type="com.lu.entity.CustomObject">
        <!--定义列名和属性名的对应-->
        <!--主键类型使用id标签-->
        <id column="id" property="cid"></id>
        <!--非主键类型使用result标签-->
        <result column="name" property="cname"></result>
        <!--列名和属性名相同,不用定义-->
    </resultMap>

    <!--使用resultMap属性,指定映射关系的id-->
    <select id="selectById2" resultMap="customMap">
        select id, name, email, age from student where id = #{studentid}
    </select>

这样我们就可以使用resultMap来定义数据库列和属性的关系

我们在测试类中进行测试:

@Test
    public void testSelectById2() {
   
     
     
        SqlSession session = MyBatisUtil.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        CustomObject co = dao.selectById2(1001);
        System.out.println(co);
        session.close();
    }

控制台输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eqrvlvRE-1657273669576)(http://175.178.73.222:888/images/pic_e86f1ef8.png)]

这样resultMap就成功解决了列名和属性名不一致的情况。

注意:resultType和resultMap不能同时使用。

3.7 列名和Java对象属性名称不一致解决方式

3.7.1 使用resultMap:自定义列名和属性名称对应关系

这个方法在上面讲解resultMap的时候就讲解了,可以直接看上面

3.7.2 使用resultType

使用列别名,让别名和Java对象属性名称一样

我们在dao接口中定义一个方法:

CustomObject selectById3(Integer id);

我们在mapper文件中写:

<!--使用列别名,解决列名和属性名不同的问题-->
<select id="selectById3" resultType="com.lu.entity.CustomObject">
	select id AS cid, name AS cname, email, age where id = #{studentid}
</select>

我们在测试类中进行测试

@Test
    public void testSelectById3() {
   
     
     
        SqlSession session = MyBatisUtil.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        CustomObject co = dao.selectById2(1003);
        System.out.println(co);
        session.close();
    }

控制台输出:
pic_84bdb020.png

3.8 MyBatis实现模糊查询

今天我们来学习mybatis实现模糊查询

3.8.1 第一种方式

第一种方式:在java程序中,把like的内容组装好,把这个内容传入到sql语句

我们先在dao接口中定义一个方法

//like的第一种方式
List<Student> selectLikeOne(@Param("name") String name);

mapper文件中:

<!--like第一种方式-->
<select id="selectLikeOne" resultType="com.lu.entity.Student">
	select * from student where name like #{name}
</select>

测试类中进行测试

@Test
public void testLikeOne() {
   
     
     
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);

    String name = "%张%";
    List<Student> students = dao.selectLikeOne(name);
    session.close();

    students.forEach(student -> System.out.println(student));
}

控制台输出:
pic_469f5585.png

3.8.2 第二种方式

第二种方式:在sql语句,组织like的内容

sql语句like的格式:where name like “%“空格#{name}空格”%”

步骤:

在dao接口中定义方法:

//like的第二种方式
List<Student> selectLikeTwo(@Param("name") String name);

在mapper文件中:

<!--like第二种方式-->
<select id="selectLikeTwo" resultType="com.lu.entity.Student">
	select * from student where name like "%" #{name} "%"
</select>

在测试类中测试:

@Test
public void testLikeTne() {
   
     
     
	SqlSession session = MyBatisUtil.getSqlSession();
	StudentDao dao = session.getMapper(StudentDao.class);

	String name = "张";
	List<Student> students = dao.selectLikeTwo(name);
	session.close();

	students.forEach(student -> System.out.println(student));
}

控制台输出:
pic_8e32e7ec.png

4 MyBatis框架动态SQL

什么是动态sql:同一个dao的方法,根据不同的条件可以表示不同的sql语句,主要是where部分有变化

通过使用mybatis提供的标签,实现动态sql的能力,主要将if,where,foreach,sql这四个标签

注意:

在使用动态sql的时候,dao方法的形参要使用java对象。

4.1 动态SQL之if

语法:

<if test = "boolean判断结果">
	sql代码
</if>


在mapper文件中
<select id="selectStudent" resultType="com.lu.entity.Student">
	select * from student
    <if test="条件1">
    	sql语句
    </if>
    <if test="条件2">
    	sql语句
    </if>
</select>

我们现在来举一个例子:

我们首先在dao接口中定义一个方法:

//if
List<Student> selectIf(Student student);

在mapper文件中:

<!--if
	test:使用对象的属性值作为条件
-->
<select id="selectIf" resultType="com.lu.entity.Student">
	select * from student where
	<if test="name != null and name != ''">
		name = #{name}
	</if>

	<if test="age > 0">
	or age = #{age}
	</if>
</select>

在测试类中

@Test
public  void testSelectIf() {
   
     
     
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);

    Student student = new Student();
    student.setName("张三");
    student.setAge(22);

    List<Student> students = dao.selectIf(student);
    students.forEach(stu -> System.out.println(stu));

    session.close();
}

控制台输出:
pic_890341e1.png

查询成功。

现在我们来修改测试类中的代码,不给name赋值,或者赋空值

@Test
public  void testSelectIf() {
   
     
     
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);

    Student student = new Student();
    student.setName("张三");
    student.setAge(22);

    List<Student> students = dao.selectIf(student);
    students.forEach(stu -> System.out.println(stu));

    session.close();
}

我们重新运行程序
pic_fa0db793.png

程序运行出错,我们发现,如果给name赋空值的话,那么就不满足第一个条件,但是满足第二个条件,这样就成为了

select * from student where or age = ?

这种sql语法肯定是错误的,那么我们应该如何避免这种错误的?

我们修改mapper文件:

<select id="selectIf" resultType="com.lu.entity.Student">
    select * from student where id = -1
    <if test="name != null and name != ''">
        name = #{name}
    </if>

    <if test="age > 0">
        or age = #{age}
    </if>
</select>

我们在where后面加上一个 id = -1,我们知道肯定是不满足条件的,这样我们如果没有给name赋值,那么我们的sql语法就变成了

select * from student where id = -1 or age > 0

这样就不会出现语法错误了,但是如果我们的name赋值了呢,那岂不是我们的语法不就变成了

select * from student where id = -1 name = "张三" or age > 0

这样我们的语法又错误了

我们再修改mapper文件:

<select id="selectIf" resultType="com.lu.entity.Student">
    select * from student where id = -1
    <if test="name != null and name != ''">
        or name = #{name}
    </if>

    <if test="age > 0">
        or age = #{age}
    </if>
</select>

这样好像就可以了,哪怕我们的name赋值了,sql语法也变成了这样:

select * from student where id = -1 or name = "张三" or age > 0

所以在具体的案例中我们在where后面总是加上一个一直满足(比如where 1 = 1)或者一直不满足(比如1 = -1)这样的语句,具体的情况需要根据我们的需求来添加,而后面的判断条件是加 and 或者是 or都根据实际情况来写。

这里我们再来讲一个细节,如果我们要查询小于某个年龄的人群,我们在mapper文件中:

<select id="selectIf" resultType="com.lu.entity.Student">
    select * from student where id = -1
    <if test="name != null and name != ''">
        or name = #{name}
    </if>

    <if test="age > 0">
        or age < #{age}
    </if>
</select>

我们在idea中看到直接报错了
pic_4cb133ec.png

标签名字有问题,这是因为idea会认为 < 小于号是闭合标签,我们需要使用小于号的实体,小于号的实体为 <

<select id="selectIf" resultType="com.lu.entity.Student">
    select * from student where id = -1
    <if test="name != null and name != ''">
        or name = #{name}
    </if>

    <if test="age > 0">
        or age < #{age}
    </if>
</select>

我们运行测试类:
pic_93f85181.png

总结一下:

在mapper的动态SQL中若出现大于号(>),小于号(<),大于等于号(>=),小于等于号(<=)等符号,最好将其转换为实体符号。否则,XML可能会出现解析错误

特别是对于小于号(<),在XML文件中是绝不能出现的,否则解析mapper文件将出错

实体符号表:

<小于&lt;
>大于&gt;
>=大于等于&gt;=
<=小于等于&lt;=

4.2 动态SQL之where

通过上面对if标签的讲解,我们发现,使用if标签时,容易引起sql语法错误。可能多个and或者少个or等。我们使用where标签可以解决if产生的语法问题。

在使用时,where标签里面是一个或多个if标签,当有一个if标签判断条件为true,where标签会转为where关键字,附加到sql语句的后面。

如果if没有一个条件为true,则忽略where和里面的if。

语法:
<where>
	<if test="条件1">sql语句1</if>
	<if test="条件2">sql语句2</if>
</where>

我们举一个例子:

dao接口中定义一个方法:

//where
List<Student> selectWhere(Student student);

在mapper文件中:

<select id="selectWhere" resultType="com.lu.entity.Student">
    select * from student
    <where>
        <if test="name != null and name != ''">
            or name = #{name}
        </if>

        <if test="age > 0">
            or age < #{age}
        </if>
    </where>
</select>

在测试类中进行测试:

@Test
public  void testSelectWhere() {
   
     
     
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);

    Student student = new Student();
    student.setName("");
    student.setAge(25);

    List<Student> students = dao.selectWhere(student);
    students.forEach(stu -> System.out.println(stu));

    session.close();
}

控制台输出:
pic_9fd53217.png

我们发现查询成功了,按理说我们测试类中给name赋了个空值,那么拼接后的sql的语句应该为:

select * from student where or age < 25

那么这样我们的语句又错了,但是我们查询结果却没有错,sql语句中也没有or,这就是标签的强大之处了,where标签会自动删除紧跟在其后的and或者or,那么这样语法就没有错误了。

4.3 动态SQL之foreach

在讲解foreach之前我们先来实现一个小案例

@Test
public void testFor() {
   
     
     
    List<Integer> idlist = new ArrayList<>();
    idlist.add(1001);
    idlist.add(1002);
    idlist.add(1003);

    // 查询id在idlist中的student
    // select * from student where id = (1001,1002,1003)

    StringBuffer sql = new StringBuffer("");
    sql.append("select * from student where id in (");

    for (Integer i :
         idlist) {
   
     
     
        sql.append(i);
        sql.append(",");
    }

    sql.deleteCharAt(sql.length() - 1);
    sql.append(")");

    System.out.println(sql);
}

我们发现,要想实现这个小案例,需要写很多的代码,我们需要大量的代码来处理字符串。所以mybatis提供了foreach标签,供我们来实现循环查询

使用foreach可以循环数组,list集合,一般使用在in语法中

语法:

<foreach collection="集合类型" open="开始的字符" close="结束的字符"
	item = "集合中的成员" separator="集合成员之间的分隔符">
	#{item的值}
</foreach>

标签属性:
collection:表示循环的对象是数组,还是list集合。如果dao接口方法的形参是数组,collection="array",如果dao接口形参是	List,collection="list"

open:循环开始时的字符。			sql.append("(");
close:循环结束是的字符。			sql.append(")");
item:集合成员,自定义的变量。	  Integer item = idlist.get(i); //item是集合成员
separator:集合成员之间的分隔符。  sql.append(",");

#{item的值}:获取集合成员的值。

4.3.1 foreach简单类型的List

我们来举一个例子

dao接口中定义一个方法:

//foreach-1
List<Student> selectForeachOne(List<Integer> idlist);

mapper文件

<!--foreach第一种方式,循环简单类型的list-->
<select id="selectForeachOne" resultType="com.lu.entity.Student">
    select * from student where id in 
    <foreach collection="list" open="(" close=")" separator="," item="myid">
        #{myid}
    </foreach>
</select>

测试类中进行测试:

@Test
public  void testSelectForeachOne() {
   
     
     
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);

    List<Integer> idlist = new ArrayList<>();
    idlist.add(1001);
    idlist.add(1002);
    idlist.add(1003);

    List<Student> students = dao.selectForeachOne(idlist);
    students.forEach(stu -> System.out.println(stu));

    session.close();
}

控制台输出:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E76M9aiO-1657273669579)(http://175.178.73.222:888/images/pic_73619e09.png)]

查询成功

现在我们来修改测试类中的代码,将idlist设置为空:

@Test
public  void testSelectForeachOne() {
   
     
     
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);

    List<Integer> idlist = new ArrayList<>();
    idlist.add(1001);
    idlist.add(1002);
    idlist.add(1003);

    idlist = null;
    List<Student> students = dao.selectForeachOne(idlist);
    students.forEach(stu -> System.out.println(stu));

    session.close();
}

控制台输出:
pic_1a966b8a.png

这样就出错了,我们需要修改mapper文件

<select id="selectForeachOne" resultType="com.lu.entity.Student">
    select * from student
    <if test="list != null and list.size > 0">
        where id in
        <foreach collection="list" open="(" close=")" separator="," item="myid">
            #{myid}
        </foreach>
    </if> 
</select>

我们重新在测试类中进行测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZOENNvKR-1657273669580)(http://175.178.73.222:888/images/pic_97c0907e.png)]

这样就不会出现错误了。

4.3.2 foreach对象类型的List

我们举一个例子

dao接口中定义一个方法:

//foreach-2
List<Student> selectForeachTwo(List<Student> studentList);

mapper文件中

<!--foreach第二种方式,循环对象类型的List-->
<select id="selectForeachTwo" resultType="com.lu.entity.Student">
    select * from student 
    <if test="list != null and list.size > 0">
        where id in 
        <foreach collection="list" open="(" close=")" separator="," item="stu">
            #{stu.id}
        </foreach>
    </if>
</select>

测试类中进行测试:

@Test
public  void testSelectForeachTwo() {
   
     
     
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);

    List<Student> list = new ArrayList<>();

    Student s1 = new Student();
    s1.setId(1001);

    Student s2 = new Student();
    s2.setId(1002);

    Student s3 = new Student();
    s3.setId(1003);

    list.add(s1);
    list.add(s2);
    list.add(s3);

    List<Student> students = dao.selectForeachTwo(list);
    students.forEach(stu -> System.out.println(stu));

    session.close();
}

控制台输出:
pic_aa6cac74.png

查询成功。

4.4 sql标签

sql标签标示一段sql代码,可以是表名,几个字段,where条件都可以,可以在其他位置复用sql标签的内容。

使用方式:

1.在mapper文件红定义sql代码片段 <sql id="唯一标签"> 部分sql语句 </sql>
2.在其他位置,使用include标签引用某个代码片段

mapper文件中这样写:

<!--定义代码片段-->
<sql id="selectStudent">
    select * from student
</sql>

<sql id="studentFieldList">
    id,name,email
</sql>

<select id="selectIf" resultType="com.lu.entity.Student">
    <include refid="selectStudent"></include>
    where id = -1
    <if test="name != null and name != ''">
        or name = #{name}
    </if>

    <if test="age > 0">
        or age < #{age}
    </if>
</select>

这样我们就实现了代码的分复用

5 主配置文件

mybatis主配置文件,提供mybatis全局设置的,包含的内容日志,数据源,mapper文件位置

我们来放一个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>
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <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/数据库名称?useUnicode=true&characterEncoding=utf-8"/>
                <property name="username" value="mysql数据库账号"/>
                <property name="password" value="mysql数据库密码"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mapper文件的全限定名称"/>
    </mappers>
</configuration>

我们从上往下看

5.1 settings部分

settings是mybatis的全局设置,影响整个mybatis的运行。这个设置一般使用默认值就可以了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ghFRDrZf-1657273669580)(http://175.178.73.222:888/images/pic_dec0c95b.png)]
pic_e5b6a751.png
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3zCB7XHL-1657273669581)(http://175.178.73.222:888/images/pic_b13f1570.png)]

一个配置完整的settings元素的示例如下:

<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

5.2 typeAliases别名

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

<!--声明别名-->
<typeAliases>
    <!--第一种语法格式
            type:java类型的全限定名称(自定义类型)
            alias:自定义别名
        -->
    <typeAlias type="com.lu.entity.Student" alias="stu"></typeAlias>

    <!--第二种方式
            name:包名,mybatis会把这个包中所有类名作为别名
        -->
    <package name="com.lu.entity"/>
</typeAliases>

下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。
pic_db702c81.png
pic_b4db8ff0.png

5.3 配置环境

environments:环境标签,在它里面可以配置多个environment
		属性: default,必须是某个environment的id属性值。标识mybatis默认连接的数据库
environment:表示一个数据库的连接信息
		属性: id 自定义的环境的标识。唯一值。
transactionManager:失误管理器
		属性: type 表示失误管理器的类型
		属性值: 1. JDBC:使用Connection对象,由Mybatis自己完成事务的处理。
			   2. MANAGED:管理,表示把事务的处理交给容器实现(由其他软件完成失误的提交,回滚)
dataSource:数据源,创建的Connection对象,连接数据库
		属性: type 数据源的类型
		属性值: 1. POOLED,mybatis会在内存中创建PooledDataSource类,管理多个Connection连接对象,使用的连接池
			   2. UNPOOLED,不适用连接池,mybatis创建一个UnPooledDataSource这个类,每次执行sql语句先创建Connection对					  象,再执行sql语句,最后关闭Connection
			   3. JNDI:java的命名和目录服务。

<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <!--配置数据源:创建Connection对象-->
        <dataSource type="POOLED">
            <!--driver:驱动的内容-->
            <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
            <!--链接数据库的url-->
            <property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8"/>
            <!--用户名-->
            <property name="username" value="root"/>
            <!--密码-->
            <property name="password" value="root"/>
        </dataSource>
    </environment>
    
    <environment id="online">
        <transactionManager type="JDBC"/>
        <!--配置数据源:创建Connection对象-->
        <dataSource type="POOLED">
            <!--driver:驱动的内容-->
            <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
            <!--链接数据库的url-->
            <property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8"/>
            <!--用户名-->
            <property name="username" value="root"/>
            <!--密码-->
            <property name="password" value="root"/>
        </dataSource>
    </environment>
</environments>

5.4 使用数据库属性配置文件

需要把数据库的配置信息放到一个单独文件中,独立管理。这个文件扩展名是properties。

这个文件中,使用自定义的key=value的格式表示数据

使用步骤:

1.在resources目录汇总,创建jdbc.properties
pic_5969b4e9.png

2.在文件中,使用key=value的格式定义数据

例如:jdbc.url=jdbc:mysql://localhost:3306/ssm
pic_c69c5d1c.png

3.在mybatis主配置文件,使用标签引用外部的属性配置文件
pic_75496a49.png

4.在使用值的位置,使用${key}获取key对应的value
pic_6f6dad67.png

5.5 mapper文件的两种指定方式

第一种方式:resources=“mapper文件的全限定路径名称”

例如:

<mappers>
    <mapper resource="com/lu/dao/StudentDao.xml"/>
</mappers>

优点:文件清晰。加载的文件时明确的,文件的位置比较灵活

缺点:文件比较多,代码量会比较大,管理难度大

第二种方式,使用<package>

例如:

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

name:mapper文件所在的包名

特点:把这个包中的所有mapper文件,一次加载

使用要求:

  1. mapper文件和dao接口在同一目录
  2. mapper文件和dao接口名称完全一样

6 PageHelper

PageHelper做数据分页。在你的select语句后面加入分页的sql内容,如果你使用的mysql数据库,它就是在select * from student后面加上limit语句。

使用步骤:

1.加入依赖pageHelper依赖

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.2.1</version>
</dependency>

2.在mybatis主配置文件,加入plugin声明(在之前加入)

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

3.在select语句之前,调用PageHelper.startPage(页码,每页大小)

@Test
public  void testPageHelper() {
   
     
     
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);

    //调用PageHelper
    PageHelper.startPage(1,3);

    List<Student> students = dao.selectAllStudents();
    students.forEach(student -> System.out.println(student));
    session.close();
}

控制台输出:

pic_1f253843.png

**到这里我们MyBatis就算入门了,恭喜你!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程简介这是一门使用Java语言,SpringBoot框架,从0开发一个RESTful API应用,接近企业级的项目(我的云音乐),课程包含了基础内容,高级内容,项目封装,项目重构等知识,99%代码为手写;因为这是项目课程;所以不会深入到源码讲解某个知识点,以及原理,但会粗略的讲解下基础原理;主要是讲解如何使用系统功能,流行的第三方框架,第三方服务,完成接近企业级项目,目的是让大家,学到真正的企业级项目开发技术。适用人群刚刚毕业的学生想提高职场竞争力想学从零开发SpringBoot项目想提升SpringBoot项目开发技术想学习SpringBoot项目架构技术想学习企业级项目开发技术就是想学习SpringBoot开发能学到什么从0开发一个类似企业级项目学会能做出市面上90%通用API快速增加1到2年实际开发经验刚毕业学完后能找到满意的工作已经工作学完后最高涨薪30%课程信息全课程目前是82章,155小时,每节视频都经过精心剪辑。在线学习分辨率最高1080P课程知识点1~11章:学习方法,项目架构,编码规范,Postman使用方法,Git和Github版本控制12~16章:搭建开发环境,快速入门SpringBoot框架17~20章:快速入门MySQL数据库21~30章:MyBatis,登录注册,找回密码,发送短信,发送邮件,企业级接口配置31~41章:实现歌单,歌单标签,音乐,列表分页,视频,评论,好友功能42~48章:阿里云OSS,话题,MyBatis-plus,应用监控49~53章:Redis使用,集成Redis,SpringCache,HTTP缓存54~58章:Elasticsearch使用,集成Elasticsearch,使用ES搜索59~61章:商城,集成支付宝SDK,支付宝支付62~64章:常用哈希和加密算法,接口加密和签名65~67章:实时挤掉用户,企业级项目测试环境,企业级接口文档68~69章:SpringBoot全站HTTPS,自签证书,申请免费证书70~73章:云MySQL数据库,云Redis数据库使用,轻量级应用部署环境,域名解析74~80章:Docker使用,生产级Kubernetes集群,域名解析,集群全站HTTPS81~82章:增强和重构项目,课程总结,后续学习计划

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值